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))
30lex_mode_incrementor(
const uint8_t start) {
47lex_mode_terminator(
const uint8_t start) {
89lex_mode_push_list(
pm_parser_t *parser,
bool interpolation, uint8_t delimiter) {
90 uint8_t incrementor = lex_mode_incrementor(delimiter);
91 uint8_t terminator = lex_mode_terminator(delimiter);
97 .interpolation = interpolation,
98 .incrementor = incrementor,
99 .terminator = terminator
106 memcpy(breakpoints,
"\\ \t\f\r\v\n\0\0\0",
sizeof(lex_mode.
as.list.
breakpoints));
111 if (terminator !=
'\0') {
112 breakpoints[index++] = terminator;
118 breakpoints[index++] =
'#';
122 if (incrementor !=
'\0') {
123 breakpoints[index++] = incrementor;
127 return lex_mode_push(parser, lex_mode);
137 return lex_mode_push_list(parser,
false,
'\0');
144lex_mode_push_regexp(
pm_parser_t *parser, uint8_t incrementor, uint8_t terminator) {
146 .
mode = PM_LEX_REGEXP,
149 .incrementor = incrementor,
150 .terminator = terminator
158 memcpy(breakpoints,
"\r\n\\#\0\0",
sizeof(lex_mode.
as.regexp.
breakpoints));
162 if (terminator !=
'\0') {
163 breakpoints[index++] = terminator;
167 if (incrementor !=
'\0') {
168 breakpoints[index++] = incrementor;
172 return lex_mode_push(parser, lex_mode);
179lex_mode_push_string(
pm_parser_t *parser,
bool interpolation,
bool label_allowed, uint8_t incrementor, uint8_t terminator) {
181 .
mode = PM_LEX_STRING,
184 .interpolation = interpolation,
185 .label_allowed = label_allowed,
186 .incrementor = incrementor,
187 .terminator = terminator
194 memcpy(breakpoints,
"\r\n\\\0\0\0",
sizeof(lex_mode.
as.string.
breakpoints));
199 if (terminator !=
'\0') {
200 breakpoints[index++] = terminator;
206 breakpoints[index++] =
'#';
211 if (incrementor !=
'\0') {
212 breakpoints[index++] = incrementor;
216 return lex_mode_push(parser, lex_mode);
226 return lex_mode_push_string(parser,
false,
false,
'\0',
'\0');
258 PM_IGNORED_NEWLINE_NONE = 0,
259 PM_IGNORED_NEWLINE_ALL,
260 PM_IGNORED_NEWLINE_PATTERN
261} pm_ignored_newline_type_t;
263static inline pm_ignored_newline_type_t
265 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);
268 return PM_IGNORED_NEWLINE_ALL;
269 }
else if ((parser->
lex_state & ~((
unsigned int) PM_LEX_STATE_LABEL)) == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)) {
270 return PM_IGNORED_NEWLINE_PATTERN;
272 return PM_IGNORED_NEWLINE_NONE;
278 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));
283 return lex_state_p(parser, PM_LEX_STATE_ARG_ANY);
287lex_state_spcarg_p(
pm_parser_t *parser,
bool space_seen) {
291 return lex_state_arg_p(parser) && space_seen && !pm_char_is_whitespace(*parser->
current.end);
296 return lex_state_p(parser, PM_LEX_STATE_END_ANY);
304 return lex_state_p(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT);
316#ifndef PM_DEBUG_LOGGING
321#define PM_DEBUG_LOGGING 0
327 fprintf(stderr,
"STATE: ");
330 if (parser->
lex_state == PM_LEX_STATE_NONE) {
331 fprintf(stderr,
"NONE\n");
335#define CHECK_STATE(state) \
336 if (parser->lex_state & state) { \
337 if (!first) fprintf(stderr, "|"); \
338 fprintf(stderr, "%s", #state); \
342 CHECK_STATE(PM_LEX_STATE_BEG)
343 CHECK_STATE(PM_LEX_STATE_END)
344 CHECK_STATE(PM_LEX_STATE_ENDARG)
345 CHECK_STATE(PM_LEX_STATE_ENDFN)
346 CHECK_STATE(PM_LEX_STATE_ARG)
347 CHECK_STATE(PM_LEX_STATE_CMDARG)
348 CHECK_STATE(PM_LEX_STATE_MID)
349 CHECK_STATE(PM_LEX_STATE_FNAME)
350 CHECK_STATE(PM_LEX_STATE_DOT)
351 CHECK_STATE(PM_LEX_STATE_CLASS)
352 CHECK_STATE(PM_LEX_STATE_LABEL)
353 CHECK_STATE(PM_LEX_STATE_LABELED)
354 CHECK_STATE(PM_LEX_STATE_FITEM)
358 fprintf(stderr,
"\n");
363 fprintf(stderr,
"Caller: %s:%d\nPrevious: ", caller_name, line_number);
365 lex_state_set(parser, state);
366 fprintf(stderr,
"Now: ");
368 fprintf(stderr,
"\n");
371#define lex_state_set(parser, state) debug_lex_state_set(parser, state, __func__, __LINE__)
379#define PM_PARSER_COMMAND_LINE_OPTION(parser, option) ((parser)->command_line & (option))
382#define PM_PARSER_COMMAND_LINE_OPTION_A(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_A)
385#define PM_PARSER_COMMAND_LINE_OPTION_E(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_E)
388#define PM_PARSER_COMMAND_LINE_OPTION_L(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_L)
391#define PM_PARSER_COMMAND_LINE_OPTION_N(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_N)
394#define PM_PARSER_COMMAND_LINE_OPTION_P(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_P)
397#define PM_PARSER_COMMAND_LINE_OPTION_X(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_X)
408 pm_diagnostic_list_append(&parser->
error_list, start, end, diag_id);
414#define PM_PARSER_ERR_FORMAT(parser, start, end, diag_id, ...) \
415 pm_diagnostic_list_append_format(&parser->error_list, start, end, diag_id, __VA_ARGS__)
423 pm_parser_err(parser, parser->
current.start, parser->
current.end, diag_id);
430#define PM_PARSER_ERR_LOCATION_FORMAT(parser, location, diag_id, ...) \
431 PM_PARSER_ERR_FORMAT(parser, (location)->start, (location)->end, diag_id, __VA_ARGS__)
446#define PM_PARSER_ERR_NODE_FORMAT(parser, node, diag_id, ...) \
447 PM_PARSER_ERR_FORMAT(parser, (node)->location.start, (node)->location.end, diag_id, __VA_ARGS__)
453#define PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, diag_id) \
454 PM_PARSER_ERR_NODE_FORMAT(parser, node, diag_id, (int) ((node)->location.end - (node)->location.start), (const char *) (node)->location.start)
471 pm_parser_err(parser, token->start, token->end, diag_id);
478#define PM_PARSER_ERR_TOKEN_FORMAT(parser, token, diag_id, ...) \
479 PM_PARSER_ERR_FORMAT(parser, (token).start, (token).end, diag_id, __VA_ARGS__)
485#define PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, token, diag_id) \
486 PM_PARSER_ERR_TOKEN_FORMAT(parser, token, diag_id, (int) ((token).end - (token).start), (const char *) (token).start)
493 pm_diagnostic_list_append(&parser->
warning_list, start, end, diag_id);
502 pm_parser_warn(parser, token->start, token->end, diag_id);
517#define PM_PARSER_WARN_FORMAT(parser, start, end, diag_id, ...) \
518 pm_diagnostic_list_append_format(&parser->warning_list, start, end, diag_id, __VA_ARGS__)
524#define PM_PARSER_WARN_TOKEN_FORMAT(parser, token, diag_id, ...) \
525 PM_PARSER_WARN_FORMAT(parser, (token).start, (token).end, diag_id, __VA_ARGS__)
531#define PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, token, diag_id) \
532 PM_PARSER_WARN_TOKEN_FORMAT(parser, token, diag_id, (int) ((token).end - (token).start), (const char *) (token).start)
538#define PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, ...) \
539 PM_PARSER_WARN_FORMAT(parser, (node)->location.start, (node)->location.end, diag_id, __VA_ARGS__)
547pm_parser_err_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
548 PM_PARSER_ERR_FORMAT(
551 ident_start + ident_length,
554 (
const char *) ident_start
566pm_parser_scope_push(
pm_parser_t *parser,
bool closed) {
568 if (scope == NULL)
return false;
573 .parameters = PM_SCOPE_PARAMETERS_NONE,
574 .implicit_parameters = { 0 },
592 if (scope->
previous == NULL)
return true;
593 if (scope->
closed)
return false;
594 }
while ((scope = scope->
previous) != NULL);
596 assert(
false &&
"unreachable");
604pm_parser_scope_find(
pm_parser_t *parser, uint32_t depth) {
607 while (depth-- > 0) {
608 assert(scope != NULL);
616 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS,
617 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT,
618 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL
619} pm_scope_forwarding_param_check_result_t;
621static pm_scope_forwarding_param_check_result_t
622pm_parser_scope_forwarding_param_check(
pm_parser_t *parser,
const uint8_t mask) {
624 bool conflict =
false;
626 while (scope != NULL) {
630 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT;
632 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS;
643 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL;
648 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_BLOCK)) {
649 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
652 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
653 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_AMPERSAND);
655 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
656 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_AMPERSAND);
663 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS)) {
664 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
667 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
668 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR);
670 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
671 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR);
678 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_ALL)) {
679 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
682 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
687 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
688 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
695 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS)) {
696 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
699 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
700 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR_STAR);
702 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
703 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR_STAR);
712pm_parser_scope_shareable_constant_get(
pm_parser_t *parser) {
736#define PM_LOCALS_HASH_THRESHOLD 9
751 name = ((name >> 16) ^ name) * 0x45d9f3b;
752 name = ((name >> 16) ^ name) * 0x45d9f3b;
753 name = (name >> 16) ^ name;
763 uint32_t next_capacity = locals->
capacity == 0 ? 4 : (locals->
capacity * 2);
764 assert(next_capacity > locals->
capacity);
767 if (next_locals == NULL) abort();
769 if (next_capacity < PM_LOCALS_HASH_THRESHOLD) {
770 if (locals->
size > 0) {
776 bool hash_needed = (locals->
capacity <= PM_LOCALS_HASH_THRESHOLD);
777 uint32_t mask = next_capacity - 1;
779 for (uint32_t index = 0; index < locals->
capacity; index++) {
783 if (hash_needed) local->
hash = pm_locals_hash(local->
name);
785 uint32_t hash = local->
hash;
787 next_locals[hash & mask] = *local;
792 pm_locals_free(locals);
793 locals->
locals = next_locals;
815 pm_locals_resize(locals);
818 if (locals->
capacity < PM_LOCALS_HASH_THRESHOLD) {
819 for (uint32_t index = 0; index < locals->
capacity; index++) {
825 .location = { .start = start, .end = end },
826 .index = locals->
size++,
831 }
else if (local->
name == name) {
836 uint32_t mask = locals->
capacity - 1;
837 uint32_t hash = pm_locals_hash(name);
838 uint32_t initial_hash = hash;
846 .location = { .start = start, .end = end },
847 .index = locals->
size++,
852 }
else if (local->
name == name) {
857 }
while ((hash & mask) != initial_hash);
860 assert(
false &&
"unreachable");
870 if (locals->
capacity < PM_LOCALS_HASH_THRESHOLD) {
871 for (uint32_t index = 0; index < locals->
size; index++) {
873 if (local->
name == name)
return index;
876 uint32_t mask = locals->
capacity - 1;
877 uint32_t hash = pm_locals_hash(name);
878 uint32_t initial_hash = hash & mask;
885 }
else if (local->
name == name) {
890 }
while ((hash & mask) != initial_hash);
902 uint32_t index = pm_locals_find(locals, name);
903 assert(index != UINT32_MAX);
906 assert(local->
reads < UINT32_MAX);
917 uint32_t index = pm_locals_find(locals, name);
918 assert(index != UINT32_MAX);
921 assert(local->
reads > 0);
931 uint32_t index = pm_locals_find(locals, name);
932 assert(index != UINT32_MAX);
947 pm_constant_id_list_init_capacity(list, locals->
size);
952 uint32_t capacity = locals->
capacity < PM_LOCALS_HASH_THRESHOLD ? locals->
size : locals->
capacity;
956 bool warn_unused = !toplevel || (!parser->parsing_eval && !PM_PARSER_COMMAND_LINE_OPTION_E(parser));
958 for (uint32_t index = 0; index < capacity; index++) {
962 pm_constant_id_list_insert(list, (
size_t) local->
index, local->
name);
964 if (warn_unused && local->
reads == 0 && ((parser->start_line >= 0) || (pm_newline_list_line(&parser->newline_list, local->
location.
start, parser->start_line) >= 0))) {
965 pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, local->
name);
967 if (constant->
length >= 1 && *constant->
start !=
'_') {
968 PM_PARSER_WARN_FORMAT(
972 PM_WARN_UNUSED_LOCAL_VARIABLE,
974 (
const char *) constant->
start
990pm_parser_constant_id_location(
pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
991 return pm_constant_pool_insert_shared(&parser->
constant_pool, start, (
size_t) (end - start));
998pm_parser_constant_id_owned(
pm_parser_t *parser, uint8_t *start,
size_t length) {
999 return pm_constant_pool_insert_owned(&parser->
constant_pool, start, length);
1006pm_parser_constant_id_constant(
pm_parser_t *parser,
const char *start,
size_t length) {
1007 return pm_constant_pool_insert_constant(&parser->
constant_pool, (
const uint8_t *) start, length);
1015 return pm_parser_constant_id_location(parser, token->start, token->end);
1024 return token->type == PM_TOKEN_NOT_PROVIDED ? 0 : pm_parser_constant_id_token(parser, token);
1036 while (node != NULL) {
1037 switch (PM_NODE_TYPE(node)) {
1038 case PM_RETURN_NODE:
1043 case PM_MATCH_REQUIRED_NODE:
1044 return void_node != NULL ? void_node : node;
1045 case PM_MATCH_PREDICATE_NODE:
1047 case PM_BEGIN_NODE: {
1053 if (vn != NULL)
return vn;
1058 if (vn != NULL)
return vn;
1066 if (vn == NULL)
return NULL;
1067 if (void_node == NULL) void_node = vn;
1070 pm_node_t *vn = pm_check_value_expression(parser, (
pm_node_t *) rescue_clause->statements);
1075 if (void_node == NULL) {
1091 case PM_ENSURE_NODE: {
1096 case PM_PARENTHESES_NODE: {
1101 case PM_STATEMENTS_NODE: {
1115 if (void_node == NULL) {
1121 case PM_UNLESS_NODE: {
1130 if (void_node == NULL) {
1136 case PM_ELSE_NODE: {
1151 case PM_LOCAL_VARIABLE_WRITE_NODE: {
1155 for (uint32_t depth = 0; depth < cast->
depth; depth++) scope = scope->
previous;
1170 pm_node_t *void_node = pm_check_value_expression(parser, node);
1171 if (void_node != NULL) {
1172 pm_parser_err_node(parser, void_node, PM_ERR_VOID_EXPRESSION);
1181 const char *
type = NULL;
1184 switch (PM_NODE_TYPE(node)) {
1185 case PM_BACK_REFERENCE_READ_NODE:
1186 case PM_CLASS_VARIABLE_READ_NODE:
1187 case PM_GLOBAL_VARIABLE_READ_NODE:
1188 case PM_INSTANCE_VARIABLE_READ_NODE:
1189 case PM_LOCAL_VARIABLE_READ_NODE:
1190 case PM_NUMBERED_REFERENCE_READ_NODE:
1191 type =
"a variable";
1194 case PM_CALL_NODE: {
1199 switch (message->
length) {
1201 switch (message->
start[0]) {
1218 switch (message->
start[1]) {
1220 if (message->
start[0] ==
'<' || message->
start[0] ==
'>' || message->
start[0] ==
'!' || message->
start[0] ==
'=') {
1226 if (message->
start[0] ==
'+' || message->
start[0] ==
'-') {
1232 if (message->
start[0] ==
'*') {
1240 if (memcmp(message->
start,
"<=>", 3) == 0) {
1249 case PM_CONSTANT_PATH_NODE:
1253 case PM_CONSTANT_READ_NODE:
1254 type =
"a constant";
1257 case PM_DEFINED_NODE:
1266 case PM_IMAGINARY_NODE:
1267 case PM_INTEGER_NODE:
1268 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
1269 case PM_INTERPOLATED_STRING_NODE:
1270 case PM_RATIONAL_NODE:
1271 case PM_REGULAR_EXPRESSION_NODE:
1272 case PM_SOURCE_ENCODING_NODE:
1273 case PM_SOURCE_FILE_NODE:
1274 case PM_SOURCE_LINE_NODE:
1275 case PM_STRING_NODE:
1276 case PM_SYMBOL_NODE:
1284 case PM_RANGE_NODE: {
1287 if (PM_NODE_FLAG_P(cast, PM_RANGE_FLAGS_EXCLUDE_END)) {
1310 PM_PARSER_WARN_NODE_FORMAT(parser, node, PM_WARN_VOID_STATEMENT, length,
type);
1321 const size_t size = node->
body.
size - (last_value ? 1 : 0);
1322 for (
size_t index = 0; index < size; index++) {
1323 pm_void_statement_check(parser, node->
body.
nodes[index]);
1333 PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL,
1334 PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP,
1335 PM_CONDITIONAL_PREDICATE_TYPE_NOT
1336} pm_conditional_predicate_type_t;
1344 case PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL:
1345 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"condition");
1347 case PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP:
1348 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"flip-flop");
1350 case PM_CONDITIONAL_PREDICATE_TYPE_NOT:
1360pm_conditional_predicate_warn_write_literal_p(
const pm_node_t *node) {
1361 switch (PM_NODE_TYPE(node)) {
1362 case PM_ARRAY_NODE: {
1363 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1366 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1367 if (!pm_conditional_predicate_warn_write_literal_p(cast->
elements.
nodes[index]))
return false;
1372 case PM_HASH_NODE: {
1373 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1376 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1378 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE))
return false;
1381 if (!pm_conditional_predicate_warn_write_literal_p(assoc->
key) || !pm_conditional_predicate_warn_write_literal_p(assoc->
value))
return false;
1388 case PM_IMAGINARY_NODE:
1389 case PM_INTEGER_NODE:
1391 case PM_RATIONAL_NODE:
1392 case PM_REGULAR_EXPRESSION_NODE:
1393 case PM_SOURCE_ENCODING_NODE:
1394 case PM_SOURCE_FILE_NODE:
1395 case PM_SOURCE_LINE_NODE:
1396 case PM_STRING_NODE:
1397 case PM_SYMBOL_NODE:
1411 if (pm_conditional_predicate_warn_write_literal_p(node)) {
1430 switch (PM_NODE_TYPE(node)) {
1433 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1434 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1439 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1440 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1443 case PM_PARENTHESES_NODE: {
1446 if ((cast->
body != NULL) && PM_NODE_TYPE_P(cast->
body, PM_STATEMENTS_NODE)) {
1448 if (statements->body.size == 1) pm_conditional_predicate(parser, statements->body.nodes[0],
type);
1453 case PM_BEGIN_NODE: {
1461 case PM_RANGE_NODE: {
1464 if (cast->
left != NULL) pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1465 if (cast->
right != NULL) pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1473 node->
type = PM_FLIP_FLOP_NODE;
1477 case PM_REGULAR_EXPRESSION_NODE:
1482 node->
type = PM_MATCH_LAST_LINE_NODE;
1484 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1485 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"regex ");
1489 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
1494 node->
type = PM_INTERPOLATED_MATCH_LAST_LINE_NODE;
1496 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1497 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"regex ");
1501 case PM_INTEGER_NODE:
1502 if (
type == PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP) {
1503 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1504 pm_parser_warn_node(parser, node, PM_WARN_INTEGER_IN_FLIP_FLOP);
1507 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1510 case PM_STRING_NODE:
1511 case PM_SOURCE_FILE_NODE:
1512 case PM_INTERPOLATED_STRING_NODE:
1513 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"string ");
1515 case PM_SYMBOL_NODE:
1516 case PM_INTERPOLATED_SYMBOL_NODE:
1517 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"symbol ");
1519 case PM_SOURCE_LINE_NODE:
1520 case PM_SOURCE_ENCODING_NODE:
1522 case PM_RATIONAL_NODE:
1523 case PM_IMAGINARY_NODE:
1524 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1526 case PM_CLASS_VARIABLE_WRITE_NODE:
1529 case PM_CONSTANT_WRITE_NODE:
1532 case PM_GLOBAL_VARIABLE_WRITE_NODE:
1535 case PM_INSTANCE_VARIABLE_WRITE_NODE:
1538 case PM_LOCAL_VARIABLE_WRITE_NODE:
1541 case PM_MULTI_WRITE_NODE:
1562#define PM_LOCATION_NULL_VALUE(parser) ((pm_location_t) { .start = (parser)->start, .end = (parser)->start })
1563#define PM_LOCATION_TOKEN_VALUE(token) ((pm_location_t) { .start = (token)->start, .end = (token)->end })
1564#define PM_LOCATION_NODE_VALUE(node) ((pm_location_t) { .start = (node)->location.start, .end = (node)->location.end })
1565#define PM_LOCATION_NODE_BASE_VALUE(node) ((pm_location_t) { .start = (node)->base.location.start, .end = (node)->base.location.end })
1566#define PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE ((pm_location_t) { .start = NULL, .end = NULL })
1567#define PM_OPTIONAL_LOCATION_TOKEN_VALUE(token) ((token)->type == PM_TOKEN_NOT_PROVIDED ? PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE : PM_LOCATION_TOKEN_VALUE(token))
1595static inline const uint8_t *
1597 if (arguments->
block != NULL) {
1638 pm_parser_err_node(parser, (
pm_node_t *) block, PM_ERR_ARGUMENT_UNEXPECTED_BLOCK);
1652char_is_identifier_start(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
1653 if (n <= 0)
return 0;
1660 }
else if (*b ==
'_') {
1662 }
else if (*b >= 0x80) {
1667 }
else if (*b < 0x80) {
1670 return pm_encoding_utf_8_char_width(b, n);
1679char_is_identifier_utf8(
const uint8_t *b, ptrdiff_t n) {
1682 }
else if (*b < 0x80) {
1685 return pm_encoding_utf_8_char_width(b, n);
1695char_is_identifier(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
1703 }
else if (*b ==
'_') {
1705 }
else if (*b >= 0x80) {
1711 return char_is_identifier_utf8(b, n);
1718#define BIT(c, idx) (((c) / 32 - 1 == idx) ? (1U << ((c) % 32)) : 0)
1719#define PUNCT(idx) ( \
1720 BIT('~', idx) | BIT('*', idx) | BIT('$', idx) | BIT('?', idx) | \
1721 BIT('!', idx) | BIT('@', idx) | BIT('/', idx) | BIT('\\', idx) | \
1722 BIT(';', idx) | BIT(',', idx) | BIT('.', idx) | BIT('=', idx) | \
1723 BIT(':', idx) | BIT('<', idx) | BIT('>', idx) | BIT('\"', idx) | \
1724 BIT('&', idx) | BIT('`', idx) | BIT('\'', idx) | BIT('+', idx) | \
1727const unsigned int pm_global_name_punctuation_hash[(0x7e - 0x20 + 31) / 32] = { PUNCT(0), PUNCT(1), PUNCT(2) };
1733char_is_global_name_punctuation(const uint8_t b) {
1734 const unsigned int i = (const unsigned int) b;
1735 if (i <= 0x20 || 0x7e < i) return false;
1737 return (pm_global_name_punctuation_hash[(i - 0x20) / 32] >> (i % 32)) & 1;
1741token_is_setter_name(pm_token_t *token) {
1743 (token->type == PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL) ||
1744 ((token->type == PM_TOKEN_IDENTIFIER) &&
1745 (token->end - token->start >= 2) &&
1746 (token->end[-1] == '='))
1754pm_local_is_keyword(const char *source, size_t length) {
1755#define KEYWORD(name) if (memcmp(source, name, length) == 0) return true
1759 switch (source[0]) {
1760 case 'd': KEYWORD("do"); return false;
1761 case 'i': KEYWORD("if"); KEYWORD("in"); return false;
1762 case 'o': KEYWORD("or"); return false;
1763 default: return false;
1766 switch (source[0]) {
1767 case 'a': KEYWORD("and"); return false;
1768 case 'd': KEYWORD("def"); return false;
1769 case 'e': KEYWORD("end"); return false;
1770 case 'f': KEYWORD("for"); return false;
1771 case 'n': KEYWORD("nil"); KEYWORD("not"); return false;
1772 default: return false;
1775 switch (source[0]) {
1776 case 'c': KEYWORD("case"); return false;
1777 case 'e': KEYWORD("else"); return false;
1778 case 'n': KEYWORD("next"); return false;
1779 case 'r': KEYWORD("redo"); return false;
1780 case 's': KEYWORD("self"); return false;
1781 case 't': KEYWORD("then"); KEYWORD("true"); return false;
1782 case 'w': KEYWORD("when"); return false;
1783 default: return false;
1786 switch (source[0]) {
1787 case 'a': KEYWORD("alias"); return false;
1788 case 'b': KEYWORD("begin"); KEYWORD("break"); return false;
1789 case 'c': KEYWORD("class"); return false;
1790 case 'e': KEYWORD("elsif"); return false;
1791 case 'f': KEYWORD("false"); return false;
1792 case 'r': KEYWORD("retry"); return false;
1793 case 's': KEYWORD("super"); return false;
1794 case 'u': KEYWORD("undef"); KEYWORD("until"); return false;
1795 case 'w': KEYWORD("while"); return false;
1796 case 'y': KEYWORD("yield"); return false;
1797 default: return false;
1800 switch (source[0]) {
1801 case 'e': KEYWORD("ensure"); return false;
1802 case 'm': KEYWORD("module"); return false;
1803 case 'r': KEYWORD("rescue"); KEYWORD("return"); return false;
1804 case 'u': KEYWORD("unless"); return false;
1805 default: return false;
1808 KEYWORD("__LINE__");
1809 KEYWORD("__FILE__");
1812 KEYWORD("__ENCODING__");
1821/******************************************************************************/
1822/* Node flag handling functions */
1823/******************************************************************************/
1829pm_node_flag_set(pm_node_t *node, pm_node_flags_t flag) {
1830 node->flags |= flag;
1837pm_node_flag_unset(pm_node_t *node, pm_node_flags_t flag) {
1838 node->flags &= (pm_node_flags_t) ~flag;
1845pm_node_flag_set_repeated_parameter(pm_node_t *node) {
1846 assert(PM_NODE_TYPE(node) == PM_BLOCK_LOCAL_VARIABLE_NODE ||
1847 PM_NODE_TYPE(node) == PM_BLOCK_PARAMETER_NODE ||
1848 PM_NODE_TYPE(node) == PM_KEYWORD_REST_PARAMETER_NODE ||
1849 PM_NODE_TYPE(node) == PM_OPTIONAL_KEYWORD_PARAMETER_NODE ||
1850 PM_NODE_TYPE(node) == PM_OPTIONAL_PARAMETER_NODE ||
1851 PM_NODE_TYPE(node) == PM_REQUIRED_KEYWORD_PARAMETER_NODE ||
1852 PM_NODE_TYPE(node) == PM_REQUIRED_PARAMETER_NODE ||
1853 PM_NODE_TYPE(node) == PM_REST_PARAMETER_NODE);
1855 pm_node_flag_set(node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER);
1858/******************************************************************************/
1859/* Node creation functions */
1860/******************************************************************************/
1867#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)
1872static inline pm_node_flags_t
1873pm_regular_expression_flags_create(pm_parser_t *parser, const pm_token_t *closing) {
1874 pm_node_flags_t flags = 0;
1876 if (closing->type == PM_TOKEN_REGEXP_END) {
1877 pm_buffer_t unknown_flags = { 0 };
1879 for (const uint8_t *flag = closing->start + 1; flag < closing->end; flag++) {
1881 case 'i': flags |= PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE; break;
1882 case 'm': flags |= PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE; break;
1883 case 'x': flags |= PM_REGULAR_EXPRESSION_FLAGS_EXTENDED; break;
1884 case 'o': flags |= PM_REGULAR_EXPRESSION_FLAGS_ONCE; break;
1886 case 'e': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_EUC_JP); break;
1887 case 'n': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT); break;
1888 case 's': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J); break;
1889 case 'u': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_UTF_8); break;
1891 default: pm_buffer_append_byte(&unknown_flags, *flag);
1895 size_t unknown_flags_length = pm_buffer_length(&unknown_flags);
1896 if (unknown_flags_length != 0) {
1897 const char *word = unknown_flags_length >= 2 ? "options" : "option";
1898 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, PM_ERR_REGEXP_UNKNOWN_OPTIONS, word, unknown_flags_length, pm_buffer_value(&unknown_flags));
1900 pm_buffer_free(&unknown_flags);
1906#undef PM_REGULAR_EXPRESSION_ENCODING_MASK
1908static pm_statements_node_t *
1909pm_statements_node_create(pm_parser_t *parser);
1912pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline);
1915pm_statements_node_body_length(pm_statements_node_t *node);
1922pm_node_alloc(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, size_t size) {
1923 void *memory = xcalloc(1, size);
1924 if (memory == NULL) {
1925 fprintf(stderr, "Failed to allocate %d bytes\n", (int) size);
1931#define PM_NODE_ALLOC(parser, type) (type *) pm_node_alloc(parser, sizeof(type))
1932#define PM_NODE_IDENTIFY(parser) (++parser->node_id)
1937static pm_missing_node_t *
1938pm_missing_node_create(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
1939 pm_missing_node_t *node = PM_NODE_ALLOC(parser, pm_missing_node_t);
1941 *node = (pm_missing_node_t) {{
1942 .type = PM_MISSING_NODE,
1943 .node_id = PM_NODE_IDENTIFY(parser),
1944 .location = { .start = start, .end = end }
1953static pm_alias_global_variable_node_t *
1954pm_alias_global_variable_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
1955 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
1956 pm_alias_global_variable_node_t *node = PM_NODE_ALLOC(parser, pm_alias_global_variable_node_t);
1958 *node = (pm_alias_global_variable_node_t) {
1960 .type = PM_ALIAS_GLOBAL_VARIABLE_NODE,
1961 .node_id = PM_NODE_IDENTIFY(parser),
1963 .start = keyword->start,
1964 .end = old_name->location.end
1967 .new_name = new_name,
1968 .old_name = old_name,
1969 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
1978static pm_alias_method_node_t *
1979pm_alias_method_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
1980 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
1981 pm_alias_method_node_t *node = PM_NODE_ALLOC(parser, pm_alias_method_node_t);
1983 *node = (pm_alias_method_node_t) {
1985 .type = PM_ALIAS_METHOD_NODE,
1986 .node_id = PM_NODE_IDENTIFY(parser),
1988 .start = keyword->start,
1989 .end = old_name->location.end
1992 .new_name = new_name,
1993 .old_name = old_name,
1994 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
2003static pm_alternation_pattern_node_t *
2004pm_alternation_pattern_node_create(pm_parser_t *parser, pm_node_t *left, pm_node_t *right, const pm_token_t *operator) {
2005 pm_alternation_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_alternation_pattern_node_t);
2007 *node = (pm_alternation_pattern_node_t) {
2009 .type = PM_ALTERNATION_PATTERN_NODE,
2010 .node_id = PM_NODE_IDENTIFY(parser),
2012 .start = left->location.start,
2013 .end = right->location.end
2018 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2027static pm_and_node_t *
2028pm_and_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
2029 pm_assert_value_expression(parser, left);
2031 pm_and_node_t *node = PM_NODE_ALLOC(parser, pm_and_node_t);
2033 *node = (pm_and_node_t) {
2035 .type = PM_AND_NODE,
2036 .node_id = PM_NODE_IDENTIFY(parser),
2038 .start = left->location.start,
2039 .end = right->location.end
2043 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2053static pm_arguments_node_t *
2054pm_arguments_node_create(pm_parser_t *parser) {
2055 pm_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_arguments_node_t);
2057 *node = (pm_arguments_node_t) {
2059 .type = PM_ARGUMENTS_NODE,
2060 .node_id = PM_NODE_IDENTIFY(parser),
2061 .location = PM_LOCATION_NULL_VALUE(parser)
2073pm_arguments_node_size(pm_arguments_node_t *node) {
2074 return node->arguments.size;
2081pm_arguments_node_arguments_append(pm_arguments_node_t *node, pm_node_t *argument) {
2082 if (pm_arguments_node_size(node) == 0) {
2083 node->base.location.start = argument->location.start;
2086 node->base.location.end = argument->location.end;
2087 pm_node_list_append(&node->arguments, argument);
2089 if (PM_NODE_TYPE_P(argument, PM_SPLAT_NODE)) {
2090 if (PM_NODE_FLAG_P(node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
2091 pm_node_flag_set((pm_node_t *) node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS);
2093 pm_node_flag_set((pm_node_t *) node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT);
2101static pm_array_node_t *
2102pm_array_node_create(pm_parser_t *parser, const pm_token_t *opening) {
2103 pm_array_node_t *node = PM_NODE_ALLOC(parser, pm_array_node_t);
2105 *node = (pm_array_node_t) {
2107 .type = PM_ARRAY_NODE,
2108 .flags = PM_NODE_FLAG_STATIC_LITERAL,
2109 .node_id = PM_NODE_IDENTIFY(parser),
2110 .location = PM_LOCATION_TOKEN_VALUE(opening)
2112 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2113 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2124pm_array_node_elements_append(pm_array_node_t *node, pm_node_t *element) {
2125 if (!node->elements.size && !node->opening_loc.start) {
2126 node->base.location.start = element->location.start;
2129 pm_node_list_append(&node->elements, element);
2130 node->base.location.end = element->location.end;
2132 // If the element is not a static literal, then the array is not a static
2133 // literal. Turn that flag off.
2134 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)) {
2135 pm_node_flag_unset((pm_node_t *)node, PM_NODE_FLAG_STATIC_LITERAL);
2138 if (PM_NODE_TYPE_P(element, PM_SPLAT_NODE)) {
2139 pm_node_flag_set((pm_node_t *)node, PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT);
2147pm_array_node_close_set(pm_array_node_t *node, const pm_token_t *closing) {
2148 assert(closing->type == PM_TOKEN_BRACKET_RIGHT || closing->type == PM_TOKEN_STRING_END || closing->type == PM_TOKEN_MISSING || closing->type == PM_TOKEN_NOT_PROVIDED);
2149 node->base.location.end = closing->end;
2150 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
2157static pm_array_pattern_node_t *
2158pm_array_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *nodes) {
2159 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2161 *node = (pm_array_pattern_node_t) {
2163 .type = PM_ARRAY_PATTERN_NODE,
2164 .node_id = PM_NODE_IDENTIFY(parser),
2166 .start = nodes->nodes[0]->location.start,
2167 .end = nodes->nodes[nodes->size - 1]->location.end
2174 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2175 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
2178 // For now we're going to just copy over each pointer manually. This could be
2179 // much more efficient, as we could instead resize the node list.
2180 bool found_rest = false;
2183 PM_NODE_LIST_FOREACH(nodes, index, child) {
2184 if (!found_rest && (PM_NODE_TYPE_P(child, PM_SPLAT_NODE) || PM_NODE_TYPE_P(child, PM_IMPLICIT_REST_NODE))) {
2187 } else if (found_rest) {
2188 pm_node_list_append(&node->posts, child);
2190 pm_node_list_append(&node->requireds, child);
2200static pm_array_pattern_node_t *
2201pm_array_pattern_node_rest_create(pm_parser_t *parser, pm_node_t *rest) {
2202 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2204 *node = (pm_array_pattern_node_t) {
2206 .type = PM_ARRAY_PATTERN_NODE,
2207 .node_id = PM_NODE_IDENTIFY(parser),
2208 .location = rest->location,
2214 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2215 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
2225static pm_array_pattern_node_t *
2226pm_array_pattern_node_constant_create(pm_parser_t *parser, pm_node_t *constant, 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) {
2231 .type = PM_ARRAY_PATTERN_NODE,
2232 .node_id = PM_NODE_IDENTIFY(parser),
2234 .start = constant->location.start,
2238 .constant = constant,
2240 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2241 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
2253static pm_array_pattern_node_t *
2254pm_array_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
2255 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2257 *node = (pm_array_pattern_node_t) {
2259 .type = PM_ARRAY_PATTERN_NODE,
2260 .node_id = PM_NODE_IDENTIFY(parser),
2262 .start = opening->start,
2268 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2269 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
2278pm_array_pattern_node_requireds_append(pm_array_pattern_node_t *node, pm_node_t *inner) {
2279 pm_node_list_append(&node->requireds, inner);
2285static pm_assoc_node_t *
2286pm_assoc_node_create(pm_parser_t *parser, pm_node_t *key, const pm_token_t *operator, pm_node_t *value) {
2287 pm_assoc_node_t *node = PM_NODE_ALLOC(parser, pm_assoc_node_t);
2290 if (value != NULL && value->location.end > key->location.end) {
2291 end = value->location.end;
2292 } else if (operator->type != PM_TOKEN_NOT_PROVIDED) {
2293 end = operator->end;
2295 end = key->location.end;
2298 // Hash string keys will be frozen, so we can mark them as frozen here so
2299 // that the compiler picks them up and also when we check for static literal
2300 // on the keys it gets factored in.
2301 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
2302 key->flags |= PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL;
2305 // If the key and value of this assoc node are both static literals, then
2306 // we can mark this node as a static literal.
2307 pm_node_flags_t flags = 0;
2309 !PM_NODE_TYPE_P(key, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(key, PM_HASH_NODE) && !PM_NODE_TYPE_P(key, PM_RANGE_NODE) &&
2310 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)
2312 flags = key->flags & value->flags & PM_NODE_FLAG_STATIC_LITERAL;
2315 *node = (pm_assoc_node_t) {
2317 .type = PM_ASSOC_NODE,
2319 .node_id = PM_NODE_IDENTIFY(parser),
2321 .start = key->location.start,
2326 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
2336static pm_assoc_splat_node_t *
2337pm_assoc_splat_node_create(pm_parser_t *parser, pm_node_t *value, const pm_token_t *operator) {
2338 assert(operator->type == PM_TOKEN_USTAR_STAR);
2339 pm_assoc_splat_node_t *node = PM_NODE_ALLOC(parser, pm_assoc_splat_node_t);
2341 *node = (pm_assoc_splat_node_t) {
2343 .type = PM_ASSOC_SPLAT_NODE,
2344 .node_id = PM_NODE_IDENTIFY(parser),
2346 .start = operator->start,
2347 .end = value == NULL ? operator->end : value->location.end
2351 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2360static pm_back_reference_read_node_t *
2361pm_back_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
2362 assert(name->type == PM_TOKEN_BACK_REFERENCE);
2363 pm_back_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_back_reference_read_node_t);
2365 *node = (pm_back_reference_read_node_t) {
2367 .type = PM_BACK_REFERENCE_READ_NODE,
2368 .node_id = PM_NODE_IDENTIFY(parser),
2369 .location = PM_LOCATION_TOKEN_VALUE(name),
2371 .name = pm_parser_constant_id_token(parser, name)
2380static pm_begin_node_t *
2381pm_begin_node_create(pm_parser_t *parser, const pm_token_t *begin_keyword, pm_statements_node_t *statements) {
2382 pm_begin_node_t *node = PM_NODE_ALLOC(parser, pm_begin_node_t);
2384 *node = (pm_begin_node_t) {
2386 .type = PM_BEGIN_NODE,
2387 .node_id = PM_NODE_IDENTIFY(parser),
2389 .start = begin_keyword->start,
2390 .end = statements == NULL ? begin_keyword->end : statements->base.location.end
2393 .begin_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(begin_keyword),
2394 .statements = statements,
2395 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
2405pm_begin_node_rescue_clause_set(pm_begin_node_t *node, pm_rescue_node_t *rescue_clause) {
2406 // If the begin keyword doesn't exist, we set the start on the begin_node
2407 if (!node->begin_keyword_loc.start) {
2408 node->base.location.start = rescue_clause->base.location.start;
2410 node->base.location.end = rescue_clause->base.location.end;
2411 node->rescue_clause = rescue_clause;
2418pm_begin_node_else_clause_set(pm_begin_node_t *node, pm_else_node_t *else_clause) {
2419 node->base.location.end = else_clause->base.location.end;
2420 node->else_clause = else_clause;
2427pm_begin_node_ensure_clause_set(pm_begin_node_t *node, pm_ensure_node_t *ensure_clause) {
2428 node->base.location.end = ensure_clause->base.location.end;
2429 node->ensure_clause = ensure_clause;
2436pm_begin_node_end_keyword_set(pm_begin_node_t *node, const pm_token_t *end_keyword) {
2437 assert(end_keyword->type == PM_TOKEN_KEYWORD_END || end_keyword->type == PM_TOKEN_MISSING);
2439 node->base.location.end = end_keyword->end;
2440 node->end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword);
2446static pm_block_argument_node_t *
2447pm_block_argument_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
2448 pm_block_argument_node_t *node = PM_NODE_ALLOC(parser, pm_block_argument_node_t);
2450 *node = (pm_block_argument_node_t) {
2452 .type = PM_BLOCK_ARGUMENT_NODE,
2453 .node_id = PM_NODE_IDENTIFY(parser),
2455 .start = operator->start,
2456 .end = expression == NULL ? operator->end : expression->location.end
2459 .expression = expression,
2460 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2469static pm_block_node_t *
2470pm_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) {
2471 pm_block_node_t *node = PM_NODE_ALLOC(parser, pm_block_node_t);
2473 *node = (pm_block_node_t) {
2475 .type = PM_BLOCK_NODE,
2476 .node_id = PM_NODE_IDENTIFY(parser),
2477 .location = { .start = opening->start, .end = closing->end },
2480 .parameters = parameters,
2482 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2483 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
2492static pm_block_parameter_node_t *
2493pm_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator) {
2494 assert(operator->type == PM_TOKEN_NOT_PROVIDED || operator->type == PM_TOKEN_UAMPERSAND || operator->type == PM_TOKEN_AMPERSAND);
2495 pm_block_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_block_parameter_node_t);
2497 *node = (pm_block_parameter_node_t) {
2499 .type = PM_BLOCK_PARAMETER_NODE,
2500 .node_id = PM_NODE_IDENTIFY(parser),
2502 .start = operator->start,
2503 .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
2506 .name = pm_parser_optional_constant_id_token(parser, name),
2507 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
2508 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2517static pm_block_parameters_node_t *
2518pm_block_parameters_node_create(pm_parser_t *parser, pm_parameters_node_t *parameters, const pm_token_t *opening) {
2519 pm_block_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_block_parameters_node_t);
2521 const uint8_t *start;
2522 if (opening->type != PM_TOKEN_NOT_PROVIDED) {
2523 start = opening->start;
2524 } else if (parameters != NULL) {
2525 start = parameters->base.location.start;
2531 if (parameters != NULL) {
2532 end = parameters->base.location.end;
2533 } else if (opening->type != PM_TOKEN_NOT_PROVIDED) {
2539 *node = (pm_block_parameters_node_t) {
2541 .type = PM_BLOCK_PARAMETERS_NODE,
2542 .node_id = PM_NODE_IDENTIFY(parser),
2548 .parameters = parameters,
2549 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2550 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2561pm_block_parameters_node_closing_set(pm_block_parameters_node_t *node, const pm_token_t *closing) {
2562 assert(closing->type == PM_TOKEN_PIPE || closing->type == PM_TOKEN_PARENTHESIS_RIGHT || closing->type == PM_TOKEN_MISSING);
2564 node->base.location.end = closing->end;
2565 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
2571static pm_block_local_variable_node_t *
2572pm_block_local_variable_node_create(pm_parser_t *parser, const pm_token_t *name) {
2573 pm_block_local_variable_node_t *node = PM_NODE_ALLOC(parser, pm_block_local_variable_node_t);
2575 *node = (pm_block_local_variable_node_t) {
2577 .type = PM_BLOCK_LOCAL_VARIABLE_NODE,
2578 .node_id = PM_NODE_IDENTIFY(parser),
2579 .location = PM_LOCATION_TOKEN_VALUE(name),
2581 .name = pm_parser_constant_id_token(parser, name)
2591pm_block_parameters_node_append_local(pm_block_parameters_node_t *node, const pm_block_local_variable_node_t *local) {
2592 pm_node_list_append(&node->locals, (pm_node_t *) local);
2594 if (node->base.location.start == NULL) node->base.location.start = local->base.location.start;
2595 node->base.location.end = local->base.location.end;
2601static pm_break_node_t *
2602pm_break_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
2603 assert(keyword->type == PM_TOKEN_KEYWORD_BREAK);
2604 pm_break_node_t *node = PM_NODE_ALLOC(parser, pm_break_node_t);
2606 *node = (pm_break_node_t) {
2608 .type = PM_BREAK_NODE,
2609 .node_id = PM_NODE_IDENTIFY(parser),
2611 .start = keyword->start,
2612 .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
2615 .arguments = arguments,
2616 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
2622// There are certain flags that we want to use internally but don't want to
2623// expose because they are not relevant beyond parsing. Therefore we'll define
2624// them here and not define them in config.yml/a header file.
2625static const pm_node_flags_t PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY = 0x4;
2626static const pm_node_flags_t PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY = 0x40;
2627static const pm_node_flags_t PM_CALL_NODE_FLAGS_COMPARISON = 0x80;
2628static const pm_node_flags_t PM_CALL_NODE_FLAGS_INDEX = 0x100;
2635static pm_call_node_t *
2636pm_call_node_create(pm_parser_t *parser, pm_node_flags_t flags) {
2637 pm_call_node_t *node = PM_NODE_ALLOC(parser, pm_call_node_t);
2639 *node = (pm_call_node_t) {
2641 .type = PM_CALL_NODE,
2643 .node_id = PM_NODE_IDENTIFY(parser),
2644 .location = PM_LOCATION_NULL_VALUE(parser),
2647 .call_operator_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2648 .message_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2649 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2651 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2663static inline pm_node_flags_t
2664pm_call_node_ignore_visibility_flag(const pm_node_t *receiver) {
2665 return PM_NODE_TYPE_P(receiver, PM_SELF_NODE) ? PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY : 0;
2672static pm_call_node_t *
2673pm_call_node_aref_create(pm_parser_t *parser, pm_node_t *receiver, pm_arguments_t *arguments) {
2674 pm_assert_value_expression(parser, receiver);
2676 pm_node_flags_t flags = pm_call_node_ignore_visibility_flag(receiver);
2677 if (arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_ARGUMENT_NODE)) {
2678 flags |= PM_CALL_NODE_FLAGS_INDEX;
2681 pm_call_node_t *node = pm_call_node_create(parser, flags);
2683 node->base.location.start = receiver->location.start;
2684 node->base.location.end = pm_arguments_end(arguments);
2686 node->receiver = receiver;
2687 node->message_loc.start = arguments->opening_loc.start;
2688 node->message_loc.end = arguments->closing_loc.end;
2690 node->opening_loc = arguments->opening_loc;
2691 node->arguments = arguments->arguments;
2692 node->closing_loc = arguments->closing_loc;
2693 node->block = arguments->block;
2695 node->name = pm_parser_constant_id_constant(parser, "[]", 2);
2702static pm_call_node_t *
2703pm_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) {
2704 pm_assert_value_expression(parser, receiver);
2705 pm_assert_value_expression(parser, argument);
2707 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver) | flags);
2709 node->base.location.start = MIN(receiver->location.start, argument->location.start);
2710 node->base.location.end = MAX(receiver->location.end, argument->location.end);
2712 node->receiver = receiver;
2713 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2715 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
2716 pm_arguments_node_arguments_append(arguments, argument);
2717 node->arguments = arguments;
2719 node->name = pm_parser_constant_id_token(parser, operator);
2726static pm_call_node_t *
2727pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_token_t *message, pm_arguments_t *arguments) {
2728 pm_assert_value_expression(parser, receiver);
2730 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2732 node->base.location.start = receiver->location.start;
2733 const uint8_t *end = pm_arguments_end(arguments);
2737 node->base.location.end = end;
2739 node->receiver = receiver;
2740 node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2741 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2742 node->opening_loc = arguments->opening_loc;
2743 node->arguments = arguments->arguments;
2744 node->closing_loc = arguments->closing_loc;
2745 node->block = arguments->block;
2747 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2748 pm_node_flag_set((pm_node_t *)node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2751 node->name = pm_parser_constant_id_token(parser, message);
2758static pm_call_node_t *
2759pm_call_node_call_synthesized_create(pm_parser_t *parser, pm_node_t *receiver, const char *message, pm_arguments_node_t *arguments) {
2760 pm_call_node_t *node = pm_call_node_create(parser, 0);
2761 node->base.location.start = parser->start;
2762 node->base.location.end = parser->end;
2764 node->receiver = receiver;
2765 node->call_operator_loc = (pm_location_t) { .start = NULL, .end = NULL };
2766 node->message_loc = (pm_location_t) { .start = NULL, .end = NULL };
2767 node->arguments = arguments;
2769 node->name = pm_parser_constant_id_constant(parser, message, strlen(message));
2777static pm_call_node_t *
2778pm_call_node_fcall_create(pm_parser_t *parser, pm_token_t *message, pm_arguments_t *arguments) {
2779 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2781 node->base.location.start = message->start;
2782 node->base.location.end = pm_arguments_end(arguments);
2784 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2785 node->opening_loc = arguments->opening_loc;
2786 node->arguments = arguments->arguments;
2787 node->closing_loc = arguments->closing_loc;
2788 node->block = arguments->block;
2790 node->name = pm_parser_constant_id_token(parser, message);
2798static pm_call_node_t *
2799pm_call_node_fcall_synthesized_create(pm_parser_t *parser, pm_arguments_node_t *arguments, pm_constant_id_t name) {
2800 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2802 node->base.location = PM_LOCATION_NULL_VALUE(parser);
2803 node->arguments = arguments;
2812static pm_call_node_t *
2813pm_call_node_not_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *message, pm_arguments_t *arguments) {
2814 pm_assert_value_expression(parser, receiver);
2815 if (receiver != NULL) pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
2817 pm_call_node_t *node = pm_call_node_create(parser, receiver == NULL ? 0 : pm_call_node_ignore_visibility_flag(receiver));
2819 node->base.location.start = message->start;
2820 if (arguments->closing_loc.start != NULL) {
2821 node->base.location.end = arguments->closing_loc.end;
2823 assert(receiver != NULL);
2824 node->base.location.end = receiver->location.end;
2827 node->receiver = receiver;
2828 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2829 node->opening_loc = arguments->opening_loc;
2830 node->arguments = arguments->arguments;
2831 node->closing_loc = arguments->closing_loc;
2833 node->name = pm_parser_constant_id_constant(parser, "!", 1);
2840static pm_call_node_t *
2841pm_call_node_shorthand_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_arguments_t *arguments) {
2842 pm_assert_value_expression(parser, receiver);
2844 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2846 node->base.location.start = receiver->location.start;
2847 node->base.location.end = pm_arguments_end(arguments);
2849 node->receiver = receiver;
2850 node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2851 node->opening_loc = arguments->opening_loc;
2852 node->arguments = arguments->arguments;
2853 node->closing_loc = arguments->closing_loc;
2854 node->block = arguments->block;
2856 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2857 pm_node_flag_set((pm_node_t *)node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2860 node->name = pm_parser_constant_id_constant(parser, "call", 4);
2867static pm_call_node_t *
2868pm_call_node_unary_create(pm_parser_t *parser, pm_token_t *operator, pm_node_t *receiver, const char *name) {
2869 pm_assert_value_expression(parser, receiver);
2871 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2873 node->base.location.start = operator->start;
2874 node->base.location.end = receiver->location.end;
2876 node->receiver = receiver;
2877 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2879 node->name = pm_parser_constant_id_constant(parser, name, strlen(name));
2887static pm_call_node_t *
2888pm_call_node_variable_call_create(pm_parser_t *parser, pm_token_t *message) {
2889 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2891 node->base.location = PM_LOCATION_TOKEN_VALUE(message);
2892 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2894 node->name = pm_parser_constant_id_token(parser, message);
2903pm_call_node_writable_p(const pm_parser_t *parser, const pm_call_node_t *node) {
2905 (node->message_loc.start != NULL) &&
2906 (node->message_loc.end[-1] != '!') &&
2907 (node->message_loc.end[-1] != '?') &&
2908 char_is_identifier_start(parser, node->message_loc.start, parser->end - node->message_loc.start) &&
2909 (node->opening_loc.start == NULL) &&
2910 (node->arguments == NULL) &&
2911 (node->block == NULL)
2919pm_call_write_read_name_init(pm_parser_t *parser, pm_constant_id_t *read_name, pm_constant_id_t *write_name) {
2920 pm_constant_t *write_constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *write_name);
2922 if (write_constant->length > 0) {
2923 size_t length = write_constant->length - 1;
2925 void *memory = xmalloc(length);
2926 memcpy(memory, write_constant->start, length);
2928 *read_name = pm_constant_pool_insert_owned(&parser->constant_pool, (uint8_t *) memory, length);
2930 // We can get here if the message was missing because of a syntax error.
2931 *read_name = pm_parser_constant_id_constant(parser, "", 0);
2938static pm_call_and_write_node_t *
2939pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2940 assert(target->block == NULL);
2941 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
2942 pm_call_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_and_write_node_t);
2944 *node = (pm_call_and_write_node_t) {
2946 .type = PM_CALL_AND_WRITE_NODE,
2947 .flags = target->base.flags,
2948 .node_id = PM_NODE_IDENTIFY(parser),
2950 .start = target->base.location.start,
2951 .end = value->location.end
2954 .receiver = target->receiver,
2955 .call_operator_loc = target->call_operator_loc,
2956 .message_loc = target->message_loc,
2958 .write_name = target->name,
2959 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2963 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
2965 // Here we're going to free the target, since it is no longer necessary.
2966 // However, we don't want to call `pm_node_destroy` because we want to keep
2967 // around all of its children since we just reused them.
2978pm_index_arguments_check(pm_parser_t *parser, const pm_arguments_node_t *arguments, const pm_node_t *block) {
2979 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) {
2980 if (arguments != NULL && PM_NODE_FLAG_P(arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) {
2982 PM_NODE_LIST_FOREACH(&arguments->arguments, index, node) {
2983 if (PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE)) {
2984 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_INDEX_KEYWORDS);
2990 if (block != NULL) {
2991 pm_parser_err_node(parser, block, PM_ERR_UNEXPECTED_INDEX_BLOCK);
2999static pm_index_and_write_node_t *
3000pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3001 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3002 pm_index_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_and_write_node_t);
3004 pm_index_arguments_check(parser, target->arguments, target->block);
3006 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3007 *node = (pm_index_and_write_node_t) {
3009 .type = PM_INDEX_AND_WRITE_NODE,
3010 .flags = target->base.flags,
3011 .node_id = PM_NODE_IDENTIFY(parser),
3013 .start = target->base.location.start,
3014 .end = value->location.end
3017 .receiver = target->receiver,
3018 .call_operator_loc = target->call_operator_loc,
3019 .opening_loc = target->opening_loc,
3020 .arguments = target->arguments,
3021 .closing_loc = target->closing_loc,
3022 .block = (pm_block_argument_node_t *) target->block,
3023 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3027 // Here we're going to free the target, since it is no longer necessary.
3028 // However, we don't want to call `pm_node_destroy` because we want to keep
3029 // around all of its children since we just reused them.
3038static pm_call_operator_write_node_t *
3039pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3040 assert(target->block == NULL);
3041 pm_call_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_operator_write_node_t);
3043 *node = (pm_call_operator_write_node_t) {
3045 .type = PM_CALL_OPERATOR_WRITE_NODE,
3046 .flags = target->base.flags,
3047 .node_id = PM_NODE_IDENTIFY(parser),
3049 .start = target->base.location.start,
3050 .end = value->location.end
3053 .receiver = target->receiver,
3054 .call_operator_loc = target->call_operator_loc,
3055 .message_loc = target->message_loc,
3057 .write_name = target->name,
3058 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
3059 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3063 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3065 // Here we're going to free the target, since it is no longer necessary.
3066 // However, we don't want to call `pm_node_destroy` because we want to keep
3067 // around all of its children since we just reused them.
3076static pm_index_operator_write_node_t *
3077pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3078 pm_index_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_operator_write_node_t);
3080 pm_index_arguments_check(parser, target->arguments, target->block);
3082 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3083 *node = (pm_index_operator_write_node_t) {
3085 .type = PM_INDEX_OPERATOR_WRITE_NODE,
3086 .flags = target->base.flags,
3087 .node_id = PM_NODE_IDENTIFY(parser),
3089 .start = target->base.location.start,
3090 .end = value->location.end
3093 .receiver = target->receiver,
3094 .call_operator_loc = target->call_operator_loc,
3095 .opening_loc = target->opening_loc,
3096 .arguments = target->arguments,
3097 .closing_loc = target->closing_loc,
3098 .block = (pm_block_argument_node_t *) target->block,
3099 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
3100 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3104 // Here we're going to free the target, since it is no longer necessary.
3105 // However, we don't want to call `pm_node_destroy` because we want to keep
3106 // around all of its children since we just reused them.
3115static pm_call_or_write_node_t *
3116pm_call_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3117 assert(target->block == NULL);
3118 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3119 pm_call_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_or_write_node_t);
3121 *node = (pm_call_or_write_node_t) {
3123 .type = PM_CALL_OR_WRITE_NODE,
3124 .flags = target->base.flags,
3125 .node_id = PM_NODE_IDENTIFY(parser),
3127 .start = target->base.location.start,
3128 .end = value->location.end
3131 .receiver = target->receiver,
3132 .call_operator_loc = target->call_operator_loc,
3133 .message_loc = target->message_loc,
3135 .write_name = target->name,
3136 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3140 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3142 // Here we're going to free the target, since it is no longer necessary.
3143 // However, we don't want to call `pm_node_destroy` because we want to keep
3144 // around all of its children since we just reused them.
3153static pm_index_or_write_node_t *
3154pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3155 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3156 pm_index_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_or_write_node_t);
3158 pm_index_arguments_check(parser, target->arguments, target->block);
3160 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3161 *node = (pm_index_or_write_node_t) {
3163 .type = PM_INDEX_OR_WRITE_NODE,
3164 .flags = target->base.flags,
3165 .node_id = PM_NODE_IDENTIFY(parser),
3167 .start = target->base.location.start,
3168 .end = value->location.end
3171 .receiver = target->receiver,
3172 .call_operator_loc = target->call_operator_loc,
3173 .opening_loc = target->opening_loc,
3174 .arguments = target->arguments,
3175 .closing_loc = target->closing_loc,
3176 .block = (pm_block_argument_node_t *) target->block,
3177 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3181 // Here we're going to free the target, since it is no longer necessary.
3182 // However, we don't want to call `pm_node_destroy` because we want to keep
3183 // around all of its children since we just reused them.
3193static pm_call_target_node_t *
3194pm_call_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3195 pm_call_target_node_t *node = PM_NODE_ALLOC(parser, pm_call_target_node_t);
3197 *node = (pm_call_target_node_t) {
3199 .type = PM_CALL_TARGET_NODE,
3200 .flags = target->base.flags,
3201 .node_id = PM_NODE_IDENTIFY(parser),
3202 .location = target->base.location
3204 .receiver = target->receiver,
3205 .call_operator_loc = target->call_operator_loc,
3206 .name = target->name,
3207 .message_loc = target->message_loc
3210 // Here we're going to free the target, since it is no longer necessary.
3211 // However, we don't want to call `pm_node_destroy` because we want to keep
3212 // around all of its children since we just reused them.
3222static pm_index_target_node_t *
3223pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3224 pm_index_target_node_t *node = PM_NODE_ALLOC(parser, pm_index_target_node_t);
3225 pm_node_flags_t flags = target->base.flags;
3227 pm_index_arguments_check(parser, target->arguments, target->block);
3229 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3230 *node = (pm_index_target_node_t) {
3232 .type = PM_INDEX_TARGET_NODE,
3233 .flags = flags | PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE,
3234 .node_id = PM_NODE_IDENTIFY(parser),
3235 .location = target->base.location
3237 .receiver = target->receiver,
3238 .opening_loc = target->opening_loc,
3239 .arguments = target->arguments,
3240 .closing_loc = target->closing_loc,
3241 .block = (pm_block_argument_node_t *) target->block,
3244 // Here we're going to free the target, since it is no longer necessary.
3245 // However, we don't want to call `pm_node_destroy` because we want to keep
3246 // around all of its children since we just reused them.
3255static pm_capture_pattern_node_t *
3256pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_local_variable_target_node_t *target, const pm_token_t *operator) {
3257 pm_capture_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_capture_pattern_node_t);
3259 *node = (pm_capture_pattern_node_t) {
3261 .type = PM_CAPTURE_PATTERN_NODE,
3262 .node_id = PM_NODE_IDENTIFY(parser),
3264 .start = value->location.start,
3265 .end = target->base.location.end
3270 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
3279static pm_case_node_t *
3280pm_case_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3281 pm_case_node_t *node = PM_NODE_ALLOC(parser, pm_case_node_t);
3283 *node = (pm_case_node_t) {
3285 .type = PM_CASE_NODE,
3286 .node_id = PM_NODE_IDENTIFY(parser),
3288 .start = case_keyword->start,
3289 .end = end_keyword->end
3292 .predicate = predicate,
3293 .else_clause = NULL,
3294 .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
3295 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3306pm_case_node_condition_append(pm_case_node_t *node, pm_node_t *condition) {
3307 assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
3309 pm_node_list_append(&node->conditions, condition);
3310 node->base.location.end = condition->location.end;
3317pm_case_node_else_clause_set(pm_case_node_t *node, pm_else_node_t *else_clause) {
3318 node->else_clause = else_clause;
3319 node->base.location.end = else_clause->base.location.end;
3326pm_case_node_end_keyword_loc_set(pm_case_node_t *node, const pm_token_t *end_keyword) {
3327 node->base.location.end = end_keyword->end;
3328 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
3334static pm_case_match_node_t *
3335pm_case_match_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3336 pm_case_match_node_t *node = PM_NODE_ALLOC(parser, pm_case_match_node_t);
3338 *node = (pm_case_match_node_t) {
3340 .type = PM_CASE_MATCH_NODE,
3341 .node_id = PM_NODE_IDENTIFY(parser),
3343 .start = case_keyword->start,
3344 .end = end_keyword->end
3347 .predicate = predicate,
3348 .else_clause = NULL,
3349 .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
3350 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3361pm_case_match_node_condition_append(pm_case_match_node_t *node, pm_node_t *condition) {
3362 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
3364 pm_node_list_append(&node->conditions, condition);
3365 node->base.location.end = condition->location.end;
3372pm_case_match_node_else_clause_set(pm_case_match_node_t *node, pm_else_node_t *else_clause) {
3373 node->else_clause = else_clause;
3374 node->base.location.end = else_clause->base.location.end;
3381pm_case_match_node_end_keyword_loc_set(pm_case_match_node_t *node, const pm_token_t *end_keyword) {
3382 node->base.location.end = end_keyword->end;
3383 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
3389static pm_class_node_t *
3390pm_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) {
3391 pm_class_node_t *node = PM_NODE_ALLOC(parser, pm_class_node_t);
3393 *node = (pm_class_node_t) {
3395 .type = PM_CLASS_NODE,
3396 .node_id = PM_NODE_IDENTIFY(parser),
3397 .location = { .start = class_keyword->start, .end = end_keyword->end },
3400 .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
3401 .constant_path = constant_path,
3402 .inheritance_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(inheritance_operator),
3403 .superclass = superclass,
3405 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3406 .name = pm_parser_constant_id_token(parser, name)
3415static pm_class_variable_and_write_node_t *
3416pm_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) {
3417 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3418 pm_class_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_and_write_node_t);
3420 *node = (pm_class_variable_and_write_node_t) {
3422 .type = PM_CLASS_VARIABLE_AND_WRITE_NODE,
3423 .node_id = PM_NODE_IDENTIFY(parser),
3425 .start = target->base.location.start,
3426 .end = value->location.end
3429 .name = target->name,
3430 .name_loc = target->base.location,
3431 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3441static pm_class_variable_operator_write_node_t *
3442pm_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) {
3443 pm_class_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_operator_write_node_t);
3445 *node = (pm_class_variable_operator_write_node_t) {
3447 .type = PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE,
3448 .node_id = PM_NODE_IDENTIFY(parser),
3450 .start = target->base.location.start,
3451 .end = value->location.end
3454 .name = target->name,
3455 .name_loc = target->base.location,
3456 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3458 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3467static pm_class_variable_or_write_node_t *
3468pm_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) {
3469 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3470 pm_class_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_or_write_node_t);
3472 *node = (pm_class_variable_or_write_node_t) {
3474 .type = PM_CLASS_VARIABLE_OR_WRITE_NODE,
3475 .node_id = PM_NODE_IDENTIFY(parser),
3477 .start = target->base.location.start,
3478 .end = value->location.end
3481 .name = target->name,
3482 .name_loc = target->base.location,
3483 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3493static pm_class_variable_read_node_t *
3494pm_class_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
3495 assert(token->type == PM_TOKEN_CLASS_VARIABLE);
3496 pm_class_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_read_node_t);
3498 *node = (pm_class_variable_read_node_t) {
3500 .type = PM_CLASS_VARIABLE_READ_NODE,
3501 .node_id = PM_NODE_IDENTIFY(parser),
3502 .location = PM_LOCATION_TOKEN_VALUE(token)
3504 .name = pm_parser_constant_id_token(parser, token)
3516static inline pm_node_flags_t
3517pm_implicit_array_write_flags(const pm_node_t *node, pm_node_flags_t flags) {
3518 if (PM_NODE_TYPE_P(node, PM_ARRAY_NODE) && ((const pm_array_node_t *) node)->opening_loc.start == NULL) {
3527static pm_class_variable_write_node_t *
3528pm_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) {
3529 pm_class_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_write_node_t);
3531 *node = (pm_class_variable_write_node_t) {
3533 .type = PM_CLASS_VARIABLE_WRITE_NODE,
3534 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3535 .node_id = PM_NODE_IDENTIFY(parser),
3537 .start = read_node->base.location.start,
3538 .end = value->location.end
3541 .name = read_node->name,
3542 .name_loc = PM_LOCATION_NODE_VALUE((pm_node_t *) read_node),
3543 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3553static pm_constant_path_and_write_node_t *
3554pm_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) {
3555 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3556 pm_constant_path_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_and_write_node_t);
3558 *node = (pm_constant_path_and_write_node_t) {
3560 .type = PM_CONSTANT_PATH_AND_WRITE_NODE,
3561 .node_id = PM_NODE_IDENTIFY(parser),
3563 .start = target->base.location.start,
3564 .end = value->location.end
3568 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3578static pm_constant_path_operator_write_node_t *
3579pm_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) {
3580 pm_constant_path_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_operator_write_node_t);
3582 *node = (pm_constant_path_operator_write_node_t) {
3584 .type = PM_CONSTANT_PATH_OPERATOR_WRITE_NODE,
3585 .node_id = PM_NODE_IDENTIFY(parser),
3587 .start = target->base.location.start,
3588 .end = value->location.end
3592 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3594 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3603static pm_constant_path_or_write_node_t *
3604pm_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) {
3605 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3606 pm_constant_path_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_or_write_node_t);
3608 *node = (pm_constant_path_or_write_node_t) {
3610 .type = PM_CONSTANT_PATH_OR_WRITE_NODE,
3611 .node_id = PM_NODE_IDENTIFY(parser),
3613 .start = target->base.location.start,
3614 .end = value->location.end
3618 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3628static pm_constant_path_node_t *
3629pm_constant_path_node_create(pm_parser_t *parser, pm_node_t *parent, const pm_token_t *delimiter, const pm_token_t *name_token) {
3630 pm_assert_value_expression(parser, parent);
3631 pm_constant_path_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_node_t);
3633 pm_constant_id_t name = PM_CONSTANT_ID_UNSET;
3634 if (name_token->type == PM_TOKEN_CONSTANT) {
3635 name = pm_parser_constant_id_token(parser, name_token);
3638 *node = (pm_constant_path_node_t) {
3640 .type = PM_CONSTANT_PATH_NODE,
3641 .node_id = PM_NODE_IDENTIFY(parser),
3643 .start = parent == NULL ? delimiter->start : parent->location.start,
3644 .end = name_token->end
3649 .delimiter_loc = PM_LOCATION_TOKEN_VALUE(delimiter),
3650 .name_loc = PM_LOCATION_TOKEN_VALUE(name_token)
3659static pm_constant_path_write_node_t *
3660pm_constant_path_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3661 pm_constant_path_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_write_node_t);
3663 *node = (pm_constant_path_write_node_t) {
3665 .type = PM_CONSTANT_PATH_WRITE_NODE,
3666 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3667 .node_id = PM_NODE_IDENTIFY(parser),
3669 .start = target->base.location.start,
3670 .end = value->location.end
3674 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3684static pm_constant_and_write_node_t *
3685pm_constant_and_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3686 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3687 pm_constant_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_and_write_node_t);
3689 *node = (pm_constant_and_write_node_t) {
3691 .type = PM_CONSTANT_AND_WRITE_NODE,
3692 .node_id = PM_NODE_IDENTIFY(parser),
3694 .start = target->base.location.start,
3695 .end = value->location.end
3698 .name = target->name,
3699 .name_loc = target->base.location,
3700 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3710static pm_constant_operator_write_node_t *
3711pm_constant_operator_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3712 pm_constant_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_operator_write_node_t);
3714 *node = (pm_constant_operator_write_node_t) {
3716 .type = PM_CONSTANT_OPERATOR_WRITE_NODE,
3717 .node_id = PM_NODE_IDENTIFY(parser),
3719 .start = target->base.location.start,
3720 .end = value->location.end
3723 .name = target->name,
3724 .name_loc = target->base.location,
3725 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3727 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3736static pm_constant_or_write_node_t *
3737pm_constant_or_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3738 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3739 pm_constant_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_or_write_node_t);
3741 *node = (pm_constant_or_write_node_t) {
3743 .type = PM_CONSTANT_OR_WRITE_NODE,
3744 .node_id = PM_NODE_IDENTIFY(parser),
3746 .start = target->base.location.start,
3747 .end = value->location.end
3750 .name = target->name,
3751 .name_loc = target->base.location,
3752 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3762static pm_constant_read_node_t *
3763pm_constant_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
3764 assert(name->type == PM_TOKEN_CONSTANT || name->type == PM_TOKEN_MISSING);
3765 pm_constant_read_node_t *node = PM_NODE_ALLOC(parser, pm_constant_read_node_t);
3767 *node = (pm_constant_read_node_t) {
3769 .type = PM_CONSTANT_READ_NODE,
3770 .node_id = PM_NODE_IDENTIFY(parser),
3771 .location = PM_LOCATION_TOKEN_VALUE(name)
3773 .name = pm_parser_constant_id_token(parser, name)
3782static pm_constant_write_node_t *
3783pm_constant_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3784 pm_constant_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_write_node_t);
3786 *node = (pm_constant_write_node_t) {
3788 .type = PM_CONSTANT_WRITE_NODE,
3789 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3790 .node_id = PM_NODE_IDENTIFY(parser),
3792 .start = target->base.location.start,
3793 .end = value->location.end
3796 .name = target->name,
3797 .name_loc = target->base.location,
3798 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3809pm_def_node_receiver_check(pm_parser_t *parser, const pm_node_t *node) {
3810 switch (PM_NODE_TYPE(node)) {
3811 case PM_BEGIN_NODE: {
3812 const pm_begin_node_t *cast = (pm_begin_node_t *) node;
3813 if (cast->statements != NULL) pm_def_node_receiver_check(parser, (pm_node_t *) cast->statements);
3816 case PM_PARENTHESES_NODE: {
3817 const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node;
3818 if (cast->body != NULL) pm_def_node_receiver_check(parser, cast->body);
3821 case PM_STATEMENTS_NODE: {
3822 const pm_statements_node_t *cast = (const pm_statements_node_t *) node;
3823 pm_def_node_receiver_check(parser, cast->body.nodes[cast->body.size - 1]);
3828 case PM_IMAGINARY_NODE:
3829 case PM_INTEGER_NODE:
3830 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
3831 case PM_INTERPOLATED_STRING_NODE:
3832 case PM_INTERPOLATED_SYMBOL_NODE:
3833 case PM_INTERPOLATED_X_STRING_NODE:
3834 case PM_RATIONAL_NODE:
3835 case PM_REGULAR_EXPRESSION_NODE:
3836 case PM_SOURCE_ENCODING_NODE:
3837 case PM_SOURCE_FILE_NODE:
3838 case PM_SOURCE_LINE_NODE:
3839 case PM_STRING_NODE:
3840 case PM_SYMBOL_NODE:
3841 case PM_X_STRING_NODE:
3842 pm_parser_err_node(parser, node, PM_ERR_SINGLETON_FOR_LITERALS);
3852static pm_def_node_t *
3854 pm_parser_t *parser,
3855 pm_constant_id_t name,
3856 const pm_token_t *name_loc,
3857 pm_node_t *receiver,
3858 pm_parameters_node_t *parameters,
3860 pm_constant_id_list_t *locals,
3861 const pm_token_t *def_keyword,
3862 const pm_token_t *operator,
3863 const pm_token_t *lparen,
3864 const pm_token_t *rparen,
3865 const pm_token_t *equal,
3866 const pm_token_t *end_keyword
3868 pm_def_node_t *node = PM_NODE_ALLOC(parser, pm_def_node_t);
3871 if (end_keyword->type == PM_TOKEN_NOT_PROVIDED) {
3872 end = body->location.end;
3874 end = end_keyword->end;
3877 if (receiver != NULL) {
3878 pm_def_node_receiver_check(parser, receiver);
3881 *node = (pm_def_node_t) {
3883 .type = PM_DEF_NODE,
3884 .node_id = PM_NODE_IDENTIFY(parser),
3885 .location = { .start = def_keyword->start, .end = end },
3888 .name_loc = PM_LOCATION_TOKEN_VALUE(name_loc),
3889 .receiver = receiver,
3890 .parameters = parameters,
3893 .def_keyword_loc = PM_LOCATION_TOKEN_VALUE(def_keyword),
3894 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3895 .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
3896 .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
3897 .equal_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(equal),
3898 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
3907static pm_defined_node_t *
3908pm_defined_node_create(pm_parser_t *parser, const pm_token_t *lparen, pm_node_t *value, const pm_token_t *rparen, const pm_location_t *keyword_loc) {
3909 pm_defined_node_t *node = PM_NODE_ALLOC(parser, pm_defined_node_t);
3911 *node = (pm_defined_node_t) {
3913 .type = PM_DEFINED_NODE,
3914 .node_id = PM_NODE_IDENTIFY(parser),
3916 .start = keyword_loc->start,
3917 .end = (rparen->type == PM_TOKEN_NOT_PROVIDED ? value->location.end : rparen->end)
3920 .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
3922 .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
3923 .keyword_loc = *keyword_loc
3932static pm_else_node_t *
3933pm_else_node_create(pm_parser_t *parser, const pm_token_t *else_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
3934 pm_else_node_t *node = PM_NODE_ALLOC(parser, pm_else_node_t);
3935 const uint8_t *end = NULL;
3936 if ((end_keyword->type == PM_TOKEN_NOT_PROVIDED) && (statements != NULL)) {
3937 end = statements->base.location.end;
3939 end = end_keyword->end;
3942 *node = (pm_else_node_t) {
3944 .type = PM_ELSE_NODE,
3945 .node_id = PM_NODE_IDENTIFY(parser),
3947 .start = else_keyword->start,
3951 .else_keyword_loc = PM_LOCATION_TOKEN_VALUE(else_keyword),
3952 .statements = statements,
3953 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
3962static pm_embedded_statements_node_t *
3963pm_embedded_statements_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
3964 pm_embedded_statements_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_statements_node_t);
3966 *node = (pm_embedded_statements_node_t) {
3968 .type = PM_EMBEDDED_STATEMENTS_NODE,
3969 .node_id = PM_NODE_IDENTIFY(parser),
3971 .start = opening->start,
3975 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
3976 .statements = statements,
3977 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
3986static pm_embedded_variable_node_t *
3987pm_embedded_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
3988 pm_embedded_variable_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_variable_node_t);
3990 *node = (pm_embedded_variable_node_t) {
3992 .type = PM_EMBEDDED_VARIABLE_NODE,
3993 .node_id = PM_NODE_IDENTIFY(parser),
3995 .start = operator->start,
3996 .end = variable->location.end
3999 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4000 .variable = variable
4009static pm_ensure_node_t *
4010pm_ensure_node_create(pm_parser_t *parser, const pm_token_t *ensure_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
4011 pm_ensure_node_t *node = PM_NODE_ALLOC(parser, pm_ensure_node_t);
4013 *node = (pm_ensure_node_t) {
4015 .type = PM_ENSURE_NODE,
4016 .node_id = PM_NODE_IDENTIFY(parser),
4018 .start = ensure_keyword->start,
4019 .end = end_keyword->end
4022 .ensure_keyword_loc = PM_LOCATION_TOKEN_VALUE(ensure_keyword),
4023 .statements = statements,
4024 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
4033static pm_false_node_t *
4034pm_false_node_create(pm_parser_t *parser, const pm_token_t *token) {
4035 assert(token->type == PM_TOKEN_KEYWORD_FALSE);
4036 pm_false_node_t *node = PM_NODE_ALLOC(parser, pm_false_node_t);
4038 *node = (pm_false_node_t) {{
4039 .type = PM_FALSE_NODE,
4040 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4041 .node_id = PM_NODE_IDENTIFY(parser),
4042 .location = PM_LOCATION_TOKEN_VALUE(token)
4052static pm_find_pattern_node_t *
4053pm_find_pattern_node_create(pm_parser_t *parser, pm_node_list_t *nodes) {
4054 pm_find_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_find_pattern_node_t);
4056 pm_node_t *left = nodes->nodes[0];
4057 assert(PM_NODE_TYPE_P(left, PM_SPLAT_NODE));
4058 pm_splat_node_t *left_splat_node = (pm_splat_node_t *) left;
4062 if (nodes->size == 1) {
4063 right = (pm_node_t *) pm_missing_node_create(parser, left->location.end, left->location.end);
4065 right = nodes->nodes[nodes->size - 1];
4066 assert(PM_NODE_TYPE_P(right, PM_SPLAT_NODE));
4069#if PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS
4070 // FindPatternNode#right is typed as SplatNode in this case, so replace the potential MissingNode with a SplatNode.
4071 // The resulting AST will anyway be ignored, but this file still needs to compile.
4072 pm_splat_node_t *right_splat_node = PM_NODE_TYPE_P(right, PM_SPLAT_NODE) ? (pm_splat_node_t *) right : left_splat_node;
4074 pm_node_t *right_splat_node = right;
4076 *node = (pm_find_pattern_node_t) {
4078 .type = PM_FIND_PATTERN_NODE,
4079 .node_id = PM_NODE_IDENTIFY(parser),
4081 .start = left->location.start,
4082 .end = right->location.end,
4086 .left = left_splat_node,
4087 .right = right_splat_node,
4089 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4090 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4093 // For now we're going to just copy over each pointer manually. This could be
4094 // much more efficient, as we could instead resize the node list to only point
4096 for (size_t index = 1; index < nodes->size - 1; index++) {
4097 pm_node_list_append(&node->requireds, nodes->nodes[index]);
4108pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
4109 ptrdiff_t diff = token->end - token->start;
4110 if (diff <= 0) return 0.0;
4112 // First, get a buffer of the content.
4113 size_t length = (size_t) diff;
4114 char *buffer = xmalloc(sizeof(char) * (length + 1));
4115 memcpy((void *) buffer, token->start, length);
4117 // Next, determine if we need to replace the decimal point because of
4118 // locale-specific options, and then normalize them if we have to.
4119 char decimal_point = *localeconv()->decimal_point;
4120 if (decimal_point != '.') {
4121 for (size_t index = 0; index < length; index++) {
4122 if (buffer[index] == '.') buffer[index] = decimal_point;
4126 // Next, handle underscores by removing them from the buffer.
4127 for (size_t index = 0; index < length; index++) {
4128 if (buffer[index] == '_') {
4129 memmove((void *) (buffer + index), (void *) (buffer + index + 1), length - index);
4134 // Null-terminate the buffer so that strtod cannot read off the end.
4135 buffer[length] = '\0';
4137 // Now, call strtod to parse the value. Note that CRuby has their own
4138 // version of strtod which avoids locales. We're okay using the locale-aware
4139 // version because we've already validated through the parser that the token
4140 // is in a valid format.
4143 double value = strtod(buffer, &eptr);
4145 // This should never happen, because we've already checked that the token
4146 // is in a valid format. However it's good to be safe.
4147 if ((eptr != buffer + length) || (errno != 0 && errno != ERANGE)) {
4148 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, (*token), PM_ERR_FLOAT_PARSE);
4149 xfree((void *) buffer);
4153 // If errno is set, then it should only be ERANGE. At this point we need to
4154 // check if it's infinity (it should be).
4155 if (errno == ERANGE && PRISM_ISINF(value)) {
4157 const char *ellipsis;
4163 warn_width = (int) length;
4167 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);
4168 value = (value < 0.0) ? -HUGE_VAL : HUGE_VAL;
4171 // Finally we can free the buffer and return the value.
4172 xfree((void *) buffer);
4179static pm_float_node_t *
4180pm_float_node_create(pm_parser_t *parser, const pm_token_t *token) {
4181 assert(token->type == PM_TOKEN_FLOAT);
4182 pm_float_node_t *node = PM_NODE_ALLOC(parser, pm_float_node_t);
4184 *node = (pm_float_node_t) {
4186 .type = PM_FLOAT_NODE,
4187 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4188 .node_id = PM_NODE_IDENTIFY(parser),
4189 .location = PM_LOCATION_TOKEN_VALUE(token)
4191 .value = pm_double_parse(parser, token)
4200static pm_imaginary_node_t *
4201pm_float_node_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4202 assert(token->type == PM_TOKEN_FLOAT_IMAGINARY);
4204 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4205 *node = (pm_imaginary_node_t) {
4207 .type = PM_IMAGINARY_NODE,
4208 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4209 .node_id = PM_NODE_IDENTIFY(parser),
4210 .location = PM_LOCATION_TOKEN_VALUE(token)
4212 .numeric = (pm_node_t *) pm_float_node_create(parser, &((pm_token_t) {
4213 .type = PM_TOKEN_FLOAT,
4214 .start = token->start,
4215 .end = token->end - 1
4225static pm_rational_node_t *
4226pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
4227 assert(token->type == PM_TOKEN_FLOAT_RATIONAL);
4229 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
4230 *node = (pm_rational_node_t) {
4232 .type = PM_RATIONAL_NODE,
4233 .flags = PM_INTEGER_BASE_FLAGS_DECIMAL | PM_NODE_FLAG_STATIC_LITERAL,
4234 .node_id = PM_NODE_IDENTIFY(parser),
4235 .location = PM_LOCATION_TOKEN_VALUE(token)
4238 .denominator = { 0 }
4241 const uint8_t *start = token->start;
4242 const uint8_t *end = token->end - 1; // r
4244 while (start < end && *start == '0') start++; // 0.1 -> .1
4245 while (end > start && end[-1] == '0') end--; // 1.0 -> 1.
4247 size_t length = (size_t) (end - start);
4249 node->denominator.value = 1;
4253 const uint8_t *point = memchr(start, '.', length);
4254 assert(point && "should have a decimal point");
4256 uint8_t *digits = xmalloc(length);
4257 if (digits == NULL) {
4258 fputs("[pm_float_node_rational_create] Failed to allocate memory", stderr);
4262 memcpy(digits, start, (unsigned long) (point - start));
4263 memcpy(digits + (point - start), point + 1, (unsigned long) (end - point - 1));
4264 pm_integer_parse(&node->numerator, PM_INTEGER_BASE_DEFAULT, digits, digits + length - 1);
4267 if (end - point > 1) memset(digits + 1, '0', (size_t) (end - point - 1));
4268 pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + (end - point));
4271 pm_integers_reduce(&node->numerator, &node->denominator);
4279static pm_imaginary_node_t *
4280pm_float_node_rational_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4281 assert(token->type == PM_TOKEN_FLOAT_RATIONAL_IMAGINARY);
4283 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4284 *node = (pm_imaginary_node_t) {
4286 .type = PM_IMAGINARY_NODE,
4287 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4288 .node_id = PM_NODE_IDENTIFY(parser),
4289 .location = PM_LOCATION_TOKEN_VALUE(token)
4291 .numeric = (pm_node_t *) pm_float_node_rational_create(parser, &((pm_token_t) {
4292 .type = PM_TOKEN_FLOAT_RATIONAL,
4293 .start = token->start,
4294 .end = token->end - 1
4304static pm_for_node_t *
4306 pm_parser_t *parser,
4308 pm_node_t *collection,
4309 pm_statements_node_t *statements,
4310 const pm_token_t *for_keyword,
4311 const pm_token_t *in_keyword,
4312 const pm_token_t *do_keyword,
4313 const pm_token_t *end_keyword
4315 pm_for_node_t *node = PM_NODE_ALLOC(parser, pm_for_node_t);
4317 *node = (pm_for_node_t) {
4319 .type = PM_FOR_NODE,
4320 .node_id = PM_NODE_IDENTIFY(parser),
4322 .start = for_keyword->start,
4323 .end = end_keyword->end
4327 .collection = collection,
4328 .statements = statements,
4329 .for_keyword_loc = PM_LOCATION_TOKEN_VALUE(for_keyword),
4330 .in_keyword_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
4331 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
4332 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
4341static pm_forwarding_arguments_node_t *
4342pm_forwarding_arguments_node_create(pm_parser_t *parser, const pm_token_t *token) {
4343 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4344 pm_forwarding_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_arguments_node_t);
4346 *node = (pm_forwarding_arguments_node_t) {{
4347 .type = PM_FORWARDING_ARGUMENTS_NODE,
4348 .node_id = PM_NODE_IDENTIFY(parser),
4349 .location = PM_LOCATION_TOKEN_VALUE(token)
4358static pm_forwarding_parameter_node_t *
4359pm_forwarding_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
4360 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4361 pm_forwarding_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_parameter_node_t);
4363 *node = (pm_forwarding_parameter_node_t) {{
4364 .type = PM_FORWARDING_PARAMETER_NODE,
4365 .node_id = PM_NODE_IDENTIFY(parser),
4366 .location = PM_LOCATION_TOKEN_VALUE(token)
4375static pm_forwarding_super_node_t *
4376pm_forwarding_super_node_create(pm_parser_t *parser, const pm_token_t *token, pm_arguments_t *arguments) {
4377 assert(arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_NODE));
4378 assert(token->type == PM_TOKEN_KEYWORD_SUPER);
4379 pm_forwarding_super_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_super_node_t);
4381 pm_block_node_t *block = NULL;
4382 if (arguments->block != NULL) {
4383 block = (pm_block_node_t *) arguments->block;
4386 *node = (pm_forwarding_super_node_t) {
4388 .type = PM_FORWARDING_SUPER_NODE,
4389 .node_id = PM_NODE_IDENTIFY(parser),
4391 .start = token->start,
4392 .end = block != NULL ? block->base.location.end : token->end
4405static pm_hash_pattern_node_t *
4406pm_hash_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4407 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4409 *node = (pm_hash_pattern_node_t) {
4411 .type = PM_HASH_PATTERN_NODE,
4412 .node_id = PM_NODE_IDENTIFY(parser),
4414 .start = opening->start,
4419 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4420 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
4431static pm_hash_pattern_node_t *
4432pm_hash_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *elements, pm_node_t *rest) {
4433 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4435 const uint8_t *start;
4438 if (elements->size > 0) {
4440 start = elements->nodes[0]->location.start;
4441 end = rest->location.end;
4443 start = elements->nodes[0]->location.start;
4444 end = elements->nodes[elements->size - 1]->location.end;
4447 assert(rest != NULL);
4448 start = rest->location.start;
4449 end = rest->location.end;
4452 *node = (pm_hash_pattern_node_t) {
4454 .type = PM_HASH_PATTERN_NODE,
4455 .node_id = PM_NODE_IDENTIFY(parser),
4464 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4465 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4469 PM_NODE_LIST_FOREACH(elements, index, element) {
4470 pm_node_list_append(&node->elements, element);
4479static pm_constant_id_t
4480pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
4481 switch (PM_NODE_TYPE(target)) {
4482 case PM_GLOBAL_VARIABLE_READ_NODE:
4483 return ((pm_global_variable_read_node_t *) target)->name;
4484 case PM_BACK_REFERENCE_READ_NODE:
4485 return ((pm_back_reference_read_node_t *) target)->name;
4486 case PM_NUMBERED_REFERENCE_READ_NODE:
4487 // This will only ever happen in the event of a syntax error, but we
4488 // still need to provide something for the node.
4489 return pm_parser_constant_id_location(parser, target->location.start, target->location.end);
4491 assert(false && "unreachable");
4492 return (pm_constant_id_t) -1;
4499static pm_global_variable_and_write_node_t *
4500pm_global_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4501 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4502 pm_global_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_and_write_node_t);
4504 *node = (pm_global_variable_and_write_node_t) {
4506 .type = PM_GLOBAL_VARIABLE_AND_WRITE_NODE,
4507 .node_id = PM_NODE_IDENTIFY(parser),
4509 .start = target->location.start,
4510 .end = value->location.end
4513 .name = pm_global_variable_write_name(parser, target),
4514 .name_loc = target->location,
4515 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4525static pm_global_variable_operator_write_node_t *
4526pm_global_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4527 pm_global_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_operator_write_node_t);
4529 *node = (pm_global_variable_operator_write_node_t) {
4531 .type = PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE,
4532 .node_id = PM_NODE_IDENTIFY(parser),
4534 .start = target->location.start,
4535 .end = value->location.end
4538 .name = pm_global_variable_write_name(parser, target),
4539 .name_loc = target->location,
4540 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4542 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
4551static pm_global_variable_or_write_node_t *
4552pm_global_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4553 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4554 pm_global_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_or_write_node_t);
4556 *node = (pm_global_variable_or_write_node_t) {
4558 .type = PM_GLOBAL_VARIABLE_OR_WRITE_NODE,
4559 .node_id = PM_NODE_IDENTIFY(parser),
4561 .start = target->location.start,
4562 .end = value->location.end
4565 .name = pm_global_variable_write_name(parser, target),
4566 .name_loc = target->location,
4567 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4577static pm_global_variable_read_node_t *
4578pm_global_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
4579 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4581 *node = (pm_global_variable_read_node_t) {
4583 .type = PM_GLOBAL_VARIABLE_READ_NODE,
4584 .node_id = PM_NODE_IDENTIFY(parser),
4585 .location = PM_LOCATION_TOKEN_VALUE(name),
4587 .name = pm_parser_constant_id_token(parser, name)
4596static pm_global_variable_read_node_t *
4597pm_global_variable_read_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name) {
4598 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4600 *node = (pm_global_variable_read_node_t) {
4602 .type = PM_GLOBAL_VARIABLE_READ_NODE,
4603 .node_id = PM_NODE_IDENTIFY(parser),
4604 .location = PM_LOCATION_NULL_VALUE(parser)
4615static pm_global_variable_write_node_t *
4616pm_global_variable_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4617 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4619 *node = (pm_global_variable_write_node_t) {
4621 .type = PM_GLOBAL_VARIABLE_WRITE_NODE,
4622 .node_id = PM_NODE_IDENTIFY(parser),
4623 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
4625 .start = target->location.start,
4626 .end = value->location.end
4629 .name = pm_global_variable_write_name(parser, target),
4630 .name_loc = PM_LOCATION_NODE_VALUE(target),
4631 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
4641static pm_global_variable_write_node_t *
4642pm_global_variable_write_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name, pm_node_t *value) {
4643 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4645 *node = (pm_global_variable_write_node_t) {
4647 .type = PM_GLOBAL_VARIABLE_WRITE_NODE,
4648 .node_id = PM_NODE_IDENTIFY(parser),
4649 .location = PM_LOCATION_NULL_VALUE(parser)
4652 .name_loc = PM_LOCATION_NULL_VALUE(parser),
4653 .operator_loc = PM_LOCATION_NULL_VALUE(parser),
4663static pm_hash_node_t *
4664pm_hash_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4665 assert(opening != NULL);
4666 pm_hash_node_t *node = PM_NODE_ALLOC(parser, pm_hash_node_t);
4668 *node = (pm_hash_node_t) {
4670 .type = PM_HASH_NODE,
4671 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4672 .node_id = PM_NODE_IDENTIFY(parser),
4673 .location = PM_LOCATION_TOKEN_VALUE(opening)
4675 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4676 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
4687pm_hash_node_elements_append(pm_hash_node_t *hash, pm_node_t *element) {
4688 pm_node_list_append(&hash->elements, element);
4690 bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE);
4691 if (static_literal) {
4692 pm_assoc_node_t *assoc = (pm_assoc_node_t *) element;
4693 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);
4694 static_literal = static_literal && PM_NODE_FLAG_P(assoc->key, PM_NODE_FLAG_STATIC_LITERAL);
4695 static_literal = static_literal && PM_NODE_FLAG_P(assoc, PM_NODE_FLAG_STATIC_LITERAL);
4698 if (!static_literal) {
4699 pm_node_flag_unset((pm_node_t *)hash, PM_NODE_FLAG_STATIC_LITERAL);
4704pm_hash_node_closing_loc_set(pm_hash_node_t *hash, pm_token_t *token) {
4705 hash->base.location.end = token->end;
4706 hash->closing_loc = PM_LOCATION_TOKEN_VALUE(token);
4712static pm_if_node_t *
4713pm_if_node_create(pm_parser_t *parser,
4714 const pm_token_t *if_keyword,
4715 pm_node_t *predicate,
4716 const pm_token_t *then_keyword,
4717 pm_statements_node_t *statements,
4718 pm_node_t *subsequent,
4719 const pm_token_t *end_keyword
4721 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4722 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4725 if (end_keyword->type != PM_TOKEN_NOT_PROVIDED) {
4726 end = end_keyword->end;
4727 } else if (subsequent != NULL) {
4728 end = subsequent->location.end;
4729 } else if (pm_statements_node_body_length(statements) != 0) {
4730 end = statements->base.location.end;
4732 end = predicate->location.end;
4735 *node = (pm_if_node_t) {
4738 .flags = PM_NODE_FLAG_NEWLINE,
4739 .node_id = PM_NODE_IDENTIFY(parser),
4741 .start = if_keyword->start,
4745 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4746 .predicate = predicate,
4747 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
4748 .statements = statements,
4749 .subsequent = subsequent,
4750 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
4759static pm_if_node_t *
4760pm_if_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *if_keyword, pm_node_t *predicate) {
4761 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4762 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4764 pm_statements_node_t *statements = pm_statements_node_create(parser);
4765 pm_statements_node_body_append(parser, statements, statement, true);
4767 *node = (pm_if_node_t) {
4770 .flags = PM_NODE_FLAG_NEWLINE,
4771 .node_id = PM_NODE_IDENTIFY(parser),
4773 .start = statement->location.start,
4774 .end = predicate->location.end
4777 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4778 .predicate = predicate,
4779 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4780 .statements = statements,
4782 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4791static pm_if_node_t *
4792pm_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) {
4793 pm_assert_value_expression(parser, predicate);
4794 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4796 pm_statements_node_t *if_statements = pm_statements_node_create(parser);
4797 pm_statements_node_body_append(parser, if_statements, true_expression, true);
4799 pm_statements_node_t *else_statements = pm_statements_node_create(parser);
4800 pm_statements_node_body_append(parser, else_statements, false_expression, true);
4802 pm_token_t end_keyword = not_provided(parser);
4803 pm_else_node_t *else_node = pm_else_node_create(parser, colon, else_statements, &end_keyword);
4805 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4807 *node = (pm_if_node_t) {
4810 .flags = PM_NODE_FLAG_NEWLINE,
4811 .node_id = PM_NODE_IDENTIFY(parser),
4813 .start = predicate->location.start,
4814 .end = false_expression->location.end,
4817 .if_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4818 .predicate = predicate,
4819 .then_keyword_loc = PM_LOCATION_TOKEN_VALUE(qmark),
4820 .statements = if_statements,
4821 .subsequent = (pm_node_t *) else_node,
4822 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4830pm_if_node_end_keyword_loc_set(pm_if_node_t *node, const pm_token_t *keyword) {
4831 node->base.location.end = keyword->end;
4832 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4836pm_else_node_end_keyword_loc_set(pm_else_node_t *node, const pm_token_t *keyword) {
4837 node->base.location.end = keyword->end;
4838 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4844static pm_implicit_node_t *
4845pm_implicit_node_create(pm_parser_t *parser, pm_node_t *value) {
4846 pm_implicit_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_node_t);
4848 *node = (pm_implicit_node_t) {
4850 .type = PM_IMPLICIT_NODE,
4851 .node_id = PM_NODE_IDENTIFY(parser),
4852 .location = value->location
4863static pm_implicit_rest_node_t *
4864pm_implicit_rest_node_create(pm_parser_t *parser, const pm_token_t *token) {
4865 assert(token->type == PM_TOKEN_COMMA);
4867 pm_implicit_rest_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_rest_node_t);
4869 *node = (pm_implicit_rest_node_t) {
4871 .type = PM_IMPLICIT_REST_NODE,
4872 .node_id = PM_NODE_IDENTIFY(parser),
4873 .location = PM_LOCATION_TOKEN_VALUE(token)
4883static pm_integer_node_t *
4884pm_integer_node_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4885 assert(token->type == PM_TOKEN_INTEGER);
4886 pm_integer_node_t *node = PM_NODE_ALLOC(parser, pm_integer_node_t);
4888 *node = (pm_integer_node_t) {
4890 .type = PM_INTEGER_NODE,
4891 .flags = base | PM_NODE_FLAG_STATIC_LITERAL,
4892 .node_id = PM_NODE_IDENTIFY(parser),
4893 .location = PM_LOCATION_TOKEN_VALUE(token)
4898 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4900 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4901 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4902 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4903 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4904 default: assert(false && "unreachable"); break;
4907 pm_integer_parse(&node->value, integer_base, token->start, token->end);
4915static pm_imaginary_node_t *
4916pm_integer_node_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4917 assert(token->type == PM_TOKEN_INTEGER_IMAGINARY);
4919 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4920 *node = (pm_imaginary_node_t) {
4922 .type = PM_IMAGINARY_NODE,
4923 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4924 .node_id = PM_NODE_IDENTIFY(parser),
4925 .location = PM_LOCATION_TOKEN_VALUE(token)
4927 .numeric = (pm_node_t *) pm_integer_node_create(parser, base, &((pm_token_t) {
4928 .type = PM_TOKEN_INTEGER,
4929 .start = token->start,
4930 .end = token->end - 1
4941static pm_rational_node_t *
4942pm_integer_node_rational_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4943 assert(token->type == PM_TOKEN_INTEGER_RATIONAL);
4945 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
4946 *node = (pm_rational_node_t) {
4948 .type = PM_RATIONAL_NODE,
4949 .flags = base | PM_NODE_FLAG_STATIC_LITERAL,
4950 .node_id = PM_NODE_IDENTIFY(parser),
4951 .location = PM_LOCATION_TOKEN_VALUE(token)
4954 .denominator = { .value = 1, 0 }
4957 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4959 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4960 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4961 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4962 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4963 default: assert(false && "unreachable"); break;
4966 pm_integer_parse(&node->numerator, integer_base, token->start, token->end - 1);
4975static pm_imaginary_node_t *
4976pm_integer_node_rational_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4977 assert(token->type == PM_TOKEN_INTEGER_RATIONAL_IMAGINARY);
4979 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4980 *node = (pm_imaginary_node_t) {
4982 .type = PM_IMAGINARY_NODE,
4983 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4984 .node_id = PM_NODE_IDENTIFY(parser),
4985 .location = PM_LOCATION_TOKEN_VALUE(token)
4987 .numeric = (pm_node_t *) pm_integer_node_rational_create(parser, base, &((pm_token_t) {
4988 .type = PM_TOKEN_INTEGER_RATIONAL,
4989 .start = token->start,
4990 .end = token->end - 1
5000static pm_in_node_t *
5001pm_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) {
5002 pm_in_node_t *node = PM_NODE_ALLOC(parser, pm_in_node_t);
5005 if (statements != NULL) {
5006 end = statements->base.location.end;
5007 } else if (then_keyword->type != PM_TOKEN_NOT_PROVIDED) {
5008 end = then_keyword->end;
5010 end = pattern->location.end;
5013 *node = (pm_in_node_t) {
5016 .node_id = PM_NODE_IDENTIFY(parser),
5018 .start = in_keyword->start,
5023 .statements = statements,
5024 .in_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
5025 .then_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword)
5034static pm_instance_variable_and_write_node_t *
5035pm_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) {
5036 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5037 pm_instance_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_and_write_node_t);
5039 *node = (pm_instance_variable_and_write_node_t) {
5041 .type = PM_INSTANCE_VARIABLE_AND_WRITE_NODE,
5042 .node_id = PM_NODE_IDENTIFY(parser),
5044 .start = target->base.location.start,
5045 .end = value->location.end
5048 .name = target->name,
5049 .name_loc = target->base.location,
5050 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5060static pm_instance_variable_operator_write_node_t *
5061pm_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) {
5062 pm_instance_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_operator_write_node_t);
5064 *node = (pm_instance_variable_operator_write_node_t) {
5066 .type = PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE,
5067 .node_id = PM_NODE_IDENTIFY(parser),
5069 .start = target->base.location.start,
5070 .end = value->location.end
5073 .name = target->name,
5074 .name_loc = target->base.location,
5075 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5077 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
5086static pm_instance_variable_or_write_node_t *
5087pm_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) {
5088 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5089 pm_instance_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_or_write_node_t);
5091 *node = (pm_instance_variable_or_write_node_t) {
5093 .type = PM_INSTANCE_VARIABLE_OR_WRITE_NODE,
5094 .node_id = PM_NODE_IDENTIFY(parser),
5096 .start = target->base.location.start,
5097 .end = value->location.end
5100 .name = target->name,
5101 .name_loc = target->base.location,
5102 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5112static pm_instance_variable_read_node_t *
5113pm_instance_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
5114 assert(token->type == PM_TOKEN_INSTANCE_VARIABLE);
5115 pm_instance_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_read_node_t);
5117 *node = (pm_instance_variable_read_node_t) {
5119 .type = PM_INSTANCE_VARIABLE_READ_NODE,
5120 .node_id = PM_NODE_IDENTIFY(parser),
5121 .location = PM_LOCATION_TOKEN_VALUE(token)
5123 .name = pm_parser_constant_id_token(parser, token)
5133static pm_instance_variable_write_node_t *
5134pm_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) {
5135 pm_instance_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_write_node_t);
5136 *node = (pm_instance_variable_write_node_t) {
5138 .type = PM_INSTANCE_VARIABLE_WRITE_NODE,
5139 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5140 .node_id = PM_NODE_IDENTIFY(parser),
5142 .start = read_node->base.location.start,
5143 .end = value->location.end
5146 .name = read_node->name,
5147 .name_loc = PM_LOCATION_NODE_BASE_VALUE(read_node),
5148 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
5161pm_interpolated_node_append(pm_node_t *node, pm_node_list_t *parts, pm_node_t *part) {
5162 switch (PM_NODE_TYPE(part)) {
5163 case PM_STRING_NODE:
5164 pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5166 case PM_EMBEDDED_STATEMENTS_NODE: {
5167 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5168 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5170 if (embedded == NULL) {
5171 // If there are no statements or more than one statement, then
5172 // we lose the static literal flag.
5173 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5174 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5175 // If the embedded statement is a string, then we can keep the
5176 // static literal flag and mark the string as frozen.
5177 pm_node_flag_set(embedded, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5178 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5179 // If the embedded statement is an interpolated string and it's
5180 // a static literal, then we can keep the static literal flag.
5182 // Otherwise we lose the static literal flag.
5183 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5188 case PM_EMBEDDED_VARIABLE_NODE:
5189 pm_node_flag_unset((pm_node_t *) node, PM_NODE_FLAG_STATIC_LITERAL);
5192 assert(false && "unexpected node type");
5196 pm_node_list_append(parts, part);
5202static pm_interpolated_regular_expression_node_t *
5203pm_interpolated_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening) {
5204 pm_interpolated_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_regular_expression_node_t);
5206 *node = (pm_interpolated_regular_expression_node_t) {
5208 .type = PM_INTERPOLATED_REGULAR_EXPRESSION_NODE,
5209 .flags = PM_NODE_FLAG_STATIC_LITERAL,
5210 .node_id = PM_NODE_IDENTIFY(parser),
5212 .start = opening->start,
5216 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5217 .closing_loc = PM_LOCATION_TOKEN_VALUE(opening),
5225pm_interpolated_regular_expression_node_append(pm_interpolated_regular_expression_node_t *node, pm_node_t *part) {
5226 if (node->base.location.start > part->location.start) {
5227 node->base.location.start = part->location.start;
5229 if (node->base.location.end < part->location.end) {
5230 node->base.location.end = part->location.end;
5233 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5237pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_interpolated_regular_expression_node_t *node, const pm_token_t *closing) {
5238 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
5239 node->base.location.end = closing->end;
5240 pm_node_flag_set((pm_node_t *) node, pm_regular_expression_flags_create(parser, closing));
5267pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_node_t *part) {
5268#define CLEAR_FLAGS(node) \
5269 node->base.flags = (pm_node_flags_t) (node->base.flags & ~(PM_NODE_FLAG_STATIC_LITERAL | PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE))
5271#define MUTABLE_FLAGS(node) \
5272 node->base.flags = (pm_node_flags_t) ((node->base.flags | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE) & ~PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN);
5274 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
5275 node->base.location.start = part->location.start;
5278 node->base.location.end = MAX(node->base.location.end, part->location.end);
5280 switch (PM_NODE_TYPE(part)) {
5281 case PM_STRING_NODE:
5282 part->flags = (pm_node_flags_t) ((part->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5284 case PM_INTERPOLATED_STRING_NODE:
5285 if (PM_NODE_FLAG_P(part, PM_NODE_FLAG_STATIC_LITERAL)) {
5286 // If the string that we're concatenating is a static literal,
5287 // then we can keep the static literal flag for this string.
5289 // Otherwise, we lose the static literal flag here and we should
5290 // also clear the mutability flags.
5294 case PM_EMBEDDED_STATEMENTS_NODE: {
5295 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5296 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5298 if (embedded == NULL) {
5299 // If we're embedding multiple statements or no statements, then
5300 // the string is not longer a static literal.
5302 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5303 // If the embedded statement is a string, then we can make that
5304 // string as frozen and static literal, and not touch the static
5305 // literal status of this string.
5306 embedded->flags = (pm_node_flags_t) ((embedded->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5308 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5309 MUTABLE_FLAGS(node);
5311 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5312 // If the embedded statement is an interpolated string, but that
5313 // string is marked as static literal, then we can keep our
5314 // static literal status for this string.
5315 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5316 MUTABLE_FLAGS(node);
5319 // In all other cases, we lose the static literal flag here and
5326 case PM_EMBEDDED_VARIABLE_NODE:
5327 // Embedded variables clear static literal, which means we also
5328 // should clear the mutability flags.
5331 case PM_X_STRING_NODE:
5332 case PM_INTERPOLATED_X_STRING_NODE:
5333 // If this is an x string, then this is a syntax error. But we want
5334 // to handle it here so that we don't fail the assertion.
5338 assert(false && "unexpected node type");
5342 pm_node_list_append(&node->parts, part);
5351static pm_interpolated_string_node_t *
5352pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5353 pm_interpolated_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_string_node_t);
5354 pm_node_flags_t flags = PM_NODE_FLAG_STATIC_LITERAL;
5356 switch (parser->frozen_string_literal) {
5357 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
5358 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE;
5360 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
5361 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN;
5365 *node = (pm_interpolated_string_node_t) {
5367 .type = PM_INTERPOLATED_STRING_NODE,
5369 .node_id = PM_NODE_IDENTIFY(parser),
5371 .start = opening->start,
5372 .end = closing->end,
5375 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5376 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5380 if (parts != NULL) {
5382 PM_NODE_LIST_FOREACH(parts, index, part) {
5383 pm_interpolated_string_node_append(node, part);
5394pm_interpolated_string_node_closing_set(pm_interpolated_string_node_t *node, const pm_token_t *closing) {
5395 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5396 node->base.location.end = closing->end;
5400pm_interpolated_symbol_node_append(pm_interpolated_symbol_node_t *node, pm_node_t *part) {
5401 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
5402 node->base.location.start = part->location.start;
5405 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5406 node->base.location.end = MAX(node->base.location.end, part->location.end);
5410pm_interpolated_symbol_node_closing_loc_set(pm_interpolated_symbol_node_t *node, const pm_token_t *closing) {
5411 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5412 node->base.location.end = closing->end;
5418static pm_interpolated_symbol_node_t *
5419pm_interpolated_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5420 pm_interpolated_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_symbol_node_t);
5422 *node = (pm_interpolated_symbol_node_t) {
5424 .type = PM_INTERPOLATED_SYMBOL_NODE,
5425 .flags = PM_NODE_FLAG_STATIC_LITERAL,
5426 .node_id = PM_NODE_IDENTIFY(parser),
5428 .start = opening->start,
5429 .end = closing->end,
5432 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5433 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5437 if (parts != NULL) {
5439 PM_NODE_LIST_FOREACH(parts, index, part) {
5440 pm_interpolated_symbol_node_append(node, part);
5450static pm_interpolated_x_string_node_t *
5451pm_interpolated_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5452 pm_interpolated_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_x_string_node_t);
5454 *node = (pm_interpolated_x_string_node_t) {
5456 .type = PM_INTERPOLATED_X_STRING_NODE,
5457 .node_id = PM_NODE_IDENTIFY(parser),
5459 .start = opening->start,
5463 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5464 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5472pm_interpolated_xstring_node_append(pm_interpolated_x_string_node_t *node, pm_node_t *part) {
5473 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5474 node->base.location.end = part->location.end;
5478pm_interpolated_xstring_node_closing_set(pm_interpolated_x_string_node_t *node, const pm_token_t *closing) {
5479 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5480 node->base.location.end = closing->end;
5486static pm_it_local_variable_read_node_t *
5487pm_it_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5488 pm_it_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_it_local_variable_read_node_t);
5490 *node = (pm_it_local_variable_read_node_t) {
5492 .type = PM_IT_LOCAL_VARIABLE_READ_NODE,
5493 .node_id = PM_NODE_IDENTIFY(parser),
5494 .location = PM_LOCATION_TOKEN_VALUE(name)
5504static pm_it_parameters_node_t *
5505pm_it_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5506 pm_it_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_it_parameters_node_t);
5508 *node = (pm_it_parameters_node_t) {
5510 .type = PM_IT_PARAMETERS_NODE,
5511 .node_id = PM_NODE_IDENTIFY(parser),
5513 .start = opening->start,
5525static pm_keyword_hash_node_t *
5526pm_keyword_hash_node_create(pm_parser_t *parser) {
5527 pm_keyword_hash_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_hash_node_t);
5529 *node = (pm_keyword_hash_node_t) {
5531 .type = PM_KEYWORD_HASH_NODE,
5532 .flags = PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS,
5533 .node_id = PM_NODE_IDENTIFY(parser),
5534 .location = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
5546pm_keyword_hash_node_elements_append(pm_keyword_hash_node_t *hash, pm_node_t *element) {
5547 // If the element being added is not an AssocNode or does not have a symbol
5548 // key, then we want to turn the SYMBOL_KEYS flag off.
5549 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE) || !PM_NODE_TYPE_P(((pm_assoc_node_t *) element)->key, PM_SYMBOL_NODE)) {
5550 pm_node_flag_unset((pm_node_t *)hash, PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS);
5553 pm_node_list_append(&hash->elements, element);
5554 if (hash->base.location.start == NULL) {
5555 hash->base.location.start = element->location.start;
5557 hash->base.location.end = element->location.end;
5563static pm_required_keyword_parameter_node_t *
5564pm_required_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name) {
5565 pm_required_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_keyword_parameter_node_t);
5567 *node = (pm_required_keyword_parameter_node_t) {
5569 .type = PM_REQUIRED_KEYWORD_PARAMETER_NODE,
5570 .node_id = PM_NODE_IDENTIFY(parser),
5572 .start = name->start,
5576 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5577 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5586static pm_optional_keyword_parameter_node_t *
5587pm_optional_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, pm_node_t *value) {
5588 pm_optional_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_keyword_parameter_node_t);
5590 *node = (pm_optional_keyword_parameter_node_t) {
5592 .type = PM_OPTIONAL_KEYWORD_PARAMETER_NODE,
5593 .node_id = PM_NODE_IDENTIFY(parser),
5595 .start = name->start,
5596 .end = value->location.end
5599 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5600 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5610static pm_keyword_rest_parameter_node_t *
5611pm_keyword_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
5612 pm_keyword_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_rest_parameter_node_t);
5614 *node = (pm_keyword_rest_parameter_node_t) {
5616 .type = PM_KEYWORD_REST_PARAMETER_NODE,
5617 .node_id = PM_NODE_IDENTIFY(parser),
5619 .start = operator->start,
5620 .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
5623 .name = pm_parser_optional_constant_id_token(parser, name),
5624 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
5625 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5634static pm_lambda_node_t *
5635pm_lambda_node_create(
5636 pm_parser_t *parser,
5637 pm_constant_id_list_t *locals,
5638 const pm_token_t *operator,
5639 const pm_token_t *opening,
5640 const pm_token_t *closing,
5641 pm_node_t *parameters,
5644 pm_lambda_node_t *node = PM_NODE_ALLOC(parser, pm_lambda_node_t);
5646 *node = (pm_lambda_node_t) {
5648 .type = PM_LAMBDA_NODE,
5649 .node_id = PM_NODE_IDENTIFY(parser),
5651 .start = operator->start,
5656 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5657 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5658 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
5659 .parameters = parameters,
5669static pm_local_variable_and_write_node_t *
5670pm_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) {
5671 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));
5672 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5673 pm_local_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_and_write_node_t);
5675 *node = (pm_local_variable_and_write_node_t) {
5677 .type = PM_LOCAL_VARIABLE_AND_WRITE_NODE,
5678 .node_id = PM_NODE_IDENTIFY(parser),
5680 .start = target->location.start,
5681 .end = value->location.end
5684 .name_loc = target->location,
5685 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5697static pm_local_variable_operator_write_node_t *
5698pm_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) {
5699 pm_local_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_operator_write_node_t);
5701 *node = (pm_local_variable_operator_write_node_t) {
5703 .type = PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE,
5704 .node_id = PM_NODE_IDENTIFY(parser),
5706 .start = target->location.start,
5707 .end = value->location.end
5710 .name_loc = target->location,
5711 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5714 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
5724static pm_local_variable_or_write_node_t *
5725pm_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) {
5726 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));
5727 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5728 pm_local_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_or_write_node_t);
5730 *node = (pm_local_variable_or_write_node_t) {
5732 .type = PM_LOCAL_VARIABLE_OR_WRITE_NODE,
5733 .node_id = PM_NODE_IDENTIFY(parser),
5735 .start = target->location.start,
5736 .end = value->location.end
5739 .name_loc = target->location,
5740 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5752static pm_local_variable_read_node_t *
5753pm_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) {
5754 if (!missing) pm_locals_read(&pm_parser_scope_find(parser, depth)->locals, name_id);
5756 pm_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_read_node_t);
5758 *node = (pm_local_variable_read_node_t) {
5760 .type = PM_LOCAL_VARIABLE_READ_NODE,
5761 .node_id = PM_NODE_IDENTIFY(parser),
5762 .location = PM_LOCATION_TOKEN_VALUE(name)
5774static pm_local_variable_read_node_t *
5775pm_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5776 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5777 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, false);
5784static pm_local_variable_read_node_t *
5785pm_local_variable_read_node_missing_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5786 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5787 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, true);
5793static pm_local_variable_write_node_t *
5794pm_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) {
5795 pm_local_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_write_node_t);
5797 *node = (pm_local_variable_write_node_t) {
5799 .type = PM_LOCAL_VARIABLE_WRITE_NODE,
5800 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5801 .node_id = PM_NODE_IDENTIFY(parser),
5803 .start = name_loc->start,
5804 .end = value->location.end
5810 .name_loc = *name_loc,
5811 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator)
5821pm_token_is_it(const uint8_t *start, const uint8_t *end) {
5822 return (end - start == 2) && (start[0] == 'i') && (start[1] == 't');
5830pm_token_is_numbered_parameter(const uint8_t *start, const uint8_t *end) {
5831 return (end - start == 2) && (start[0] == '_') && (start[1] != '0') && (pm_char_is_decimal_digit(start[1]));
5839pm_refute_numbered_parameter(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
5840 if (pm_token_is_numbered_parameter(start, end)) {
5841 PM_PARSER_ERR_FORMAT(parser, start, end, PM_ERR_PARAMETER_NUMBERED_RESERVED, start);
5849static pm_local_variable_target_node_t *
5850pm_local_variable_target_node_create(pm_parser_t *parser, const pm_location_t *location, pm_constant_id_t name, uint32_t depth) {
5851 pm_refute_numbered_parameter(parser, location->start, location->end);
5852 pm_local_variable_target_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_target_node_t);
5854 *node = (pm_local_variable_target_node_t) {
5856 .type = PM_LOCAL_VARIABLE_TARGET_NODE,
5857 .node_id = PM_NODE_IDENTIFY(parser),
5858 .location = *location
5870static pm_match_predicate_node_t *
5871pm_match_predicate_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5872 pm_assert_value_expression(parser, value);
5874 pm_match_predicate_node_t *node = PM_NODE_ALLOC(parser, pm_match_predicate_node_t);
5876 *node = (pm_match_predicate_node_t) {
5878 .type = PM_MATCH_PREDICATE_NODE,
5879 .node_id = PM_NODE_IDENTIFY(parser),
5881 .start = value->location.start,
5882 .end = pattern->location.end
5887 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5896static pm_match_required_node_t *
5897pm_match_required_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5898 pm_assert_value_expression(parser, value);
5900 pm_match_required_node_t *node = PM_NODE_ALLOC(parser, pm_match_required_node_t);
5902 *node = (pm_match_required_node_t) {
5904 .type = PM_MATCH_REQUIRED_NODE,
5905 .node_id = PM_NODE_IDENTIFY(parser),
5907 .start = value->location.start,
5908 .end = pattern->location.end
5913 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5922static pm_match_write_node_t *
5923pm_match_write_node_create(pm_parser_t *parser, pm_call_node_t *call) {
5924 pm_match_write_node_t *node = PM_NODE_ALLOC(parser, pm_match_write_node_t);
5926 *node = (pm_match_write_node_t) {
5928 .type = PM_MATCH_WRITE_NODE,
5929 .node_id = PM_NODE_IDENTIFY(parser),
5930 .location = call->base.location
5942static pm_module_node_t *
5943pm_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) {
5944 pm_module_node_t *node = PM_NODE_ALLOC(parser, pm_module_node_t);
5946 *node = (pm_module_node_t) {
5948 .type = PM_MODULE_NODE,
5949 .node_id = PM_NODE_IDENTIFY(parser),
5951 .start = module_keyword->start,
5952 .end = end_keyword->end
5955 .locals = (locals == NULL ? ((pm_constant_id_list_t) { .ids = NULL, .size = 0, .capacity = 0 }) : *locals),
5956 .module_keyword_loc = PM_LOCATION_TOKEN_VALUE(module_keyword),
5957 .constant_path = constant_path,
5959 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
5960 .name = pm_parser_constant_id_token(parser, name)
5969static pm_multi_target_node_t *
5970pm_multi_target_node_create(pm_parser_t *parser) {
5971 pm_multi_target_node_t *node = PM_NODE_ALLOC(parser, pm_multi_target_node_t);
5973 *node = (pm_multi_target_node_t) {
5975 .type = PM_MULTI_TARGET_NODE,
5976 .node_id = PM_NODE_IDENTIFY(parser),
5977 .location = { .start = NULL, .end = NULL }
5982 .lparen_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
5983 .rparen_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
5993pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t *node, pm_node_t *target) {
5994 if (PM_NODE_TYPE_P(target, PM_SPLAT_NODE)) {
5995 if (node->rest == NULL) {
5996 node->rest = target;
5998 pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
5999 pm_node_list_append(&node->rights, target);
6001 } else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
6002 if (node->rest == NULL) {
6003 node->rest = target;
6005 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
6006 pm_node_list_append(&node->rights, target);
6008 } else if (node->rest == NULL) {
6009 pm_node_list_append(&node->lefts, target);
6011 pm_node_list_append(&node->rights, target);
6014 if (node->base.location.start == NULL || (node->base.location.start > target->location.start)) {
6015 node->base.location.start = target->location.start;
6018 if (node->base.location.end == NULL || (node->base.location.end < target->location.end)) {
6019 node->base.location.end = target->location.end;
6027pm_multi_target_node_opening_set(pm_multi_target_node_t *node, const pm_token_t *lparen) {
6028 node->base.location.start = lparen->start;
6029 node->lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen);
6036pm_multi_target_node_closing_set(pm_multi_target_node_t *node, const pm_token_t *rparen) {
6037 node->base.location.end = rparen->end;
6038 node->rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen);
6044static pm_multi_write_node_t *
6045pm_multi_write_node_create(pm_parser_t *parser, pm_multi_target_node_t *target, const pm_token_t *operator, pm_node_t *value) {
6046 pm_multi_write_node_t *node = PM_NODE_ALLOC(parser, pm_multi_write_node_t);
6048 *node = (pm_multi_write_node_t) {
6050 .type = PM_MULTI_WRITE_NODE,
6051 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
6052 .node_id = PM_NODE_IDENTIFY(parser),
6054 .start = target->base.location.start,
6055 .end = value->location.end
6058 .lefts = target->lefts,
6059 .rest = target->rest,
6060 .rights = target->rights,
6061 .lparen_loc = target->lparen_loc,
6062 .rparen_loc = target->rparen_loc,
6063 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6067 // Explicitly do not call pm_node_destroy here because we want to keep
6068 // around all of the information within the MultiWriteNode node.
6077static pm_next_node_t *
6078pm_next_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6079 assert(keyword->type == PM_TOKEN_KEYWORD_NEXT);
6080 pm_next_node_t *node = PM_NODE_ALLOC(parser, pm_next_node_t);
6082 *node = (pm_next_node_t) {
6084 .type = PM_NEXT_NODE,
6085 .node_id = PM_NODE_IDENTIFY(parser),
6087 .start = keyword->start,
6088 .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
6091 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6092 .arguments = arguments
6101static pm_nil_node_t *
6102pm_nil_node_create(pm_parser_t *parser, const pm_token_t *token) {
6103 assert(token->type == PM_TOKEN_KEYWORD_NIL);
6104 pm_nil_node_t *node = PM_NODE_ALLOC(parser, pm_nil_node_t);
6106 *node = (pm_nil_node_t) {{
6107 .type = PM_NIL_NODE,
6108 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6109 .node_id = PM_NODE_IDENTIFY(parser),
6110 .location = PM_LOCATION_TOKEN_VALUE(token)
6119static pm_no_keywords_parameter_node_t *
6120pm_no_keywords_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
6121 assert(operator->type == PM_TOKEN_USTAR_STAR || operator->type == PM_TOKEN_STAR_STAR);
6122 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
6123 pm_no_keywords_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_no_keywords_parameter_node_t);
6125 *node = (pm_no_keywords_parameter_node_t) {
6127 .type = PM_NO_KEYWORDS_PARAMETER_NODE,
6128 .node_id = PM_NODE_IDENTIFY(parser),
6130 .start = operator->start,
6134 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6135 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
6144static pm_numbered_parameters_node_t *
6145pm_numbered_parameters_node_create(pm_parser_t *parser, const pm_location_t *location, uint8_t maximum) {
6146 pm_numbered_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_parameters_node_t);
6148 *node = (pm_numbered_parameters_node_t) {
6150 .type = PM_NUMBERED_PARAMETERS_NODE,
6151 .node_id = PM_NODE_IDENTIFY(parser),
6152 .location = *location
6164#define NTH_REF_MAX ((uint32_t) (INT_MAX >> 1))
6173pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *token) {
6174 const uint8_t *start = token->start + 1;
6175 const uint8_t *end = token->end;
6177 ptrdiff_t diff = end - start;
6179#if PTRDIFF_MAX > SIZE_MAX
6180 assert(diff < (ptrdiff_t) SIZE_MAX);
6182 size_t length = (size_t) diff;
6184 char *digits = xcalloc(length + 1, sizeof(char));
6185 memcpy(digits, start, length);
6186 digits[length] = '\0';
6190 unsigned long value = strtoul(digits, &endptr, 10);
6192 if ((digits == endptr) || (*endptr != '\0')) {
6193 pm_parser_err(parser, start, end, PM_ERR_INVALID_NUMBER_DECIMAL);
6199 if ((errno == ERANGE) || (value > NTH_REF_MAX)) {
6200 PM_PARSER_WARN_FORMAT(parser, start, end, PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start);
6204 return (uint32_t) value;
6212static pm_numbered_reference_read_node_t *
6213pm_numbered_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
6214 assert(name->type == PM_TOKEN_NUMBERED_REFERENCE);
6215 pm_numbered_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_reference_read_node_t);
6217 *node = (pm_numbered_reference_read_node_t) {
6219 .type = PM_NUMBERED_REFERENCE_READ_NODE,
6220 .node_id = PM_NODE_IDENTIFY(parser),
6221 .location = PM_LOCATION_TOKEN_VALUE(name),
6223 .number = pm_numbered_reference_read_node_number(parser, name)
6232static pm_optional_parameter_node_t *
6233pm_optional_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator, pm_node_t *value) {
6234 pm_optional_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_parameter_node_t);
6236 *node = (pm_optional_parameter_node_t) {
6238 .type = PM_OPTIONAL_PARAMETER_NODE,
6239 .node_id = PM_NODE_IDENTIFY(parser),
6241 .start = name->start,
6242 .end = value->location.end
6245 .name = pm_parser_constant_id_token(parser, name),
6246 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
6247 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6257static pm_or_node_t *
6258pm_or_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
6259 pm_assert_value_expression(parser, left);
6261 pm_or_node_t *node = PM_NODE_ALLOC(parser, pm_or_node_t);
6263 *node = (pm_or_node_t) {
6266 .node_id = PM_NODE_IDENTIFY(parser),
6268 .start = left->location.start,
6269 .end = right->location.end
6274 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6283static pm_parameters_node_t *
6284pm_parameters_node_create(pm_parser_t *parser) {
6285 pm_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_parameters_node_t);
6287 *node = (pm_parameters_node_t) {
6289 .type = PM_PARAMETERS_NODE,
6290 .node_id = PM_NODE_IDENTIFY(parser),
6291 .location = PM_LOCATION_TOKEN_VALUE(&parser->current)
6294 .keyword_rest = NULL,
6309pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param) {
6310 if (params->base.location.start == NULL) {
6311 params->base.location.start = param->location.start;
6313 params->base.location.start = params->base.location.start < param->location.start ? params->base.location.start : param->location.start;
6316 if (params->base.location.end == NULL) {
6317 params->base.location.end = param->location.end;
6319 params->base.location.end = params->base.location.end > param->location.end ? params->base.location.end : param->location.end;
6327pm_parameters_node_requireds_append(pm_parameters_node_t *params, pm_node_t *param) {
6328 pm_parameters_node_location_set(params, param);
6329 pm_node_list_append(¶ms->requireds, param);
6336pm_parameters_node_optionals_append(pm_parameters_node_t *params, pm_optional_parameter_node_t *param) {
6337 pm_parameters_node_location_set(params, (pm_node_t *) param);
6338 pm_node_list_append(¶ms->optionals, (pm_node_t *) param);
6345pm_parameters_node_posts_append(pm_parameters_node_t *params, pm_node_t *param) {
6346 pm_parameters_node_location_set(params, param);
6347 pm_node_list_append(¶ms->posts, param);
6354pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6355 pm_parameters_node_location_set(params, param);
6356 params->rest = param;
6363pm_parameters_node_keywords_append(pm_parameters_node_t *params, pm_node_t *param) {
6364 pm_parameters_node_location_set(params, param);
6365 pm_node_list_append(¶ms->keywords, param);
6372pm_parameters_node_keyword_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6373 assert(params->keyword_rest == NULL);
6374 pm_parameters_node_location_set(params, param);
6375 params->keyword_rest = param;
6382pm_parameters_node_block_set(pm_parameters_node_t *params, pm_block_parameter_node_t *param) {
6383 assert(params->block == NULL);
6384 pm_parameters_node_location_set(params, (pm_node_t *) param);
6385 params->block = param;
6391static pm_program_node_t *
6392pm_program_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, pm_statements_node_t *statements) {
6393 pm_program_node_t *node = PM_NODE_ALLOC(parser, pm_program_node_t);
6395 *node = (pm_program_node_t) {
6397 .type = PM_PROGRAM_NODE,
6398 .node_id = PM_NODE_IDENTIFY(parser),
6400 .start = statements == NULL ? parser->start : statements->base.location.start,
6401 .end = statements == NULL ? parser->end : statements->base.location.end
6405 .statements = statements
6414static pm_parentheses_node_t *
6415pm_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) {
6416 pm_parentheses_node_t *node = PM_NODE_ALLOC(parser, pm_parentheses_node_t);
6418 *node = (pm_parentheses_node_t) {
6420 .type = PM_PARENTHESES_NODE,
6422 .node_id = PM_NODE_IDENTIFY(parser),
6424 .start = opening->start,
6429 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6430 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6439static pm_pinned_expression_node_t *
6440pm_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) {
6441 pm_pinned_expression_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_expression_node_t);
6443 *node = (pm_pinned_expression_node_t) {
6445 .type = PM_PINNED_EXPRESSION_NODE,
6446 .node_id = PM_NODE_IDENTIFY(parser),
6448 .start = operator->start,
6452 .expression = expression,
6453 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6454 .lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen),
6455 .rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen)
6464static pm_pinned_variable_node_t *
6465pm_pinned_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
6466 pm_pinned_variable_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_variable_node_t);
6468 *node = (pm_pinned_variable_node_t) {
6470 .type = PM_PINNED_VARIABLE_NODE,
6471 .node_id = PM_NODE_IDENTIFY(parser),
6473 .start = operator->start,
6474 .end = variable->location.end
6477 .variable = variable,
6478 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6487static pm_post_execution_node_t *
6488pm_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) {
6489 pm_post_execution_node_t *node = PM_NODE_ALLOC(parser, pm_post_execution_node_t);
6491 *node = (pm_post_execution_node_t) {
6493 .type = PM_POST_EXECUTION_NODE,
6494 .node_id = PM_NODE_IDENTIFY(parser),
6496 .start = keyword->start,
6500 .statements = statements,
6501 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6502 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6503 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6512static pm_pre_execution_node_t *
6513pm_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) {
6514 pm_pre_execution_node_t *node = PM_NODE_ALLOC(parser, pm_pre_execution_node_t);
6516 *node = (pm_pre_execution_node_t) {
6518 .type = PM_PRE_EXECUTION_NODE,
6519 .node_id = PM_NODE_IDENTIFY(parser),
6521 .start = keyword->start,
6525 .statements = statements,
6526 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6527 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6528 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6537static pm_range_node_t *
6538pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
6539 pm_assert_value_expression(parser, left);
6540 pm_assert_value_expression(parser, right);
6542 pm_range_node_t *node = PM_NODE_ALLOC(parser, pm_range_node_t);
6543 pm_node_flags_t flags = 0;
6545 // Indicate that this node is an exclusive range if the operator is `...`.
6546 if (operator->type == PM_TOKEN_DOT_DOT_DOT || operator->type == PM_TOKEN_UDOT_DOT_DOT) {
6547 flags |= PM_RANGE_FLAGS_EXCLUDE_END;
6550 // Indicate that this node is a static literal (i.e., can be compiled with
6551 // a putobject in CRuby) if the left and right are implicit nil, explicit
6552 // nil, or integers.
6554 (left == NULL || PM_NODE_TYPE_P(left, PM_NIL_NODE) || PM_NODE_TYPE_P(left, PM_INTEGER_NODE)) &&
6555 (right == NULL || PM_NODE_TYPE_P(right, PM_NIL_NODE) || PM_NODE_TYPE_P(right, PM_INTEGER_NODE))
6557 flags |= PM_NODE_FLAG_STATIC_LITERAL;
6560 *node = (pm_range_node_t) {
6562 .type = PM_RANGE_NODE,
6564 .node_id = PM_NODE_IDENTIFY(parser),
6566 .start = (left == NULL ? operator->start : left->location.start),
6567 .end = (right == NULL ? operator->end : right->location.end)
6572 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6581static pm_redo_node_t *
6582pm_redo_node_create(pm_parser_t *parser, const pm_token_t *token) {
6583 assert(token->type == PM_TOKEN_KEYWORD_REDO);
6584 pm_redo_node_t *node = PM_NODE_ALLOC(parser, pm_redo_node_t);
6586 *node = (pm_redo_node_t) {{
6587 .type = PM_REDO_NODE,
6588 .node_id = PM_NODE_IDENTIFY(parser),
6589 .location = PM_LOCATION_TOKEN_VALUE(token)
6599static pm_regular_expression_node_t *
6600pm_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) {
6601 pm_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_regular_expression_node_t);
6603 *node = (pm_regular_expression_node_t) {
6605 .type = PM_REGULAR_EXPRESSION_NODE,
6606 .flags = pm_regular_expression_flags_create(parser, closing) | PM_NODE_FLAG_STATIC_LITERAL,
6607 .node_id = PM_NODE_IDENTIFY(parser),
6609 .start = MIN(opening->start, closing->start),
6610 .end = MAX(opening->end, closing->end)
6613 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6614 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
6615 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
6616 .unescaped = *unescaped
6625static inline pm_regular_expression_node_t *
6626pm_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6627 return pm_regular_expression_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6633static pm_required_parameter_node_t *
6634pm_required_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
6635 pm_required_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_parameter_node_t);
6637 *node = (pm_required_parameter_node_t) {
6639 .type = PM_REQUIRED_PARAMETER_NODE,
6640 .node_id = PM_NODE_IDENTIFY(parser),
6641 .location = PM_LOCATION_TOKEN_VALUE(token)
6643 .name = pm_parser_constant_id_token(parser, token)
6652static pm_rescue_modifier_node_t *
6653pm_rescue_modifier_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *keyword, pm_node_t *rescue_expression) {
6654 pm_rescue_modifier_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_modifier_node_t);
6656 *node = (pm_rescue_modifier_node_t) {
6658 .type = PM_RESCUE_MODIFIER_NODE,
6659 .node_id = PM_NODE_IDENTIFY(parser),
6661 .start = expression->location.start,
6662 .end = rescue_expression->location.end
6665 .expression = expression,
6666 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6667 .rescue_expression = rescue_expression
6676static pm_rescue_node_t *
6677pm_rescue_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
6678 pm_rescue_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_node_t);
6680 *node = (pm_rescue_node_t) {
6682 .type = PM_RESCUE_NODE,
6683 .node_id = PM_NODE_IDENTIFY(parser),
6684 .location = PM_LOCATION_TOKEN_VALUE(keyword)
6686 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6687 .operator_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
6688 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
6699pm_rescue_node_operator_set(pm_rescue_node_t *node, const pm_token_t *operator) {
6700 node->operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
6707pm_rescue_node_reference_set(pm_rescue_node_t *node, pm_node_t *reference) {
6708 node->reference = reference;
6709 node->base.location.end = reference->location.end;
6716pm_rescue_node_statements_set(pm_rescue_node_t *node, pm_statements_node_t *statements) {
6717 node->statements = statements;
6718 if (pm_statements_node_body_length(statements) > 0) {
6719 node->base.location.end = statements->base.location.end;
6727pm_rescue_node_subsequent_set(pm_rescue_node_t *node, pm_rescue_node_t *subsequent) {
6728 node->subsequent = subsequent;
6729 node->base.location.end = subsequent->base.location.end;
6736pm_rescue_node_exceptions_append(pm_rescue_node_t *node, pm_node_t *exception) {
6737 pm_node_list_append(&node->exceptions, exception);
6738 node->base.location.end = exception->location.end;
6744static pm_rest_parameter_node_t *
6745pm_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
6746 pm_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_rest_parameter_node_t);
6748 *node = (pm_rest_parameter_node_t) {
6750 .type = PM_REST_PARAMETER_NODE,
6751 .node_id = PM_NODE_IDENTIFY(parser),
6753 .start = operator->start,
6754 .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
6757 .name = pm_parser_optional_constant_id_token(parser, name),
6758 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
6759 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6768static pm_retry_node_t *
6769pm_retry_node_create(pm_parser_t *parser, const pm_token_t *token) {
6770 assert(token->type == PM_TOKEN_KEYWORD_RETRY);
6771 pm_retry_node_t *node = PM_NODE_ALLOC(parser, pm_retry_node_t);
6773 *node = (pm_retry_node_t) {{
6774 .type = PM_RETRY_NODE,
6775 .node_id = PM_NODE_IDENTIFY(parser),
6776 .location = PM_LOCATION_TOKEN_VALUE(token)
6785static pm_return_node_t *
6786pm_return_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6787 pm_return_node_t *node = PM_NODE_ALLOC(parser, pm_return_node_t);
6789 *node = (pm_return_node_t) {
6791 .type = PM_RETURN_NODE,
6792 .node_id = PM_NODE_IDENTIFY(parser),
6794 .start = keyword->start,
6795 .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
6798 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6799 .arguments = arguments
6808static pm_self_node_t *
6809pm_self_node_create(pm_parser_t *parser, const pm_token_t *token) {
6810 assert(token->type == PM_TOKEN_KEYWORD_SELF);
6811 pm_self_node_t *node = PM_NODE_ALLOC(parser, pm_self_node_t);
6813 *node = (pm_self_node_t) {{
6814 .type = PM_SELF_NODE,
6815 .node_id = PM_NODE_IDENTIFY(parser),
6816 .location = PM_LOCATION_TOKEN_VALUE(token)
6825static pm_shareable_constant_node_t *
6826pm_shareable_constant_node_create(pm_parser_t *parser, pm_node_t *write, pm_shareable_constant_value_t value) {
6827 pm_shareable_constant_node_t *node = PM_NODE_ALLOC(parser, pm_shareable_constant_node_t);
6829 *node = (pm_shareable_constant_node_t) {
6831 .type = PM_SHAREABLE_CONSTANT_NODE,
6832 .flags = (pm_node_flags_t) value,
6833 .node_id = PM_NODE_IDENTIFY(parser),
6834 .location = PM_LOCATION_NODE_VALUE(write)
6845static pm_singleton_class_node_t *
6846pm_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) {
6847 pm_singleton_class_node_t *node = PM_NODE_ALLOC(parser, pm_singleton_class_node_t);
6849 *node = (pm_singleton_class_node_t) {
6851 .type = PM_SINGLETON_CLASS_NODE,
6852 .node_id = PM_NODE_IDENTIFY(parser),
6854 .start = class_keyword->start,
6855 .end = end_keyword->end
6859 .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
6860 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6861 .expression = expression,
6863 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
6872static pm_source_encoding_node_t *
6873pm_source_encoding_node_create(pm_parser_t *parser, const pm_token_t *token) {
6874 assert(token->type == PM_TOKEN_KEYWORD___ENCODING__);
6875 pm_source_encoding_node_t *node = PM_NODE_ALLOC(parser, pm_source_encoding_node_t);
6877 *node = (pm_source_encoding_node_t) {{
6878 .type = PM_SOURCE_ENCODING_NODE,
6879 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6880 .node_id = PM_NODE_IDENTIFY(parser),
6881 .location = PM_LOCATION_TOKEN_VALUE(token)
6890static pm_source_file_node_t*
6891pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword) {
6892 pm_source_file_node_t *node = PM_NODE_ALLOC(parser, pm_source_file_node_t);
6893 assert(file_keyword->type == PM_TOKEN_KEYWORD___FILE__);
6895 pm_node_flags_t flags = 0;
6897 switch (parser->frozen_string_literal) {
6898 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6899 flags |= PM_STRING_FLAGS_MUTABLE;
6901 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6902 flags |= PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6906 *node = (pm_source_file_node_t) {
6908 .type = PM_SOURCE_FILE_NODE,
6910 .node_id = PM_NODE_IDENTIFY(parser),
6911 .location = PM_LOCATION_TOKEN_VALUE(file_keyword),
6913 .filepath = parser->filepath
6922static pm_source_line_node_t *
6923pm_source_line_node_create(pm_parser_t *parser, const pm_token_t *token) {
6924 assert(token->type == PM_TOKEN_KEYWORD___LINE__);
6925 pm_source_line_node_t *node = PM_NODE_ALLOC(parser, pm_source_line_node_t);
6927 *node = (pm_source_line_node_t) {{
6928 .type = PM_SOURCE_LINE_NODE,
6929 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6930 .node_id = PM_NODE_IDENTIFY(parser),
6931 .location = PM_LOCATION_TOKEN_VALUE(token)
6940static pm_splat_node_t *
6941pm_splat_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
6942 pm_splat_node_t *node = PM_NODE_ALLOC(parser, pm_splat_node_t);
6944 *node = (pm_splat_node_t) {
6946 .type = PM_SPLAT_NODE,
6947 .node_id = PM_NODE_IDENTIFY(parser),
6949 .start = operator->start,
6950 .end = (expression == NULL ? operator->end : expression->location.end)
6953 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6954 .expression = expression
6963static pm_statements_node_t *
6964pm_statements_node_create(pm_parser_t *parser) {
6965 pm_statements_node_t *node = PM_NODE_ALLOC(parser, pm_statements_node_t);
6967 *node = (pm_statements_node_t) {
6969 .type = PM_STATEMENTS_NODE,
6970 .node_id = PM_NODE_IDENTIFY(parser),
6971 .location = PM_LOCATION_NULL_VALUE(parser)
6983pm_statements_node_body_length(pm_statements_node_t *node) {
6984 return node && node->body.size;
6991pm_statements_node_location_set(pm_statements_node_t *node, const uint8_t *start, const uint8_t *end) {
6992 node->base.location = (pm_location_t) { .start = start, .end = end };
7000pm_statements_node_body_update(pm_statements_node_t *node, pm_node_t *statement) {
7001 if (pm_statements_node_body_length(node) == 0 || statement->location.start < node->base.location.start) {
7002 node->base.location.start = statement->location.start;
7005 if (statement->location.end > node->base.location.end) {
7006 node->base.location.end = statement->location.end;
7014pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline) {
7015 pm_statements_node_body_update(node, statement);
7017 if (node->body.size > 0) {
7018 const pm_node_t *previous = node->body.nodes[node->body.size - 1];
7020 switch (PM_NODE_TYPE(previous)) {
7025 case PM_RETURN_NODE:
7026 pm_parser_warn_node(parser, statement, PM_WARN_UNREACHABLE_STATEMENT);
7033 pm_node_list_append(&node->body, statement);
7034 if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
7041pm_statements_node_body_prepend(pm_statements_node_t *node, pm_node_t *statement) {
7042 pm_statements_node_body_update(node, statement);
7043 pm_node_list_prepend(&node->body, statement);
7044 pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
7050static inline pm_string_node_t *
7051pm_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) {
7052 pm_string_node_t *node = PM_NODE_ALLOC(parser, pm_string_node_t);
7053 pm_node_flags_t flags = 0;
7055 switch (parser->frozen_string_literal) {
7056 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
7057 flags = PM_STRING_FLAGS_MUTABLE;
7059 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
7060 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
7064 *node = (pm_string_node_t) {
7066 .type = PM_STRING_NODE,
7068 .node_id = PM_NODE_IDENTIFY(parser),
7070 .start = (opening->type == PM_TOKEN_NOT_PROVIDED ? content->start : opening->start),
7071 .end = (closing->type == PM_TOKEN_NOT_PROVIDED ? content->end : closing->end)
7074 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7075 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
7076 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7077 .unescaped = *string
7086static pm_string_node_t *
7087pm_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7088 return pm_string_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7095static pm_string_node_t *
7096pm_string_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7097 pm_string_node_t *node = pm_string_node_create_unescaped(parser, opening, content, closing, &parser->current_string);
7098 parser->current_string = PM_STRING_EMPTY;
7105static pm_super_node_t *
7106pm_super_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_t *arguments) {
7107 assert(keyword->type == PM_TOKEN_KEYWORD_SUPER);
7108 pm_super_node_t *node = PM_NODE_ALLOC(parser, pm_super_node_t);
7110 const uint8_t *end = pm_arguments_end(arguments);
7112 assert(false && "unreachable");
7115 *node = (pm_super_node_t) {
7117 .type = PM_SUPER_NODE,
7118 .node_id = PM_NODE_IDENTIFY(parser),
7120 .start = keyword->start,
7124 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7125 .lparen_loc = arguments->opening_loc,
7126 .arguments = arguments->arguments,
7127 .rparen_loc = arguments->closing_loc,
7128 .block = arguments->block
7139pm_ascii_only_p(const pm_string_t *contents) {
7140 const size_t length = pm_string_length(contents);
7141 const uint8_t *source = pm_string_source(contents);
7143 for (size_t index = 0; index < length; index++) {
7144 if (source[index] & 0x80) return false;
7154parse_symbol_encoding_validate_utf8(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
7155 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
7156 size_t width = pm_encoding_utf_8_char_width(cursor, end - cursor);
7159 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
7172parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
7173 const pm_encoding_t *encoding = parser->encoding;
7175 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
7176 size_t width = encoding->char_width(cursor, end - cursor);
7179 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
7196static inline pm_node_flags_t
7197parse_symbol_encoding(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents, bool validate) {
7198 if (parser->explicit_encoding != NULL) {
7199 // A Symbol may optionally have its encoding explicitly set. This will
7200 // happen if an escape sequence results in a non-ASCII code point.
7201 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7202 if (validate) parse_symbol_encoding_validate_utf8(parser, location, contents);
7203 return PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING;
7204 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7205 return PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING;
7206 } else if (validate) {
7207 parse_symbol_encoding_validate_other(parser, location, contents);
7209 } else if (pm_ascii_only_p(contents)) {
7210 // Ruby stipulates that all source files must use an ASCII-compatible
7211 // encoding. Thus, all symbols appearing in source are eligible for
7212 // "downgrading" to US-ASCII.
7213 return PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING;
7214 } else if (validate) {
7215 parse_symbol_encoding_validate_other(parser, location, contents);
7221static pm_node_flags_t
7222parse_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) {
7223 assert ((modifier == 'n' && modifier_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) ||
7224 (modifier == 'u' && modifier_encoding == PM_ENCODING_UTF_8_ENTRY) ||
7225 (modifier == 'e' && modifier_encoding == PM_ENCODING_EUC_JP_ENTRY) ||
7226 (modifier == 's' && modifier_encoding == PM_ENCODING_WINDOWS_31J_ENTRY));
7228 // There's special validation logic used if a string does not contain any character escape sequences.
7229 if (parser->explicit_encoding == NULL) {
7230 // If an ASCII-only string without character escapes is used with an encoding modifier, then resulting Regexp
7231 // has the modifier encoding, unless the ASCII-8BIT modifier is used, in which case the Regexp "downgrades" to
7232 // the US-ASCII encoding.
7234 return modifier == 'n' ? PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING : flags;
7237 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7239 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
7241 } else if (parser->encoding != modifier_encoding) {
7242 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_ENCODING_OPTION_MISMATCH, modifier, parser->encoding->name);
7244 if (modifier == 'n' && !ascii_only) {
7245 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));
7252 // 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.
7253 bool mixed_encoding = false;
7255 if (mixed_encoding) {
7256 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
7257 } else if (modifier != 'n' && parser->explicit_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) {
7258 // 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.
7259 bool valid_string_in_modifier_encoding = true;
7261 if (!valid_string_in_modifier_encoding) {
7262 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
7264 } else if (modifier != 'u' && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7265 // 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.
7266 if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
7267 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));
7271 // We've determined the encoding would naturally be EUC-JP and there is no need to force the encoding to anything else.
7281static pm_node_flags_t
7282parse_and_validate_regular_expression_encoding(pm_parser_t *parser, const pm_string_t *source, bool ascii_only, pm_node_flags_t flags) {
7283 // 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.
7284 bool valid_unicode_range = true;
7285 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY && !valid_unicode_range) {
7286 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));
7290 // US-ASCII strings do not admit multi-byte character literals. However, character escape sequences corresponding
7291 // to multi-byte characters are allowed.
7292 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY && parser->explicit_encoding == NULL && !ascii_only) {
7293 // CRuby will continue processing even though a SyntaxError has already been detected. It may result in the
7294 // following error message appearing twice. We do the same for compatibility.
7295 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
7306 if (flags & PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT) {
7307 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'n', PM_ENCODING_ASCII_8BIT_ENTRY);
7310 if (flags & PM_REGULAR_EXPRESSION_FLAGS_UTF_8) {
7311 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'u', PM_ENCODING_UTF_8_ENTRY);
7314 if (flags & PM_REGULAR_EXPRESSION_FLAGS_EUC_JP) {
7315 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'e', PM_ENCODING_EUC_JP_ENTRY);
7318 if (flags & PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J) {
7319 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 's', PM_ENCODING_WINDOWS_31J_ENTRY);
7322 // At this point no encoding modifiers will be present on the regular expression as they would have already
7323 // been processed. Ruby stipulates that all source files must use an ASCII-compatible encoding. Thus, all
7324 // regular expressions without an encoding modifier appearing in source are eligible for "downgrading" to US-ASCII.
7326 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING;
7329 // A Regexp may optionally have its encoding explicitly set via a character escape sequence in the source string
7330 // or by specifying a modifier.
7332 // NB: an explicitly set encoding is ignored by Ruby if the Regexp consists of only US ASCII code points.
7333 if (parser->explicit_encoding != NULL) {
7334 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7335 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING;
7336 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7337 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING;
7348static pm_symbol_node_t *
7349pm_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) {
7350 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7352 *node = (pm_symbol_node_t) {
7354 .type = PM_SYMBOL_NODE,
7355 .flags = PM_NODE_FLAG_STATIC_LITERAL | flags,
7356 .node_id = PM_NODE_IDENTIFY(parser),
7358 .start = (opening->type == PM_TOKEN_NOT_PROVIDED ? value->start : opening->start),
7359 .end = (closing->type == PM_TOKEN_NOT_PROVIDED ? value->end : closing->end)
7362 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7363 .value_loc = PM_LOCATION_TOKEN_VALUE(value),
7364 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7365 .unescaped = *unescaped
7374static inline pm_symbol_node_t *
7375pm_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
7376 return pm_symbol_node_create_unescaped(parser, opening, value, closing, &PM_STRING_EMPTY, 0);
7382static pm_symbol_node_t *
7383pm_symbol_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
7384 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));
7385 parser->current_string = PM_STRING_EMPTY;
7392static pm_symbol_node_t *
7393pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
7394 pm_symbol_node_t *node;
7396 switch (token->type) {
7397 case PM_TOKEN_LABEL: {
7398 pm_token_t opening = not_provided(parser);
7399 pm_token_t closing = { .type = PM_TOKEN_LABEL_END, .start = token->end - 1, .end = token->end };
7401 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end - 1 };
7402 node = pm_symbol_node_create(parser, &opening, &label, &closing);
7404 assert((label.end - label.start) >= 0);
7405 pm_string_shared_init(&node->unescaped, label.start, label.end);
7406 pm_node_flag_set((pm_node_t *) node, parse_symbol_encoding(parser, &label, &node->unescaped, false));
7410 case PM_TOKEN_MISSING: {
7411 pm_token_t opening = not_provided(parser);
7412 pm_token_t closing = not_provided(parser);
7414 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end };
7415 node = pm_symbol_node_create(parser, &opening, &label, &closing);
7419 assert(false && "unreachable");
7430static pm_symbol_node_t *
7431pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
7432 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7434 *node = (pm_symbol_node_t) {
7436 .type = PM_SYMBOL_NODE,
7437 .flags = PM_NODE_FLAG_STATIC_LITERAL | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING,
7438 .node_id = PM_NODE_IDENTIFY(parser),
7439 .location = PM_LOCATION_NULL_VALUE(parser)
7441 .value_loc = PM_LOCATION_NULL_VALUE(parser),
7445 pm_string_constant_init(&node->unescaped, content, strlen(content));
7453pm_symbol_node_label_p(pm_node_t *node) {
7454 const uint8_t *end = NULL;
7456 switch (PM_NODE_TYPE(node)) {
7457 case PM_SYMBOL_NODE:
7458 end = ((pm_symbol_node_t *) node)->closing_loc.end;
7460 case PM_INTERPOLATED_SYMBOL_NODE:
7461 end = ((pm_interpolated_symbol_node_t *) node)->closing_loc.end;
7467 return (end != NULL) && (end[-1] == ':');
7473static pm_symbol_node_t *
7474pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const pm_token_t *opening, const pm_token_t *closing) {
7475 pm_symbol_node_t *new_node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7477 *new_node = (pm_symbol_node_t) {
7479 .type = PM_SYMBOL_NODE,
7480 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7481 .node_id = PM_NODE_IDENTIFY(parser),
7483 .start = opening->start,
7487 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7488 .value_loc = node->content_loc,
7489 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7490 .unescaped = node->unescaped
7493 pm_token_t content = { .type = PM_TOKEN_IDENTIFIER, .start = node->content_loc.start, .end = node->content_loc.end };
7494 pm_node_flag_set((pm_node_t *) new_node, parse_symbol_encoding(parser, &content, &node->unescaped, true));
7496 // We are explicitly _not_ using pm_node_destroy here because we don't want
7497 // to trash the unescaped string. We could instead copy the string if we
7498 // know that it is owned, but we're taking the fast path for now.
7507static pm_string_node_t *
7508pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
7509 pm_string_node_t *new_node = PM_NODE_ALLOC(parser, pm_string_node_t);
7510 pm_node_flags_t flags = 0;
7512 switch (parser->frozen_string_literal) {
7513 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
7514 flags = PM_STRING_FLAGS_MUTABLE;
7516 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
7517 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
7521 *new_node = (pm_string_node_t) {
7523 .type = PM_STRING_NODE,
7525 .node_id = PM_NODE_IDENTIFY(parser),
7526 .location = node->base.location
7528 .opening_loc = node->opening_loc,
7529 .content_loc = node->value_loc,
7530 .closing_loc = node->closing_loc,
7531 .unescaped = node->unescaped
7534 // We are explicitly _not_ using pm_node_destroy here because we don't want
7535 // to trash the unescaped string. We could instead copy the string if we
7536 // know that it is owned, but we're taking the fast path for now.
7545static pm_true_node_t *
7546pm_true_node_create(pm_parser_t *parser, const pm_token_t *token) {
7547 assert(token->type == PM_TOKEN_KEYWORD_TRUE);
7548 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
7550 *node = (pm_true_node_t) {{
7551 .type = PM_TRUE_NODE,
7552 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7553 .node_id = PM_NODE_IDENTIFY(parser),
7554 .location = PM_LOCATION_TOKEN_VALUE(token)
7563static pm_true_node_t *
7564pm_true_node_synthesized_create(pm_parser_t *parser) {
7565 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
7567 *node = (pm_true_node_t) {{
7568 .type = PM_TRUE_NODE,
7569 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7570 .node_id = PM_NODE_IDENTIFY(parser),
7571 .location = { .start = parser->start, .end = parser->end }
7580static pm_undef_node_t *
7581pm_undef_node_create(pm_parser_t *parser, const pm_token_t *token) {
7582 assert(token->type == PM_TOKEN_KEYWORD_UNDEF);
7583 pm_undef_node_t *node = PM_NODE_ALLOC(parser, pm_undef_node_t);
7585 *node = (pm_undef_node_t) {
7587 .type = PM_UNDEF_NODE,
7588 .node_id = PM_NODE_IDENTIFY(parser),
7589 .location = PM_LOCATION_TOKEN_VALUE(token),
7591 .keyword_loc = PM_LOCATION_TOKEN_VALUE(token),
7602pm_undef_node_append(pm_undef_node_t *node, pm_node_t *name) {
7603 node->base.location.end = name->location.end;
7604 pm_node_list_append(&node->names, name);
7610static pm_unless_node_t *
7611pm_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) {
7612 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7613 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
7616 if (statements != NULL) {
7617 end = statements->base.location.end;
7619 end = predicate->location.end;
7622 *node = (pm_unless_node_t) {
7624 .type = PM_UNLESS_NODE,
7625 .flags = PM_NODE_FLAG_NEWLINE,
7626 .node_id = PM_NODE_IDENTIFY(parser),
7628 .start = keyword->start,
7632 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7633 .predicate = predicate,
7634 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
7635 .statements = statements,
7636 .else_clause = NULL,
7637 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
7646static pm_unless_node_t *
7647pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *unless_keyword, pm_node_t *predicate) {
7648 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7649 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
7651 pm_statements_node_t *statements = pm_statements_node_create(parser);
7652 pm_statements_node_body_append(parser, statements, statement, true);
7654 *node = (pm_unless_node_t) {
7656 .type = PM_UNLESS_NODE,
7657 .flags = PM_NODE_FLAG_NEWLINE,
7658 .node_id = PM_NODE_IDENTIFY(parser),
7660 .start = statement->location.start,
7661 .end = predicate->location.end
7664 .keyword_loc = PM_LOCATION_TOKEN_VALUE(unless_keyword),
7665 .predicate = predicate,
7666 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7667 .statements = statements,
7668 .else_clause = NULL,
7669 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
7676pm_unless_node_end_keyword_loc_set(pm_unless_node_t *node, const pm_token_t *end_keyword) {
7677 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
7678 node->base.location.end = end_keyword->end;
7687pm_loop_modifier_block_exits(pm_parser_t *parser, pm_statements_node_t *statements) {
7688 assert(parser->current_block_exits != NULL);
7690 // All of the block exits that we want to remove should be within the
7691 // statements, and since we are modifying the statements, we shouldn't have
7692 // to check the end location.
7693 const uint8_t *start = statements->base.location.start;
7695 for (size_t index = parser->current_block_exits->size; index > 0; index--) {
7696 pm_node_t *block_exit = parser->current_block_exits->nodes[index - 1];
7697 if (block_exit->location.start < start) break;
7699 // Implicitly remove from the list by lowering the size.
7700 parser->current_block_exits->size--;
7707static pm_until_node_t *
7708pm_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) {
7709 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
7710 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7712 *node = (pm_until_node_t) {
7714 .type = PM_UNTIL_NODE,
7716 .node_id = PM_NODE_IDENTIFY(parser),
7718 .start = keyword->start,
7719 .end = closing->end,
7722 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7723 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
7724 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7725 .predicate = predicate,
7726 .statements = statements
7735static pm_until_node_t *
7736pm_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) {
7737 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
7738 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7739 pm_loop_modifier_block_exits(parser, statements);
7741 *node = (pm_until_node_t) {
7743 .type = PM_UNTIL_NODE,
7745 .node_id = PM_NODE_IDENTIFY(parser),
7747 .start = statements->base.location.start,
7748 .end = predicate->location.end,
7751 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7752 .do_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7753 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7754 .predicate = predicate,
7755 .statements = statements
7764static pm_when_node_t *
7765pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
7766 pm_when_node_t *node = PM_NODE_ALLOC(parser, pm_when_node_t);
7768 *node = (pm_when_node_t) {
7770 .type = PM_WHEN_NODE,
7771 .node_id = PM_NODE_IDENTIFY(parser),
7773 .start = keyword->start,
7777 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7779 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7790pm_when_node_conditions_append(pm_when_node_t *node, pm_node_t *condition) {
7791 node->base.location.end = condition->location.end;
7792 pm_node_list_append(&node->conditions, condition);
7799pm_when_node_then_keyword_loc_set(pm_when_node_t *node, const pm_token_t *then_keyword) {
7800 node->base.location.end = then_keyword->end;
7801 node->then_keyword_loc = PM_LOCATION_TOKEN_VALUE(then_keyword);
7808pm_when_node_statements_set(pm_when_node_t *node, pm_statements_node_t *statements) {
7809 if (statements->base.location.end > node->base.location.end) {
7810 node->base.location.end = statements->base.location.end;
7813 node->statements = statements;
7819static pm_while_node_t *
7820pm_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) {
7821 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7822 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7824 *node = (pm_while_node_t) {
7826 .type = PM_WHILE_NODE,
7828 .node_id = PM_NODE_IDENTIFY(parser),
7830 .start = keyword->start,
7834 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7835 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
7836 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7837 .predicate = predicate,
7838 .statements = statements
7847static pm_while_node_t *
7848pm_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) {
7849 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7850 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7851 pm_loop_modifier_block_exits(parser, statements);
7853 *node = (pm_while_node_t) {
7855 .type = PM_WHILE_NODE,
7857 .node_id = PM_NODE_IDENTIFY(parser),
7859 .start = statements->base.location.start,
7860 .end = predicate->location.end
7863 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7864 .do_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7865 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7866 .predicate = predicate,
7867 .statements = statements
7876static pm_while_node_t *
7877pm_while_node_synthesized_create(pm_parser_t *parser, pm_node_t *predicate, pm_statements_node_t *statements) {
7878 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7880 *node = (pm_while_node_t) {
7882 .type = PM_WHILE_NODE,
7883 .node_id = PM_NODE_IDENTIFY(parser),
7884 .location = PM_LOCATION_NULL_VALUE(parser)
7886 .keyword_loc = PM_LOCATION_NULL_VALUE(parser),
7887 .do_keyword_loc = PM_LOCATION_NULL_VALUE(parser),
7888 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
7889 .predicate = predicate,
7890 .statements = statements
7900static pm_x_string_node_t *
7901pm_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) {
7902 pm_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_x_string_node_t);
7904 *node = (pm_x_string_node_t) {
7906 .type = PM_X_STRING_NODE,
7907 .flags = PM_STRING_FLAGS_FROZEN,
7908 .node_id = PM_NODE_IDENTIFY(parser),
7910 .start = opening->start,
7914 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
7915 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
7916 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
7917 .unescaped = *unescaped
7926static inline pm_x_string_node_t *
7927pm_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7928 return pm_xstring_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7934static pm_yield_node_t *
7935pm_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) {
7936 pm_yield_node_t *node = PM_NODE_ALLOC(parser, pm_yield_node_t);
7939 if (rparen_loc->start != NULL) {
7940 end = rparen_loc->end;
7941 } else if (arguments != NULL) {
7942 end = arguments->base.location.end;
7943 } else if (lparen_loc->start != NULL) {
7944 end = lparen_loc->end;
7949 *node = (pm_yield_node_t) {
7951 .type = PM_YIELD_NODE,
7952 .node_id = PM_NODE_IDENTIFY(parser),
7954 .start = keyword->start,
7958 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7959 .lparen_loc = *lparen_loc,
7960 .arguments = arguments,
7961 .rparen_loc = *rparen_loc
7968#undef PM_NODE_IDENTIFY
7975pm_parser_local_depth_constant_id(pm_parser_t *parser, pm_constant_id_t constant_id) {
7976 pm_scope_t *scope = parser->current_scope;
7979 while (scope != NULL) {
7980 if (pm_locals_find(&scope->locals, constant_id) != UINT32_MAX) return depth;
7981 if (scope->closed) break;
7983 scope = scope->previous;
7996pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
7997 return pm_parser_local_depth_constant_id(parser, pm_parser_constant_id_token(parser, token));
8004pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id, const uint8_t *start, const uint8_t *end, uint32_t reads) {
8005 pm_locals_write(&parser->current_scope->locals, constant_id, start, end, reads);
8011static pm_constant_id_t
8012pm_parser_local_add_location(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, uint32_t reads) {
8013 pm_constant_id_t constant_id = pm_parser_constant_id_location(parser, start, end);
8014 if (constant_id != 0) pm_parser_local_add(parser, constant_id, start, end, reads);
8021static inline pm_constant_id_t
8022pm_parser_local_add_token(pm_parser_t *parser, pm_token_t *token, uint32_t reads) {
8023 return pm_parser_local_add_location(parser, token->start, token->end, reads);
8029static pm_constant_id_t
8030pm_parser_local_add_owned(pm_parser_t *parser, uint8_t *start, size_t length) {
8031 pm_constant_id_t constant_id = pm_parser_constant_id_owned(parser, start, length);
8032 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
8039static pm_constant_id_t
8040pm_parser_local_add_constant(pm_parser_t *parser, const char *start, size_t length) {
8041 pm_constant_id_t constant_id = pm_parser_constant_id_constant(parser, start, length);
8042 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
8054pm_parser_parameter_name_check(pm_parser_t *parser, const pm_token_t *name) {
8055 // We want to check whether the parameter name is a numbered parameter or
8057 pm_refute_numbered_parameter(parser, name->start, name->end);
8059 // Otherwise we'll fetch the constant id for the parameter name and check
8060 // whether it's already in the current scope.
8061 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, name);
8063 if (pm_locals_find(&parser->current_scope->locals, constant_id) != UINT32_MAX) {
8064 // Add an error if the parameter doesn't start with _ and has been seen before
8065 if ((name->start < name->end) && (*name->start != '_')) {
8066 pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NAME_DUPLICATED);
8077pm_parser_scope_pop(pm_parser_t *parser) {
8078 pm_scope_t *scope = parser->current_scope;
8079 parser->current_scope = scope->previous;
8080 pm_locals_free(&scope->locals);
8081 pm_node_list_free(&scope->implicit_parameters);
8085/******************************************************************************/
8087/******************************************************************************/
8093pm_state_stack_push(pm_state_stack_t *stack, bool value) {
8094 *stack = (*stack << 1) | (value & 1);
8101pm_state_stack_pop(pm_state_stack_t *stack) {
8109pm_state_stack_p(const pm_state_stack_t *stack) {
8114pm_accepts_block_stack_push(pm_parser_t *parser, bool value) {
8115 // Use the negation of the value to prevent stack overflow.
8116 pm_state_stack_push(&parser->accepts_block_stack, !value);
8120pm_accepts_block_stack_pop(pm_parser_t *parser) {
8121 pm_state_stack_pop(&parser->accepts_block_stack);
8125pm_accepts_block_stack_p(pm_parser_t *parser) {
8126 return !pm_state_stack_p(&parser->accepts_block_stack);
8130pm_do_loop_stack_push(pm_parser_t *parser, bool value) {
8131 pm_state_stack_push(&parser->do_loop_stack, value);
8135pm_do_loop_stack_pop(pm_parser_t *parser) {
8136 pm_state_stack_pop(&parser->do_loop_stack);
8140pm_do_loop_stack_p(pm_parser_t *parser) {
8141 return pm_state_stack_p(&parser->do_loop_stack);
8144/******************************************************************************/
8145/* Lexer check helpers */
8146/******************************************************************************/
8152static inline uint8_t
8153peek_at(const pm_parser_t *parser, const uint8_t *cursor) {
8154 if (cursor < parser->end) {
8166static inline uint8_t
8167peek_offset(pm_parser_t *parser, ptrdiff_t offset) {
8168 return peek_at(parser, parser->current.end + offset);
8175static inline uint8_t
8176peek(const pm_parser_t *parser) {
8177 return peek_at(parser, parser->current.end);
8185match(pm_parser_t *parser, uint8_t value) {
8186 if (peek(parser) == value) {
8187 parser->current.end++;
8198match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
8199 if (peek_at(parser, cursor) == '\n') {
8202 if (peek_at(parser, cursor) == '\r' && peek_at(parser, cursor + 1) == '\n') {
8214match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
8215 return match_eol_at(parser, parser->current.end + offset);
8224match_eol(pm_parser_t *parser) {
8225 return match_eol_at(parser, parser->current.end);
8231static inline const uint8_t *
8232next_newline(const uint8_t *cursor, ptrdiff_t length) {
8233 assert(length >= 0);
8235 // Note that it's okay for us to use memchr here to look for \n because none
8236 // of the encodings that we support have \n as a component of a multi-byte
8238 return memchr(cursor, '\n', (size_t) length);
8245ambiguous_operator_p(const pm_parser_t *parser, bool space_seen) {
8246 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));
8254parser_lex_magic_comment_encoding_value(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
8255 const pm_encoding_t *encoding = pm_encoding_find(start, end);
8257 if (encoding != NULL) {
8258 if (parser->encoding != encoding) {
8259 parser->encoding = encoding;
8260 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
8263 parser->encoding_changed = (encoding != PM_ENCODING_UTF_8_ENTRY);
8275parser_lex_magic_comment_encoding(pm_parser_t *parser) {
8276 const uint8_t *cursor = parser->current.start + 1;
8277 const uint8_t *end = parser->current.end;
8279 bool separator = false;
8281 if (end - cursor <= 6) return;
8282 switch (cursor[6]) {
8283 case 'C': case 'c': cursor += 6; continue;
8284 case 'O': case 'o': cursor += 5; continue;
8285 case 'D': case 'd': cursor += 4; continue;
8286 case 'I': case 'i': cursor += 3; continue;
8287 case 'N': case 'n': cursor += 2; continue;
8288 case 'G': case 'g': cursor += 1; continue;
8295 if (pm_char_is_whitespace(*cursor)) break;
8298 if (pm_strncasecmp(cursor - 6, (const uint8_t *) "coding", 6) == 0) break;
8304 if (++cursor >= end) return;
8305 } while (pm_char_is_whitespace(*cursor));
8307 if (separator) break;
8308 if (*cursor != '=' && *cursor != ':') return;
8314 const uint8_t *value_start = cursor;
8315 while ((*cursor == '-' || *cursor == '_' || parser->encoding->alnum_char(cursor, 1)) && ++cursor < end);
8317 if (!parser_lex_magic_comment_encoding_value(parser, value_start, cursor)) {
8318 // If we were unable to parse the encoding value, then we've got an
8319 // issue because we didn't understand the encoding that the user was
8320 // trying to use. In this case we'll keep using the default encoding but
8321 // add an error to the parser to indicate an unsuccessful parse.
8322 pm_parser_err(parser, value_start, cursor, PM_ERR_INVALID_ENCODING_MAGIC_COMMENT);
8327 PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE,
8328 PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE,
8329 PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID
8330} pm_magic_comment_boolean_value_t;
8336static pm_magic_comment_boolean_value_t
8337parser_lex_magic_comment_boolean_value(const uint8_t *value_start, uint32_t value_length) {
8338 if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "true", 4) == 0) {
8339 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE;
8340 } else if (value_length == 5 && pm_strncasecmp(value_start, (const uint8_t *) "false", 5) == 0) {
8341 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE;
8343 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID;
8348pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
8349 return b == '\'' || b == '"' || b == ':' || b == ';';
8357static inline const uint8_t *
8358parser_lex_magic_comment_emacs_marker(
pm_parser_t *parser,
const uint8_t *cursor,
const uint8_t *end) {
8359 while ((cursor + 3 <= end) && (cursor = pm_memchr(cursor,
'-', (
size_t) (end - cursor), parser->
encoding_changed, parser->
encoding)) != NULL) {
8360 if (cursor + 3 <= end && cursor[1] ==
'*' && cursor[2] ==
'-') {
8379parser_lex_magic_comment(
pm_parser_t *parser,
bool semantic_token_seen) {
8382 const uint8_t *start = parser->
current.start + 1;
8383 const uint8_t *end = parser->
current.end;
8384 if (end - start <= 7)
return false;
8386 const uint8_t *cursor;
8387 bool indicator =
false;
8389 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
8392 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
8403 while (cursor < end) {
8404 while (cursor < end && (pm_char_is_magic_comment_key_delimiter(*cursor) || pm_char_is_whitespace(*cursor))) cursor++;
8406 const uint8_t *key_start = cursor;
8407 while (cursor < end && (!pm_char_is_magic_comment_key_delimiter(*cursor) && !pm_char_is_whitespace(*cursor))) cursor++;
8409 const uint8_t *key_end = cursor;
8410 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
8411 if (cursor == end)
break;
8413 if (*cursor ==
':') {
8416 if (!indicator)
return false;
8420 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
8421 if (cursor == end)
break;
8423 const uint8_t *value_start;
8424 const uint8_t *value_end;
8426 if (*cursor ==
'"') {
8427 value_start = ++cursor;
8428 for (; cursor < end && *cursor !=
'"'; cursor++) {
8429 if (*cursor ==
'\\' && (cursor + 1 < end)) cursor++;
8432 if (*cursor ==
'"') cursor++;
8434 value_start = cursor;
8435 while (cursor < end && *cursor !=
'"' && *cursor !=
';' && !pm_char_is_whitespace(*cursor)) cursor++;
8440 while (cursor < end && (*cursor ==
';' || pm_char_is_whitespace(*cursor))) cursor++;
8442 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
8443 if (cursor != end)
return false;
8449 const size_t key_length = (size_t) (key_end - key_start);
8453 pm_string_shared_init(&key, key_start, key_end);
8455 uint8_t *buffer =
xmalloc(key_length);
8456 if (buffer == NULL)
break;
8458 memcpy(buffer, key_start, key_length);
8459 buffer[dash - key_start] =
'_';
8461 while ((dash = pm_memchr(dash + 1,
'-', (
size_t) (key_end - dash - 1), parser->
encoding_changed, parser->
encoding)) != NULL) {
8462 buffer[dash - key_start] =
'_';
8465 pm_string_owned_init(&key, buffer, key_length);
8471 uint32_t value_length = (uint32_t) (value_end - value_start);
8477 (key_length == 8 && pm_strncasecmp(key_source, (
const uint8_t *)
"encoding", 8) == 0) ||
8478 (key_length == 6 && pm_strncasecmp(key_source, (
const uint8_t *)
"coding", 6) == 0)
8480 result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
8484 if (key_length == 11) {
8485 if (pm_strncasecmp(key_source, (
const uint8_t *)
"warn_indent", 11) == 0) {
8486 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
8487 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
8488 PM_PARSER_WARN_TOKEN_FORMAT(
8491 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8493 (
const char *) key_source,
8495 (
const char *) value_start
8498 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
8501 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
8506 }
else if (key_length == 21) {
8507 if (pm_strncasecmp(key_source, (
const uint8_t *)
"frozen_string_literal", 21) == 0) {
8510 if (semantic_token_seen) {
8511 pm_parser_warn_token(parser, &parser->
current, PM_WARN_IGNORED_FROZEN_STRING_LITERAL);
8513 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
8514 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
8515 PM_PARSER_WARN_TOKEN_FORMAT(
8518 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8520 (
const char *) key_source,
8522 (
const char *) value_start
8525 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
8528 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
8534 }
else if (key_length == 24) {
8535 if (pm_strncasecmp(key_source, (
const uint8_t *)
"shareable_constant_value", 24) == 0) {
8536 const uint8_t *cursor = parser->
current.start;
8537 while ((cursor > parser->
start) && ((cursor[-1] ==
' ') || (cursor[-1] ==
'\t'))) cursor--;
8539 if (!((cursor == parser->
start) || (cursor[-1] ==
'\n'))) {
8540 pm_parser_warn_token(parser, &parser->
current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
8541 }
else if (value_length == 4 && pm_strncasecmp(value_start, (
const uint8_t *)
"none", 4) == 0) {
8542 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
8543 }
else if (value_length == 7 && pm_strncasecmp(value_start, (
const uint8_t *)
"literal", 7) == 0) {
8544 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
8545 }
else if (value_length == 23 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_everything", 23) == 0) {
8546 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING);
8547 }
else if (value_length == 17 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_copy", 17) == 0) {
8548 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY);
8550 PM_PARSER_WARN_TOKEN_FORMAT(
8553 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8555 (
const char *) key_source,
8557 (
const char *) value_start
8585static const uint32_t context_terminators[] = {
8587 [
PM_CONTEXT_BEGIN] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8590 [
PM_CONTEXT_BEGIN_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8592 [
PM_CONTEXT_BLOCK_KEYWORDS] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
8595 [
PM_CONTEXT_BLOCK_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8596 [
PM_CONTEXT_CASE_WHEN] = (1 << PM_TOKEN_KEYWORD_WHEN) | (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_ELSE),
8597 [
PM_CONTEXT_CASE_IN] = (1 << PM_TOKEN_KEYWORD_IN) | (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_ELSE),
8598 [
PM_CONTEXT_CLASS] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
8601 [
PM_CONTEXT_CLASS_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8602 [
PM_CONTEXT_DEF] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
8605 [
PM_CONTEXT_DEF_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8610 [
PM_CONTEXT_ELSIF] = (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_ELSIF) | (1 << PM_TOKEN_KEYWORD_END),
8614 [
PM_CONTEXT_IF] = (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_ELSIF) | (1 << PM_TOKEN_KEYWORD_END),
8616 [
PM_CONTEXT_LAMBDA_DO_END] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
8619 [
PM_CONTEXT_LAMBDA_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8622 [
PM_CONTEXT_MODULE] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
8625 [
PM_CONTEXT_MODULE_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8629 [
PM_CONTEXT_PREDICATE] = (1 << PM_TOKEN_KEYWORD_THEN) | (1 << PM_TOKEN_NEWLINE) | (1 << PM_TOKEN_SEMICOLON),
8632 [
PM_CONTEXT_SCLASS] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
8635 [
PM_CONTEXT_SCLASS_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8637 [
PM_CONTEXT_UNLESS] = (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8644 return token->type < 32 && (context_terminators[context] & (1 << token->type));
8655 while (context_node != NULL) {
8656 if (context_terminator(context_node->
context, token))
return context_node->
context;
8657 context_node = context_node->
prev;
8666 if (context_node == NULL)
return false;
8691 while (context_node != NULL) {
8692 if (context_node->
context == context)
return true;
8693 context_node = context_node->
prev;
8703 while (context_node != NULL) {
8704 switch (context_node->
context) {
8725 context_node = context_node->
prev;
8740 assert(
false &&
"unreachable");
8797 assert(
false &&
"unreachable");
8806pm_strspn_number_validate(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const uint8_t *invalid) {
8807 if (invalid != NULL) {
8808 pm_diagnostic_id_t diag_id = (invalid == (
string + length - 1)) ? PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING : PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER;
8809 pm_parser_err(parser, invalid, invalid + 1, diag_id);
8814pm_strspn_binary_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8815 const uint8_t *invalid = NULL;
8816 size_t length = pm_strspn_binary_number(
string, parser->
end -
string, &invalid);
8817 pm_strspn_number_validate(parser,
string, length, invalid);
8822pm_strspn_octal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8823 const uint8_t *invalid = NULL;
8824 size_t length = pm_strspn_octal_number(
string, parser->
end -
string, &invalid);
8825 pm_strspn_number_validate(parser,
string, length, invalid);
8830pm_strspn_decimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8831 const uint8_t *invalid = NULL;
8832 size_t length = pm_strspn_decimal_number(
string, parser->
end -
string, &invalid);
8833 pm_strspn_number_validate(parser,
string, length, invalid);
8838pm_strspn_hexadecimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8839 const uint8_t *invalid = NULL;
8840 size_t length = pm_strspn_hexadecimal_number(
string, parser->
end -
string, &invalid);
8841 pm_strspn_number_validate(parser,
string, length, invalid);
8845static pm_token_type_t
8846lex_optional_float_suffix(
pm_parser_t *parser,
bool* seen_e) {
8847 pm_token_type_t
type = PM_TOKEN_INTEGER;
8851 if (peek(parser) ==
'.') {
8852 if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8854 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8855 type = PM_TOKEN_FLOAT;
8865 if ((peek(parser) ==
'e') || (peek(parser) ==
'E')) {
8866 if ((peek_offset(parser, 1) ==
'+') || (peek_offset(parser, 1) ==
'-')) {
8869 if (pm_char_is_decimal_digit(peek(parser))) {
8871 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8873 pm_parser_err_current(parser, PM_ERR_INVALID_FLOAT_EXPONENT);
8875 }
else if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8877 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8883 type = PM_TOKEN_FLOAT;
8889static pm_token_type_t
8890lex_numeric_prefix(
pm_parser_t *parser,
bool* seen_e) {
8891 pm_token_type_t
type = PM_TOKEN_INTEGER;
8894 if (peek_offset(parser, -1) ==
'0') {
8895 switch (*parser->
current.end) {
8900 if (pm_char_is_decimal_digit(peek(parser))) {
8901 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8904 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_DECIMAL);
8913 if (pm_char_is_binary_digit(peek(parser))) {
8914 parser->
current.end += pm_strspn_binary_number_validate(parser, parser->
current.end);
8917 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
8927 if (pm_char_is_octal_digit(peek(parser))) {
8928 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8931 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
8947 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8955 if (pm_char_is_hexadecimal_digit(peek(parser))) {
8956 parser->
current.end += pm_strspn_hexadecimal_number_validate(parser, parser->
current.end);
8959 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
8962 parser->
integer_base = PM_INTEGER_BASE_FLAGS_HEXADECIMAL;
8967 type = lex_optional_float_suffix(parser, seen_e);
8974 type = lex_optional_float_suffix(parser, seen_e);
8981 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8984 type = lex_optional_float_suffix(parser, seen_e);
8990 if (peek_offset(parser, 0) ==
'.' && pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8991 const uint8_t *fraction_start = parser->
current.end;
8992 const uint8_t *fraction_end = parser->
current.end + 2;
8993 fraction_end += pm_strspn_decimal_digit(fraction_end, parser->
end - fraction_end);
8994 pm_parser_err(parser, fraction_start, fraction_end, PM_ERR_INVALID_NUMBER_FRACTION);
9000static pm_token_type_t
9002 pm_token_type_t
type = PM_TOKEN_INTEGER;
9006 bool seen_e =
false;
9007 type = lex_numeric_prefix(parser, &seen_e);
9009 const uint8_t *end = parser->
current.end;
9010 pm_token_type_t suffix_type =
type;
9012 if (
type == PM_TOKEN_INTEGER) {
9013 if (match(parser,
'r')) {
9014 suffix_type = PM_TOKEN_INTEGER_RATIONAL;
9016 if (match(parser,
'i')) {
9017 suffix_type = PM_TOKEN_INTEGER_RATIONAL_IMAGINARY;
9019 }
else if (match(parser,
'i')) {
9020 suffix_type = PM_TOKEN_INTEGER_IMAGINARY;
9023 if (!seen_e && match(parser,
'r')) {
9024 suffix_type = PM_TOKEN_FLOAT_RATIONAL;
9026 if (match(parser,
'i')) {
9027 suffix_type = PM_TOKEN_FLOAT_RATIONAL_IMAGINARY;
9029 }
else if (match(parser,
'i')) {
9030 suffix_type = PM_TOKEN_FLOAT_IMAGINARY;
9034 const uint8_t b = peek(parser);
9035 if (b !=
'\0' && (b >= 0x80 || ((b >=
'a' && b <=
'z') || (b >=
'A' && b <=
'Z')) || b ==
'_')) {
9045static pm_token_type_t
9048 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
9049 return PM_TOKEN_GLOBAL_VARIABLE;
9054 bool allow_multiple =
true;
9056 switch (*parser->
current.end) {
9074 return PM_TOKEN_GLOBAL_VARIABLE;
9081 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_BACK_REFERENCE;
9087 if ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0) {
9090 }
while ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0);
9094 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
current, diag_id);
9097 return PM_TOKEN_GLOBAL_VARIABLE;
9110 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_NUMBERED_REFERENCE;
9114 allow_multiple =
false;
9119 if ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0) {
9122 }
while (allow_multiple && (width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0);
9123 }
else if (pm_char_is_whitespace(peek(parser))) {
9126 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
9132 PM_PARSER_ERR_FORMAT(parser, parser->
current.start, end, diag_id, (
int) (end - parser->
current.start), (
const char *) parser->
current.start);
9135 return PM_TOKEN_GLOBAL_VARIABLE;
9152static inline pm_token_type_t
9153lex_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) {
9154 if (memcmp(current_start, value, vlen) == 0) {
9157 if (parser->
lex_state & PM_LEX_STATE_FNAME) {
9158 lex_state_set(parser, PM_LEX_STATE_ENDFN);
9160 lex_state_set(parser, state);
9161 if (state == PM_LEX_STATE_BEG) {
9165 if ((modifier_type != PM_TOKEN_EOF) && !(last_state & (PM_LEX_STATE_BEG | PM_LEX_STATE_LABELED | PM_LEX_STATE_CLASS))) {
9166 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
9167 return modifier_type;
9174 return PM_TOKEN_EOF;
9177static pm_token_type_t
9178lex_identifier(
pm_parser_t *parser,
bool previous_command_start) {
9181 const uint8_t *end = parser->
end;
9182 const uint8_t *current_start = parser->
current.start;
9183 const uint8_t *current_end = parser->
current.end;
9186 if (encoding_changed) {
9187 while ((width = char_is_identifier(parser, current_end, end - current_end)) > 0) {
9188 current_end += width;
9191 while ((width = char_is_identifier_utf8(current_end, end - current_end)) > 0) {
9192 current_end += width;
9195 parser->
current.end = current_end;
9199 width = (size_t) (current_end - current_start);
9201 if (current_end < end) {
9202 if (((current_end + 1 >= end) || (current_end[1] !=
'=')) && (match(parser,
'!') || match(parser,
'?'))) {
9208 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
9209 (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')
9213 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
9214 (void) match(parser,
':');
9215 return PM_TOKEN_LABEL;
9218 if (parser->
lex_state != PM_LEX_STATE_DOT) {
9219 if (width == 8 && (lex_keyword(parser, current_start,
"defined?", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_DEFINED, PM_TOKEN_EOF) != PM_TOKEN_EOF)) {
9220 return PM_TOKEN_KEYWORD_DEFINED;
9224 return PM_TOKEN_METHOD_NAME;
9227 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,
'=')) {
9230 return PM_TOKEN_IDENTIFIER;
9234 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
9235 peek(parser) ==
':' && peek_offset(parser, 1) !=
':'
9239 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
9240 (void) match(parser,
':');
9241 return PM_TOKEN_LABEL;
9245 if (parser->
lex_state != PM_LEX_STATE_DOT) {
9246 pm_token_type_t
type;
9249 if (lex_keyword(parser, current_start,
"do", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_DO, PM_TOKEN_EOF) != PM_TOKEN_EOF) {
9250 if (pm_do_loop_stack_p(parser)) {
9251 return PM_TOKEN_KEYWORD_DO_LOOP;
9253 return PM_TOKEN_KEYWORD_DO;
9256 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;
9257 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;
9258 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;
9261 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;
9262 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;
9263 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;
9264 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;
9265 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;
9266 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;
9267 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;
9270 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;
9271 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;
9272 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;
9273 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;
9274 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;
9275 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;
9276 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;
9277 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;
9280 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;
9281 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;
9282 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;
9283 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;
9284 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;
9285 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;
9286 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;
9287 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;
9288 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;
9289 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;
9290 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;
9291 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;
9292 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;
9295 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;
9296 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;
9297 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;
9298 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;
9299 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;
9302 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;
9303 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;
9306 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;
9311 if (encoding_changed) {
9312 return parser->
encoding->
isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
9314 return pm_encoding_utf_8_isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
9340static pm_token_type_t
9341lex_interpolation(
pm_parser_t *parser,
const uint8_t *pound) {
9344 if (pound + 1 >= parser->
end) {
9345 parser->
current.end = pound + 1;
9346 return PM_TOKEN_STRING_CONTENT;
9355 if (pound + 2 >= parser->
end) {
9356 parser->
current.end = pound + 1;
9357 return PM_TOKEN_STRING_CONTENT;
9362 const uint8_t *variable = pound + 2;
9363 if (*variable ==
'@' && pound + 3 < parser->
end) variable++;
9365 if (char_is_identifier_start(parser, variable, parser->
end - variable)) {
9369 if (pound > parser->
current.start) {
9371 return PM_TOKEN_STRING_CONTENT;
9376 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
9377 parser->
current.end = pound + 1;
9378 return PM_TOKEN_EMBVAR;
9384 parser->
current.end = pound + 1;
9385 return PM_TOKEN_NOT_PROVIDED;
9390 if (pound + 2 >= parser->
end) {
9391 parser->
current.end = pound + 1;
9392 return PM_TOKEN_STRING_CONTENT;
9398 const uint8_t *check = pound + 2;
9400 if (pound[2] ==
'-') {
9401 if (pound + 3 >= parser->
end) {
9402 parser->
current.end = pound + 2;
9403 return PM_TOKEN_STRING_CONTENT;
9414 char_is_identifier_start(parser, check, parser->
end - check) ||
9415 (pound[2] !=
'-' && (pm_char_is_decimal_digit(pound[2]) || char_is_global_name_punctuation(pound[2])))
9420 if (pound > parser->
current.start) {
9422 return PM_TOKEN_STRING_CONTENT;
9427 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
9428 parser->
current.end = pound + 1;
9429 return PM_TOKEN_EMBVAR;
9434 parser->
current.end = pound + 1;
9435 return PM_TOKEN_NOT_PROVIDED;
9440 if (pound > parser->
current.start) {
9442 return PM_TOKEN_STRING_CONTENT;
9449 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBEXPR });
9450 parser->
current.end = pound + 2;
9452 pm_do_loop_stack_push(parser,
false);
9453 return PM_TOKEN_EMBEXPR_BEGIN;
9458 parser->
current.end = pound + 1;
9459 return PM_TOKEN_NOT_PROVIDED;
9463static const uint8_t PM_ESCAPE_FLAG_NONE = 0x0;
9464static const uint8_t PM_ESCAPE_FLAG_CONTROL = 0x1;
9465static const uint8_t PM_ESCAPE_FLAG_META = 0x2;
9466static const uint8_t PM_ESCAPE_FLAG_SINGLE = 0x4;
9467static const uint8_t PM_ESCAPE_FLAG_REGEXP = 0x8;
9472static const bool ascii_printable_chars[] = {
9473 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
9474 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9475 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9476 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9477 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9478 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
9479 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9480 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
9484char_is_ascii_printable(
const uint8_t b) {
9485 return (b < 0x80) && ascii_printable_chars[b];
9492static inline uint8_t
9493escape_hexadecimal_digit(
const uint8_t value) {
9494 return (uint8_t) ((value <=
'9') ? (value -
'0') : (value & 0x7) + 9);
9502static inline uint32_t
9503escape_unicode(
pm_parser_t *parser,
const uint8_t *
string,
size_t length) {
9505 for (
size_t index = 0; index < length; index++) {
9506 if (index != 0) value <<= 4;
9507 value |= escape_hexadecimal_digit(
string[index]);
9512 if (value >= 0xD800 && value <= 0xDFFF) {
9513 pm_parser_err(parser,
string,
string + length, PM_ERR_ESCAPE_INVALID_UNICODE);
9523static inline uint8_t
9524escape_byte(uint8_t value,
const uint8_t flags) {
9525 if (flags & PM_ESCAPE_FLAG_CONTROL) value &= 0x9f;
9526 if (flags & PM_ESCAPE_FLAG_META) value |= 0x80;
9534escape_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) {
9538 if (value >= 0x80 || flags & PM_ESCAPE_FLAG_SINGLE) {
9546 if (!pm_buffer_append_unicode_codepoint(buffer, value)) {
9547 pm_parser_err(parser, start, end, PM_ERR_ESCAPE_INVALID_UNICODE);
9548 pm_buffer_append_byte(buffer, 0xEF);
9549 pm_buffer_append_byte(buffer, 0xBF);
9550 pm_buffer_append_byte(buffer, 0xBD);
9562 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_MIXED_ENCODING, parser->
encoding->
name);
9568 pm_buffer_append_byte(buffer,
byte);
9588 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9589 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X",
byte);
9592 escape_write_byte_encoded(parser, buffer,
byte);
9604 width = pm_encoding_utf_8_char_width(parser->
current.end, parser->
end - parser->
current.end);
9608 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(*parser->
current.end++, flags));
9609 }
else if (width > 1) {
9611 pm_buffer_t *b = (flags & PM_ESCAPE_FLAG_REGEXP) ? regular_expression_buffer : buffer;
9612 pm_buffer_append_bytes(b, parser->
current.end, width);
9618 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9628escape_read_warn(
pm_parser_t *parser, uint8_t flags, uint8_t flag,
const char *
type) {
9629#define FLAG(value) ((value & PM_ESCAPE_FLAG_CONTROL) ? "\\C-" : (value & PM_ESCAPE_FLAG_META) ? "\\M-" : "")
9631 PM_PARSER_WARN_TOKEN_FORMAT(
9634 PM_WARN_INVALID_CHARACTER,
9648 uint8_t peeked = peek(parser);
9652 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\\', flags));
9657 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\'', flags));
9662 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\a', flags));
9667 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\b', flags));
9672 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\033', flags));
9677 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\f', flags));
9682 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\n', flags));
9687 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\r', flags));
9692 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
' ', flags));
9697 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\t', flags));
9702 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\v', flags));
9705 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': {
9706 uint8_t value = (uint8_t) (*parser->
current.end -
'0');
9709 if (pm_char_is_octal_digit(peek(parser))) {
9710 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
9713 if (pm_char_is_octal_digit(peek(parser))) {
9714 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
9719 value = escape_byte(value, flags);
9720 escape_write_byte(parser, buffer, regular_expression_buffer, flags, value);
9724 const uint8_t *start = parser->
current.end - 1;
9727 uint8_t
byte = peek(parser);
9729 if (pm_char_is_hexadecimal_digit(
byte)) {
9730 uint8_t value = escape_hexadecimal_digit(
byte);
9733 byte = peek(parser);
9734 if (pm_char_is_hexadecimal_digit(
byte)) {
9735 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(
byte));
9739 value = escape_byte(value, flags);
9740 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9741 if (flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) {
9742 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X", value);
9744 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9748 escape_write_byte_encoded(parser, buffer, value);
9750 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
9756 const uint8_t *start = parser->
current.end - 1;
9760 const uint8_t *start = parser->
current.end - 2;
9761 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9762 }
else if (peek(parser) ==
'{') {
9763 const uint8_t *unicode_codepoints_start = parser->
current.end - 2;
9768 if ((whitespace = pm_strspn_inline_whitespace(parser->
current.end, parser->
end - parser->
current.end)) > 0) {
9769 parser->
current.end += whitespace;
9770 }
else if (peek(parser) ==
'\\' && peek_offset(parser, 1) ==
'n') {
9781 const uint8_t *extra_codepoints_start = NULL;
9782 int codepoints_count = 0;
9785 const uint8_t *unicode_start = parser->
current.end;
9786 size_t hexadecimal_length = pm_strspn_hexadecimal_digit(parser->
current.end, parser->
end - parser->
current.end);
9788 if (hexadecimal_length > 6) {
9790 pm_parser_err(parser, unicode_start, unicode_start + hexadecimal_length, PM_ERR_ESCAPE_INVALID_UNICODE_LONG);
9791 }
else if (hexadecimal_length == 0) {
9794 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9798 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9800 pm_parser_err(parser, parser->
current.end, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE);
9801 pm_parser_err(parser, parser->
current.end, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9807 parser->
current.end += hexadecimal_length;
9809 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count == 2) {
9810 extra_codepoints_start = unicode_start;
9813 uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length);
9814 escape_write_unicode(parser, buffer, flags, unicode_start, parser->
current.end, value);
9821 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count > 1) {
9822 pm_parser_err(parser, extra_codepoints_start, parser->
current.end - 1, PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL);
9826 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_LIST, (
int) (parser->
current.end - start), start);
9827 }
else if (peek(parser) ==
'}') {
9830 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9834 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9836 pm_parser_err(parser, unicode_codepoints_start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9840 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9841 pm_buffer_append_bytes(regular_expression_buffer, unicode_codepoints_start, (
size_t) (parser->
current.end - unicode_codepoints_start));
9844 size_t length = pm_strspn_hexadecimal_digit(parser->
current.end, MIN(parser->
end - parser->
current.end, 4));
9847 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9848 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9850 const uint8_t *start = parser->
current.end - 2;
9851 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9853 }
else if (length == 4) {
9854 uint32_t value = escape_unicode(parser, parser->
current.end, 4);
9856 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9857 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end + 4 - start));
9860 escape_write_unicode(parser, buffer, flags, start, parser->
current.end + 4, value);
9863 parser->
current.end += length;
9865 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9869 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9871 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_UNICODE);
9880 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9881 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9885 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9889 uint8_t peeked = peek(parser);
9893 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9899 if (match(parser,
'u') || match(parser,
'U')) {
9900 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9904 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9908 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9909 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9913 escape_read_warn(parser, flags, 0,
"\\t");
9914 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9917 if (!char_is_ascii_printable(peeked)) {
9918 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9923 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9930 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9931 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9934 if (peek(parser) !=
'-') {
9936 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9942 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9946 uint8_t peeked = peek(parser);
9950 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9956 if (match(parser,
'u') || match(parser,
'U')) {
9957 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9961 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9965 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9966 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9970 escape_read_warn(parser, flags, 0,
"\\t");
9971 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9974 if (!char_is_ascii_printable(peeked)) {
9976 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9981 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9988 if (flags & PM_ESCAPE_FLAG_META) {
9989 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META_REPEAT);
9992 if (peek(parser) !=
'-') {
9994 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
10000 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
10004 uint8_t peeked = peek(parser);
10009 if (match(parser,
'u') || match(parser,
'U')) {
10010 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
10014 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_META);
10018 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_META,
"\\s");
10019 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10023 escape_read_warn(parser, flags & ((uint8_t) ~PM_ESCAPE_FLAG_CONTROL), PM_ESCAPE_FLAG_META,
"\\t");
10024 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10027 if (!char_is_ascii_printable(peeked)) {
10029 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
10034 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10039 if (peek_offset(parser, 1) ==
'\n') {
10041 escape_write_byte_encoded(parser, buffer, escape_byte(
'\n', flags));
10047 if ((flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) && !char_is_ascii_printable(peeked)) {
10049 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
10053 escape_write_escape_encoded(parser, buffer, regular_expression_buffer, flags);
10055 pm_parser_err_current(parser, PM_ERR_INVALID_ESCAPE_CHARACTER);
10087static pm_token_type_t
10089 if (lex_state_end_p(parser)) {
10090 lex_state_set(parser, PM_LEX_STATE_BEG);
10091 return PM_TOKEN_QUESTION_MARK;
10095 pm_parser_err_current(parser, PM_ERR_INCOMPLETE_QUESTION_MARK);
10097 return PM_TOKEN_CHARACTER_LITERAL;
10100 if (pm_char_is_whitespace(*parser->
current.end)) {
10101 lex_state_set(parser, PM_LEX_STATE_BEG);
10102 return PM_TOKEN_QUESTION_MARK;
10105 lex_state_set(parser, PM_LEX_STATE_BEG);
10107 if (match(parser,
'\\')) {
10108 lex_state_set(parser, PM_LEX_STATE_END);
10111 pm_buffer_init_capacity(&buffer, 3);
10113 escape_read(parser, &buffer, NULL, PM_ESCAPE_FLAG_SINGLE);
10116 return PM_TOKEN_CHARACTER_LITERAL;
10125 (parser->
current.end + encoding_width >= parser->
end) ||
10126 !char_is_identifier(parser, parser->
current.end + encoding_width, parser->
end - (parser->
current.end + encoding_width))
10129 lex_state_set(parser, PM_LEX_STATE_END);
10130 parser->
current.end += encoding_width;
10132 return PM_TOKEN_CHARACTER_LITERAL;
10136 return PM_TOKEN_QUESTION_MARK;
10143static pm_token_type_t
10145 pm_token_type_t
type = match(parser,
'@') ? PM_TOKEN_CLASS_VARIABLE : PM_TOKEN_INSTANCE_VARIABLE;
10146 const uint8_t *end = parser->
end;
10149 if ((width = char_is_identifier_start(parser, parser->
current.end, end - parser->
current.end)) > 0) {
10150 parser->
current.end += width;
10152 while ((width = char_is_identifier(parser, parser->
current.end, end - parser->
current.end)) > 0) {
10153 parser->
current.end += width;
10155 }
else if (parser->
current.end < end && pm_char_is_decimal_digit(*parser->
current.end)) {
10156 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE;
10158 diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS_3_3 : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE_3_3;
10162 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, diag_id, (
int) ((parser->
current.end + width) - parser->
current.start), (
const char *) parser->
current.start);
10164 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_CLASS_VARIABLE_BARE : PM_ERR_INSTANCE_VARIABLE_BARE;
10165 pm_parser_err_token(parser, &parser->
current, diag_id);
10171 lex_mode_pop(parser);
10193 if (comment == NULL)
return NULL;
10208static pm_token_type_t
10211 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10213 if (newline == NULL) {
10216 pm_newline_list_append(&parser->
newline_list, newline);
10217 parser->
current.end = newline + 1;
10220 parser->
current.type = PM_TOKEN_EMBDOC_BEGIN;
10221 parser_lex_callback(parser);
10224 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_EMBDOC);
10225 if (comment == NULL)
return PM_TOKEN_EOF;
10229 while (parser->
current.end + 4 <= parser->
end) {
10235 (memcmp(parser->
current.end,
"=end", 4) == 0) &&
10238 pm_char_is_whitespace(parser->
current.end[4]) ||
10239 (parser->
current.end[4] ==
'\0') ||
10240 (parser->
current.end[4] ==
'\004') ||
10241 (parser->
current.end[4] ==
'\032')
10244 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10246 if (newline == NULL) {
10249 pm_newline_list_append(&parser->
newline_list, newline);
10250 parser->
current.end = newline + 1;
10253 parser->
current.type = PM_TOKEN_EMBDOC_END;
10254 parser_lex_callback(parser);
10259 return PM_TOKEN_EMBDOC_END;
10264 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10266 if (newline == NULL) {
10269 pm_newline_list_append(&parser->
newline_list, newline);
10270 parser->
current.end = newline + 1;
10273 parser->
current.type = PM_TOKEN_EMBDOC_LINE;
10274 parser_lex_callback(parser);
10277 pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
10282 return PM_TOKEN_EOF;
10292 parser->
current.type = PM_TOKEN_IGNORED_NEWLINE;
10293 parser_lex_callback(parser);
10317 const uint8_t *cursor = parser->
current.end;
10319 while (cursor < parser->end && *cursor !=
'\n' && *cursor !=
'#') {
10320 if (!pm_char_is_inline_whitespace(*cursor++))
return false;
10383 pm_buffer_append_byte(&token_buffer->
buffer,
byte);
10394static inline size_t
10400 width = pm_encoding_utf_8_char_width(parser->
current.end, parser->
end - parser->
current.end);
10405 return (width == 0 ? 1 : width);
10413 size_t width = parser_char_width(parser);
10414 pm_buffer_append_bytes(&token_buffer->
buffer, parser->
current.end, width);
10415 parser->
current.end += width;
10420 size_t width = parser_char_width(parser);
10421 pm_buffer_append_bytes(&token_buffer->
base.
buffer, parser->
current.end, width);
10423 parser->
current.end += width;
10427pm_slice_ascii_only_p(
const uint8_t *value,
size_t length) {
10428 for (
size_t index = 0; index < length; index++) {
10429 if (value[index] & 0x80)
return false;
10464 if (token_buffer->
cursor == NULL) {
10467 pm_buffer_append_bytes(&token_buffer->
buffer, token_buffer->
cursor, (
size_t) (parser->
current.end - token_buffer->
cursor));
10468 pm_token_buffer_copy(parser, token_buffer);
10480 pm_regexp_token_buffer_copy(parser, token_buffer);
10484#define PM_TOKEN_BUFFER_DEFAULT_SIZE 16
10496 const uint8_t *start;
10497 if (token_buffer->
cursor == NULL) {
10498 pm_buffer_init_capacity(&token_buffer->
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10499 start = parser->
current.start;
10501 start = token_buffer->
cursor;
10504 const uint8_t *end = parser->
current.end - 1;
10505 assert(end >= start);
10506 pm_buffer_append_bytes(&token_buffer->
buffer, start, (
size_t) (end - start));
10508 token_buffer->
cursor = end;
10513 const uint8_t *start;
10515 pm_buffer_init_capacity(&token_buffer->
base.
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10516 pm_buffer_init_capacity(&token_buffer->
regexp_buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10517 start = parser->
current.start;
10522 const uint8_t *end = parser->
current.end - 1;
10523 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, (
size_t) (end - start));
10524 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, (
size_t) (end - start));
10529#undef PM_TOKEN_BUFFER_DEFAULT_SIZE
10535static inline size_t
10537 size_t whitespace = 0;
10540 case PM_HEREDOC_INDENT_NONE:
10545 case PM_HEREDOC_INDENT_DASH:
10547 *cursor += pm_strspn_inline_whitespace(*cursor, parser->
end - *cursor);
10549 case PM_HEREDOC_INDENT_TILDE:
10552 while (*cursor < parser->end && pm_char_is_inline_whitespace(**cursor)) {
10553 if (**cursor ==
'\t') {
10554 whitespace = (whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
10573 size_t eol_length = match_eol(parser);
10580 parser_flush_heredoc_end(parser);
10586 uint8_t delimiter = *parser->
current.end;
10590 if (eol_length == 2) {
10591 delimiter = *(parser->
current.end + 1);
10594 parser->
current.end += eol_length;
10598 return *parser->
current.end++;
10605#define LEX(token_type) parser->current.type = token_type; parser_lex_callback(parser); return
10624 bool lexed_comment =
false;
10632 case PM_LEX_DEFAULT:
10633 case PM_LEX_EMBEXPR:
10634 case PM_LEX_EMBVAR:
10650 bool space_seen =
false;
10654 bool chomping =
true;
10655 while (parser->
current.end < parser->
end && chomping) {
10656 switch (*parser->
current.end) {
10665 if (match_eol_offset(parser, 1)) {
10668 pm_parser_warn(parser, parser->
current.end, parser->
current.end + 1, PM_WARN_UNEXPECTED_CARRIAGE_RETURN);
10674 size_t eol_length = match_eol_offset(parser, 1);
10680 parser->
current.end += eol_length + 1;
10684 }
else if (pm_char_is_inline_whitespace(*parser->
current.end)) {
10717 switch (*parser->
current.end++) {
10725 const uint8_t *ending = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10726 parser->
current.end = ending == NULL ? parser->
end : ending;
10731 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_INLINE);
10734 if (ending) parser->
current.end++;
10735 parser->
current.type = PM_TOKEN_COMMENT;
10736 parser_lex_callback(parser);
10748 parser_lex_magic_comment_encoding(parser);
10752 lexed_comment =
true;
10758 size_t eol_length = match_eol_at(parser, parser->
current.end - 1);
10770 if (!lexed_comment) {
10771 parser->
current.end += eol_length - 1;
10780 parser_flush_heredoc_end(parser);
10785 switch (lex_state_ignored_p(parser)) {
10786 case PM_IGNORED_NEWLINE_NONE:
10788 case PM_IGNORED_NEWLINE_PATTERN:
10790 if (!lexed_comment) parser_lex_ignored_newline(parser);
10791 lex_state_set(parser, PM_LEX_STATE_BEG);
10793 parser->
current.type = PM_TOKEN_NEWLINE;
10797 case PM_IGNORED_NEWLINE_ALL:
10798 if (!lexed_comment) parser_lex_ignored_newline(parser);
10799 lexed_comment =
false;
10800 goto lex_next_token;
10808 next_content += pm_strspn_inline_whitespace(next_content, parser->
end - next_content);
10810 if (next_content < parser->end) {
10816 if (next_content[0] ==
'#') {
10818 const uint8_t *following = next_newline(next_content, parser->
end - next_content);
10820 while (following && (following + 1 < parser->
end)) {
10822 following += pm_strspn_inline_whitespace(following, parser->
end - following);
10826 if (peek_at(parser, following) !=
'#')
break;
10830 following = next_newline(following, parser->
end - following);
10835 if (lex_state_ignored_p(parser)) {
10836 if (!lexed_comment) parser_lex_ignored_newline(parser);
10837 lexed_comment =
false;
10838 goto lex_next_token;
10844 (peek_at(parser, following) ==
'.') ||
10845 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'.')
10847 if (!lexed_comment) parser_lex_ignored_newline(parser);
10848 lexed_comment =
false;
10849 goto lex_next_token;
10859 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'&') ||
10860 (peek_at(parser, following) ==
'|' && peek_at(parser, following + 1) ==
'|') ||
10861 (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))) ||
10862 (peek_at(parser, following) ==
'o' && peek_at(parser, following + 1) ==
'r' && !char_is_identifier(parser, following + 2, parser->
end - (following + 2)))
10865 if (!lexed_comment) parser_lex_ignored_newline(parser);
10866 lexed_comment =
false;
10867 goto lex_next_token;
10873 if (next_content[0] ==
'.') {
10877 if (peek_at(parser, next_content + 1) ==
'.') {
10878 if (!lexed_comment) parser_lex_ignored_newline(parser);
10879 lex_state_set(parser, PM_LEX_STATE_BEG);
10881 parser->
current.type = PM_TOKEN_NEWLINE;
10885 if (!lexed_comment) parser_lex_ignored_newline(parser);
10886 lex_state_set(parser, PM_LEX_STATE_DOT);
10887 parser->
current.start = next_content;
10888 parser->
current.end = next_content + 1;
10895 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'.') {
10896 if (!lexed_comment) parser_lex_ignored_newline(parser);
10897 lex_state_set(parser, PM_LEX_STATE_DOT);
10898 parser->
current.start = next_content;
10899 parser->
current.end = next_content + 2;
10901 LEX(PM_TOKEN_AMPERSAND_DOT);
10907 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'&') {
10908 if (!lexed_comment) parser_lex_ignored_newline(parser);
10909 lex_state_set(parser, PM_LEX_STATE_BEG);
10910 parser->
current.start = next_content;
10911 parser->
current.end = next_content + 2;
10913 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
10918 if (peek_at(parser, next_content) ==
'|' && peek_at(parser, next_content + 1) ==
'|') {
10919 if (!lexed_comment) parser_lex_ignored_newline(parser);
10920 lex_state_set(parser, PM_LEX_STATE_BEG);
10921 parser->
current.start = next_content;
10922 parser->
current.end = next_content + 2;
10924 LEX(PM_TOKEN_PIPE_PIPE);
10930 peek_at(parser, next_content) ==
'a' &&
10931 peek_at(parser, next_content + 1) ==
'n' &&
10932 peek_at(parser, next_content + 2) ==
'd' &&
10933 !char_is_identifier(parser, next_content + 3, parser->
end - (next_content + 3))
10935 if (!lexed_comment) parser_lex_ignored_newline(parser);
10936 lex_state_set(parser, PM_LEX_STATE_BEG);
10937 parser->
current.start = next_content;
10938 parser->
current.end = next_content + 3;
10941 LEX(PM_TOKEN_KEYWORD_AND);
10947 peek_at(parser, next_content) ==
'o' &&
10948 peek_at(parser, next_content + 1) ==
'r' &&
10949 !char_is_identifier(parser, next_content + 2, parser->
end - (next_content + 2))
10951 if (!lexed_comment) parser_lex_ignored_newline(parser);
10952 lex_state_set(parser, PM_LEX_STATE_BEG);
10953 parser->
current.start = next_content;
10954 parser->
current.end = next_content + 2;
10957 LEX(PM_TOKEN_KEYWORD_OR);
10964 lex_state_set(parser, PM_LEX_STATE_BEG);
10966 parser->
current.type = PM_TOKEN_NEWLINE;
10967 if (!lexed_comment) parser_lex_callback(parser);
10977 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10978 LEX(PM_TOKEN_COMMA);
10982 pm_token_type_t
type = PM_TOKEN_PARENTHESIS_LEFT;
10984 if (space_seen && (lex_state_arg_p(parser) || parser->
lex_state == (PM_LEX_STATE_END | PM_LEX_STATE_LABEL))) {
10985 type = PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES;
10989 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10990 pm_do_loop_stack_push(parser,
false);
10997 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10998 pm_do_loop_stack_pop(parser);
10999 LEX(PM_TOKEN_PARENTHESIS_RIGHT);
11003 lex_state_set(parser, PM_LEX_STATE_BEG);
11005 LEX(PM_TOKEN_SEMICOLON);
11010 pm_token_type_t
type = PM_TOKEN_BRACKET_LEFT;
11012 if (lex_state_operator_p(parser)) {
11013 if (match(parser,
']')) {
11015 lex_state_set(parser, PM_LEX_STATE_ARG);
11016 LEX(match(parser,
'=') ? PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL : PM_TOKEN_BRACKET_LEFT_RIGHT);
11019 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABEL);
11023 if (lex_state_beg_p(parser) || (lex_state_arg_p(parser) && (space_seen || lex_state_p(parser, PM_LEX_STATE_LABELED)))) {
11024 type = PM_TOKEN_BRACKET_LEFT_ARRAY;
11027 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
11028 pm_do_loop_stack_push(parser,
false);
11034 lex_state_set(parser, PM_LEX_STATE_END);
11035 pm_do_loop_stack_pop(parser);
11036 LEX(PM_TOKEN_BRACKET_RIGHT);
11040 pm_token_type_t
type = PM_TOKEN_BRACE_LEFT;
11045 lex_state_set(parser, PM_LEX_STATE_BEG);
11046 type = PM_TOKEN_LAMBDA_BEGIN;
11047 }
else if (lex_state_p(parser, PM_LEX_STATE_LABELED)) {
11049 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
11050 }
else if (lex_state_p(parser, PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_END | PM_LEX_STATE_ENDFN)) {
11053 lex_state_set(parser, PM_LEX_STATE_BEG);
11054 }
else if (lex_state_p(parser, PM_LEX_STATE_ENDARG)) {
11057 lex_state_set(parser, PM_LEX_STATE_BEG);
11060 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
11065 pm_do_loop_stack_push(parser,
false);
11073 pm_do_loop_stack_pop(parser);
11076 lex_mode_pop(parser);
11077 LEX(PM_TOKEN_EMBEXPR_END);
11081 lex_state_set(parser, PM_LEX_STATE_END);
11082 LEX(PM_TOKEN_BRACE_RIGHT);
11086 if (match(parser,
'*')) {
11087 if (match(parser,
'=')) {
11088 lex_state_set(parser, PM_LEX_STATE_BEG);
11089 LEX(PM_TOKEN_STAR_STAR_EQUAL);
11092 pm_token_type_t
type = PM_TOKEN_STAR_STAR;
11094 if (lex_state_spcarg_p(parser, space_seen)) {
11095 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR_STAR);
11096 type = PM_TOKEN_USTAR_STAR;
11097 }
else if (lex_state_beg_p(parser)) {
11098 type = PM_TOKEN_USTAR_STAR;
11099 }
else if (ambiguous_operator_p(parser, space_seen)) {
11100 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"**",
"argument prefix");
11103 if (lex_state_operator_p(parser)) {
11104 lex_state_set(parser, PM_LEX_STATE_ARG);
11106 lex_state_set(parser, PM_LEX_STATE_BEG);
11112 if (match(parser,
'=')) {
11113 lex_state_set(parser, PM_LEX_STATE_BEG);
11114 LEX(PM_TOKEN_STAR_EQUAL);
11117 pm_token_type_t
type = PM_TOKEN_STAR;
11119 if (lex_state_spcarg_p(parser, space_seen)) {
11120 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR);
11121 type = PM_TOKEN_USTAR;
11122 }
else if (lex_state_beg_p(parser)) {
11123 type = PM_TOKEN_USTAR;
11124 }
else if (ambiguous_operator_p(parser, space_seen)) {
11125 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"*",
"argument prefix");
11128 if (lex_state_operator_p(parser)) {
11129 lex_state_set(parser, PM_LEX_STATE_ARG);
11131 lex_state_set(parser, PM_LEX_STATE_BEG);
11139 if (lex_state_operator_p(parser)) {
11140 lex_state_set(parser, PM_LEX_STATE_ARG);
11141 if (match(parser,
'@')) {
11142 LEX(PM_TOKEN_BANG);
11145 lex_state_set(parser, PM_LEX_STATE_BEG);
11148 if (match(parser,
'=')) {
11149 LEX(PM_TOKEN_BANG_EQUAL);
11152 if (match(parser,
'~')) {
11153 LEX(PM_TOKEN_BANG_TILDE);
11156 LEX(PM_TOKEN_BANG);
11161 current_token_starts_line(parser) &&
11163 memcmp(parser->
current.end,
"begin", 5) == 0 &&
11164 (pm_char_is_whitespace(peek_offset(parser, 5)) || (peek_offset(parser, 5) ==
'\0'))
11166 pm_token_type_t
type = lex_embdoc(parser);
11167 if (
type == PM_TOKEN_EOF) {
11171 goto lex_next_token;
11174 if (lex_state_operator_p(parser)) {
11175 lex_state_set(parser, PM_LEX_STATE_ARG);
11177 lex_state_set(parser, PM_LEX_STATE_BEG);
11180 if (match(parser,
'>')) {
11181 LEX(PM_TOKEN_EQUAL_GREATER);
11184 if (match(parser,
'~')) {
11185 LEX(PM_TOKEN_EQUAL_TILDE);
11188 if (match(parser,
'=')) {
11189 LEX(match(parser,
'=') ? PM_TOKEN_EQUAL_EQUAL_EQUAL : PM_TOKEN_EQUAL_EQUAL);
11192 LEX(PM_TOKEN_EQUAL);
11196 if (match(parser,
'<')) {
11198 !lex_state_p(parser, PM_LEX_STATE_DOT | PM_LEX_STATE_CLASS) &&
11199 !lex_state_end_p(parser) &&
11200 (!lex_state_p(parser, PM_LEX_STATE_ARG_ANY) || lex_state_p(parser, PM_LEX_STATE_LABELED) || space_seen)
11202 const uint8_t *end = parser->
current.end;
11207 if (match(parser,
'-')) {
11208 indent = PM_HEREDOC_INDENT_DASH;
11210 else if (match(parser,
'~')) {
11211 indent = PM_HEREDOC_INDENT_TILDE;
11214 if (match(parser,
'`')) {
11215 quote = PM_HEREDOC_QUOTE_BACKTICK;
11217 else if (match(parser,
'"')) {
11218 quote = PM_HEREDOC_QUOTE_DOUBLE;
11220 else if (match(parser,
'\'')) {
11221 quote = PM_HEREDOC_QUOTE_SINGLE;
11224 const uint8_t *ident_start = parser->
current.end;
11229 }
else if (quote == PM_HEREDOC_QUOTE_NONE && (width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) == 0) {
11232 if (quote == PM_HEREDOC_QUOTE_NONE) {
11233 parser->
current.end += width;
11235 while ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end))) {
11236 parser->
current.end += width;
11242 if (*parser->
current.end ==
'\r' || *parser->
current.end ==
'\n')
break;
11247 size_t ident_length = (size_t) (parser->
current.end - ident_start);
11248 bool ident_error =
false;
11250 if (quote != PM_HEREDOC_QUOTE_NONE && !match(parser, (uint8_t) quote)) {
11251 pm_parser_err(parser, ident_start, ident_start + ident_length, PM_ERR_HEREDOC_IDENTIFIER);
11252 ident_error =
true;
11257 .mode = PM_LEX_HEREDOC,
11260 .ident_start = ident_start,
11261 .ident_length = ident_length,
11265 .next_start = parser->
current.end,
11267 .line_continuation =
false
11272 const uint8_t *body_start = next_newline(parser->
current.end, parser->
end - parser->
current.end);
11274 if (body_start == NULL) {
11279 if (!ident_error) pm_parser_err_heredoc_term(parser, ident_start, ident_length);
11280 body_start = parser->
end;
11284 pm_newline_list_append(&parser->
newline_list, body_start);
11293 LEX(PM_TOKEN_HEREDOC_START);
11297 if (match(parser,
'=')) {
11298 lex_state_set(parser, PM_LEX_STATE_BEG);
11299 LEX(PM_TOKEN_LESS_LESS_EQUAL);
11302 if (ambiguous_operator_p(parser, space_seen)) {
11303 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"<<",
"here document");
11306 if (lex_state_operator_p(parser)) {
11307 lex_state_set(parser, PM_LEX_STATE_ARG);
11309 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
11310 lex_state_set(parser, PM_LEX_STATE_BEG);
11313 LEX(PM_TOKEN_LESS_LESS);
11316 if (lex_state_operator_p(parser)) {
11317 lex_state_set(parser, PM_LEX_STATE_ARG);
11319 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
11320 lex_state_set(parser, PM_LEX_STATE_BEG);
11323 if (match(parser,
'=')) {
11324 if (match(parser,
'>')) {
11325 LEX(PM_TOKEN_LESS_EQUAL_GREATER);
11328 LEX(PM_TOKEN_LESS_EQUAL);
11331 LEX(PM_TOKEN_LESS);
11335 if (match(parser,
'>')) {
11336 if (lex_state_operator_p(parser)) {
11337 lex_state_set(parser, PM_LEX_STATE_ARG);
11339 lex_state_set(parser, PM_LEX_STATE_BEG);
11341 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_GREATER_EQUAL : PM_TOKEN_GREATER_GREATER);
11344 if (lex_state_operator_p(parser)) {
11345 lex_state_set(parser, PM_LEX_STATE_ARG);
11347 lex_state_set(parser, PM_LEX_STATE_BEG);
11350 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_EQUAL : PM_TOKEN_GREATER);
11354 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
11355 lex_mode_push_string(parser,
true, label_allowed,
'\0',
'"');
11356 LEX(PM_TOKEN_STRING_BEGIN);
11361 if (lex_state_p(parser, PM_LEX_STATE_FNAME)) {
11362 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11363 LEX(PM_TOKEN_BACKTICK);
11366 if (lex_state_p(parser, PM_LEX_STATE_DOT)) {
11367 if (previous_command_start) {
11368 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11370 lex_state_set(parser, PM_LEX_STATE_ARG);
11373 LEX(PM_TOKEN_BACKTICK);
11376 lex_mode_push_string(parser,
true,
false,
'\0',
'`');
11377 LEX(PM_TOKEN_BACKTICK);
11382 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
11383 lex_mode_push_string(parser,
false, label_allowed,
'\0',
'\'');
11384 LEX(PM_TOKEN_STRING_BEGIN);
11389 LEX(lex_question_mark(parser));
11393 if (match(parser,
'&')) {
11394 lex_state_set(parser, PM_LEX_STATE_BEG);
11396 if (match(parser,
'=')) {
11397 LEX(PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
11400 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
11403 if (match(parser,
'=')) {
11404 lex_state_set(parser, PM_LEX_STATE_BEG);
11405 LEX(PM_TOKEN_AMPERSAND_EQUAL);
11408 if (match(parser,
'.')) {
11409 lex_state_set(parser, PM_LEX_STATE_DOT);
11410 LEX(PM_TOKEN_AMPERSAND_DOT);
11413 pm_token_type_t
type = PM_TOKEN_AMPERSAND;
11414 if (lex_state_spcarg_p(parser, space_seen)) {
11415 if ((peek(parser) !=
':') || (peek_offset(parser, 1) ==
'\0')) {
11416 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
11418 const uint8_t delim = peek_offset(parser, 1);
11420 if ((delim !=
'\'') && (delim !=
'"') && !char_is_identifier(parser, parser->
current.end + 1, parser->
end - (parser->
current.end + 1))) {
11421 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
11425 type = PM_TOKEN_UAMPERSAND;
11426 }
else if (lex_state_beg_p(parser)) {
11427 type = PM_TOKEN_UAMPERSAND;
11428 }
else if (ambiguous_operator_p(parser, space_seen)) {
11429 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"&",
"argument prefix");
11432 if (lex_state_operator_p(parser)) {
11433 lex_state_set(parser, PM_LEX_STATE_ARG);
11435 lex_state_set(parser, PM_LEX_STATE_BEG);
11443 if (match(parser,
'|')) {
11444 if (match(parser,
'=')) {
11445 lex_state_set(parser, PM_LEX_STATE_BEG);
11446 LEX(PM_TOKEN_PIPE_PIPE_EQUAL);
11449 if (lex_state_p(parser, PM_LEX_STATE_BEG)) {
11451 LEX(PM_TOKEN_PIPE);
11454 lex_state_set(parser, PM_LEX_STATE_BEG);
11455 LEX(PM_TOKEN_PIPE_PIPE);
11458 if (match(parser,
'=')) {
11459 lex_state_set(parser, PM_LEX_STATE_BEG);
11460 LEX(PM_TOKEN_PIPE_EQUAL);
11463 if (lex_state_operator_p(parser)) {
11464 lex_state_set(parser, PM_LEX_STATE_ARG);
11466 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
11469 LEX(PM_TOKEN_PIPE);
11473 if (lex_state_operator_p(parser)) {
11474 lex_state_set(parser, PM_LEX_STATE_ARG);
11476 if (match(parser,
'@')) {
11477 LEX(PM_TOKEN_UPLUS);
11480 LEX(PM_TOKEN_PLUS);
11483 if (match(parser,
'=')) {
11484 lex_state_set(parser, PM_LEX_STATE_BEG);
11485 LEX(PM_TOKEN_PLUS_EQUAL);
11489 lex_state_beg_p(parser) ||
11490 (lex_state_spcarg_p(parser, space_seen) ? (pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS),
true) : false)
11492 lex_state_set(parser, PM_LEX_STATE_BEG);
11494 if (pm_char_is_decimal_digit(peek(parser))) {
11496 pm_token_type_t
type = lex_numeric(parser);
11497 lex_state_set(parser, PM_LEX_STATE_END);
11501 LEX(PM_TOKEN_UPLUS);
11504 if (ambiguous_operator_p(parser, space_seen)) {
11505 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"+",
"unary operator");
11508 lex_state_set(parser, PM_LEX_STATE_BEG);
11509 LEX(PM_TOKEN_PLUS);
11514 if (lex_state_operator_p(parser)) {
11515 lex_state_set(parser, PM_LEX_STATE_ARG);
11517 if (match(parser,
'@')) {
11518 LEX(PM_TOKEN_UMINUS);
11521 LEX(PM_TOKEN_MINUS);
11524 if (match(parser,
'=')) {
11525 lex_state_set(parser, PM_LEX_STATE_BEG);
11526 LEX(PM_TOKEN_MINUS_EQUAL);
11529 if (match(parser,
'>')) {
11530 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11531 LEX(PM_TOKEN_MINUS_GREATER);
11534 bool spcarg = lex_state_spcarg_p(parser, space_seen);
11535 bool is_beg = lex_state_beg_p(parser);
11536 if (!is_beg && spcarg) {
11537 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS);
11540 if (is_beg || spcarg) {
11541 lex_state_set(parser, PM_LEX_STATE_BEG);
11542 LEX(pm_char_is_decimal_digit(peek(parser)) ? PM_TOKEN_UMINUS_NUM : PM_TOKEN_UMINUS);
11545 if (ambiguous_operator_p(parser, space_seen)) {
11546 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"-",
"unary operator");
11549 lex_state_set(parser, PM_LEX_STATE_BEG);
11550 LEX(PM_TOKEN_MINUS);
11555 bool beg_p = lex_state_beg_p(parser);
11557 if (match(parser,
'.')) {
11558 if (match(parser,
'.')) {
11561 if (lex_state_p(parser, PM_LEX_STATE_END)) {
11562 lex_state_set(parser, PM_LEX_STATE_BEG);
11564 lex_state_set(parser, PM_LEX_STATE_ENDARG);
11566 LEX(PM_TOKEN_UDOT_DOT_DOT);
11570 pm_parser_warn_token(parser, &parser->
current, PM_WARN_DOT_DOT_DOT_EOL);
11573 lex_state_set(parser, PM_LEX_STATE_BEG);
11574 LEX(beg_p ? PM_TOKEN_UDOT_DOT_DOT : PM_TOKEN_DOT_DOT_DOT);
11577 lex_state_set(parser, PM_LEX_STATE_BEG);
11578 LEX(beg_p ? PM_TOKEN_UDOT_DOT : PM_TOKEN_DOT_DOT);
11581 lex_state_set(parser, PM_LEX_STATE_DOT);
11596 pm_token_type_t
type = lex_numeric(parser);
11597 lex_state_set(parser, PM_LEX_STATE_END);
11603 if (match(parser,
':')) {
11604 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)) {
11605 lex_state_set(parser, PM_LEX_STATE_BEG);
11606 LEX(PM_TOKEN_UCOLON_COLON);
11609 lex_state_set(parser, PM_LEX_STATE_DOT);
11610 LEX(PM_TOKEN_COLON_COLON);
11613 if (lex_state_end_p(parser) || pm_char_is_whitespace(peek(parser)) || peek(parser) ==
'#') {
11614 lex_state_set(parser, PM_LEX_STATE_BEG);
11615 LEX(PM_TOKEN_COLON);
11618 if (peek(parser) ==
'"' || peek(parser) ==
'\'') {
11619 lex_mode_push_string(parser, peek(parser) ==
'"',
false,
'\0', *parser->
current.end);
11623 lex_state_set(parser, PM_LEX_STATE_FNAME);
11624 LEX(PM_TOKEN_SYMBOL_BEGIN);
11628 if (lex_state_beg_p(parser)) {
11629 lex_mode_push_regexp(parser,
'\0',
'/');
11630 LEX(PM_TOKEN_REGEXP_BEGIN);
11633 if (match(parser,
'=')) {
11634 lex_state_set(parser, PM_LEX_STATE_BEG);
11635 LEX(PM_TOKEN_SLASH_EQUAL);
11638 if (lex_state_spcarg_p(parser, space_seen)) {
11639 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_SLASH);
11640 lex_mode_push_regexp(parser,
'\0',
'/');
11641 LEX(PM_TOKEN_REGEXP_BEGIN);
11644 if (ambiguous_operator_p(parser, space_seen)) {
11645 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"/",
"regexp literal");
11648 if (lex_state_operator_p(parser)) {
11649 lex_state_set(parser, PM_LEX_STATE_ARG);
11651 lex_state_set(parser, PM_LEX_STATE_BEG);
11654 LEX(PM_TOKEN_SLASH);
11658 if (lex_state_operator_p(parser)) {
11659 lex_state_set(parser, PM_LEX_STATE_ARG);
11661 lex_state_set(parser, PM_LEX_STATE_BEG);
11663 LEX(match(parser,
'=') ? PM_TOKEN_CARET_EQUAL : PM_TOKEN_CARET);
11667 if (lex_state_operator_p(parser)) {
11668 (void) match(parser,
'@');
11669 lex_state_set(parser, PM_LEX_STATE_ARG);
11671 lex_state_set(parser, PM_LEX_STATE_BEG);
11674 LEX(PM_TOKEN_TILDE);
11682 if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->
current.end >= parser->
end)) {
11683 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT_EOF);
11684 LEX(PM_TOKEN_PERCENT);
11687 if (!lex_state_beg_p(parser) && match(parser,
'=')) {
11688 lex_state_set(parser, PM_LEX_STATE_BEG);
11689 LEX(PM_TOKEN_PERCENT_EQUAL);
11691 lex_state_beg_p(parser) ||
11692 (lex_state_p(parser, PM_LEX_STATE_FITEM) && (peek(parser) ==
's')) ||
11693 lex_state_spcarg_p(parser, space_seen)
11696 if (*parser->
current.end >= 0x80) {
11697 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11700 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11701 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11702 LEX(PM_TOKEN_STRING_BEGIN);
11707 uint8_t delimiter = peek_offset(parser, 1);
11709 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11710 goto lex_next_token;
11713 switch (peek(parser)) {
11718 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11720 lex_mode_push_list_eof(parser);
11723 LEX(PM_TOKEN_PERCENT_LOWER_I);
11729 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11731 lex_mode_push_list_eof(parser);
11734 LEX(PM_TOKEN_PERCENT_UPPER_I);
11740 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11741 lex_mode_push_regexp(parser, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11743 lex_mode_push_regexp(parser,
'\0',
'\0');
11746 LEX(PM_TOKEN_REGEXP_BEGIN);
11752 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11753 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11755 lex_mode_push_string_eof(parser);
11758 LEX(PM_TOKEN_STRING_BEGIN);
11764 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11765 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11767 lex_mode_push_string_eof(parser);
11770 LEX(PM_TOKEN_STRING_BEGIN);
11776 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11777 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11778 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
11780 lex_mode_push_string_eof(parser);
11783 LEX(PM_TOKEN_SYMBOL_BEGIN);
11789 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11791 lex_mode_push_list_eof(parser);
11794 LEX(PM_TOKEN_PERCENT_LOWER_W);
11800 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11802 lex_mode_push_list_eof(parser);
11805 LEX(PM_TOKEN_PERCENT_UPPER_W);
11811 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11812 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11814 lex_mode_push_string_eof(parser);
11817 LEX(PM_TOKEN_PERCENT_LOWER_X);
11824 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11825 goto lex_next_token;
11829 if (ambiguous_operator_p(parser, space_seen)) {
11830 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"%",
"string literal");
11833 lex_state_set(parser, lex_state_operator_p(parser) ? PM_LEX_STATE_ARG : PM_LEX_STATE_BEG);
11834 LEX(PM_TOKEN_PERCENT);
11839 pm_token_type_t
type = lex_global_variable(parser);
11844 lex_mode_pop(parser);
11847 lex_state_set(parser, PM_LEX_STATE_END);
11853 lex_state_set(parser, parser->
lex_state & PM_LEX_STATE_FNAME ? PM_LEX_STATE_ENDFN : PM_LEX_STATE_END);
11854 LEX(lex_at_variable(parser));
11857 if (*parser->
current.start !=
'_') {
11858 size_t width = char_is_identifier_start(parser, parser->
current.start, parser->
end - parser->
current.start);
11865 if (*parser->
current.start >= 0x80) {
11866 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *parser->
current.start);
11867 }
else if (*parser->
current.start ==
'\\') {
11868 switch (peek_at(parser, parser->
current.start + 1)) {
11871 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped space");
11875 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped form feed");
11879 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped horizontal tab");
11883 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped vertical tab");
11886 if (peek_at(parser, parser->
current.start + 2) !=
'\n') {
11888 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped carriage return");
11893 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"backslash");
11896 }
else if (char_is_ascii_printable(*parser->
current.start)) {
11897 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_PRINTABLE_CHARACTER, *parser->
current.start);
11899 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_CHARACTER, *parser->
current.start);
11902 goto lex_next_token;
11908 pm_token_type_t
type = lex_identifier(parser, previous_command_start);
11916 current_token_starts_line(parser) &&
11917 (memcmp(parser->
current.start,
"__END__", 7) == 0) &&
11918 (parser->
current.end == parser->
end || match_eol(parser))
11923 const uint8_t *cursor = parser->
current.end;
11924 while ((cursor = next_newline(cursor, parser->
end - cursor)) != NULL) {
11925 pm_newline_list_append(&parser->
newline_list, cursor++);
11929 parser->
current.type = PM_TOKEN___END__;
11930 parser_lex_callback(parser);
11940 if (
type == PM_TOKEN_IDENTIFIER ||
type == PM_TOKEN_CONSTANT ||
type == PM_TOKEN_METHOD_NAME) {
11941 if (lex_state_p(parser, PM_LEX_STATE_BEG_ANY | PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_DOT)) {
11942 if (previous_command_start) {
11943 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11945 lex_state_set(parser, PM_LEX_STATE_ARG);
11947 }
else if (parser->
lex_state == PM_LEX_STATE_FNAME) {
11948 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11950 lex_state_set(parser, PM_LEX_STATE_END);
11955 !(last_state & (PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME)) &&
11956 (
type == PM_TOKEN_IDENTIFIER) &&
11957 ((pm_parser_local_depth(parser, &parser->
current) != -1) ||
11958 pm_token_is_numbered_parameter(parser->
current.start, parser->
current.end))
11960 lex_state_set(parser, PM_LEX_STATE_END | PM_LEX_STATE_LABEL);
11967 case PM_LEX_LIST: {
11981 whitespace = pm_strspn_inline_whitespace(parser->
current.end, parser->
end - parser->
current.end);
11982 if (peek_offset(parser, (ptrdiff_t)whitespace) ==
'\n') {
11989 if (whitespace > 0) {
11990 parser->
current.end += whitespace;
11991 if (peek_offset(parser, -1) ==
'\n') {
11993 parser_flush_heredoc_end(parser);
11995 LEX(PM_TOKEN_WORDS_SEP);
12007 const uint8_t *breakpoints = lex_mode->
as.list.
breakpoints;
12008 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12014 while (breakpoint != NULL) {
12017 if (pm_char_is_whitespace(*breakpoint)) {
12018 parser->
current.end = breakpoint;
12019 pm_token_buffer_flush(parser, &token_buffer);
12020 LEX(PM_TOKEN_STRING_CONTENT);
12029 parser->
current.end = breakpoint + 1;
12030 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12037 if (breakpoint > parser->
current.start) {
12038 parser->
current.end = breakpoint;
12039 pm_token_buffer_flush(parser, &token_buffer);
12040 LEX(PM_TOKEN_STRING_CONTENT);
12045 parser->
current.end = breakpoint + 1;
12046 lex_mode_pop(parser);
12047 lex_state_set(parser, PM_LEX_STATE_END);
12048 LEX(PM_TOKEN_STRING_END);
12052 if (*breakpoint ==
'\0') {
12053 breakpoint = pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->
end - (breakpoint + 1),
true);
12060 if (*breakpoint ==
'\\') {
12061 parser->
current.end = breakpoint + 1;
12070 pm_token_buffer_escape(parser, &token_buffer);
12071 uint8_t peeked = peek(parser);
12079 pm_token_buffer_push_byte(&token_buffer, peeked);
12084 if (peek(parser) !=
'\n') {
12085 pm_token_buffer_push_byte(&token_buffer,
'\r');
12090 pm_token_buffer_push_byte(&token_buffer,
'\n');
12096 parser_flush_heredoc_end(parser);
12097 pm_token_buffer_copy(parser, &token_buffer);
12098 LEX(PM_TOKEN_STRING_CONTENT);
12108 pm_token_buffer_push_byte(&token_buffer, peeked);
12111 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12113 pm_token_buffer_push_byte(&token_buffer,
'\\');
12114 pm_token_buffer_push_escaped(&token_buffer, parser);
12121 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12126 if (*breakpoint ==
'#') {
12127 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12129 if (
type == PM_TOKEN_NOT_PROVIDED) {
12134 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12138 if (
type == PM_TOKEN_STRING_CONTENT) {
12139 pm_token_buffer_flush(parser, &token_buffer);
12148 parser->
current.end = breakpoint + 1;
12149 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12155 pm_token_buffer_flush(parser, &token_buffer);
12156 LEX(PM_TOKEN_STRING_CONTENT);
12162 pm_token_buffer_flush(parser, &token_buffer);
12163 LEX(PM_TOKEN_STRING_CONTENT);
12165 case PM_LEX_REGEXP: {
12187 const uint8_t *breakpoints = lex_mode->
as.regexp.
breakpoints;
12188 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12191 while (breakpoint != NULL) {
12193 bool is_terminator = (*breakpoint == term);
12198 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
12199 if (term ==
'\n') {
12200 is_terminator =
true;
12206 if (term ==
'\r') {
12207 is_terminator =
false;
12213 if (is_terminator) {
12215 parser->
current.end = breakpoint + 1;
12216 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12224 if (breakpoint > parser->
current.start) {
12225 parser->
current.end = breakpoint;
12226 pm_regexp_token_buffer_flush(parser, &token_buffer);
12227 LEX(PM_TOKEN_STRING_CONTENT);
12231 size_t eol_length = match_eol_at(parser, breakpoint);
12233 parser->
current.end = breakpoint + eol_length;
12236 parser->
current.end = breakpoint + 1;
12243 lex_mode_pop(parser);
12244 lex_state_set(parser, PM_LEX_STATE_END);
12245 LEX(PM_TOKEN_REGEXP_END);
12250 if (*breakpoint && *breakpoint == lex_mode->
as.regexp.
incrementor) {
12251 parser->
current.end = breakpoint + 1;
12252 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12257 switch (*breakpoint) {
12260 parser->
current.end = breakpoint + 1;
12261 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12264 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12265 parser->
current.end = breakpoint + 1;
12266 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12271 parser->
current.end = breakpoint;
12272 pm_regexp_token_buffer_escape(parser, &token_buffer);
12280 pm_newline_list_append(&parser->
newline_list, breakpoint);
12281 parser->
current.end = breakpoint + 1;
12282 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12286 parser->
current.end = breakpoint + 1;
12287 parser_flush_heredoc_end(parser);
12288 pm_regexp_token_buffer_flush(parser, &token_buffer);
12289 LEX(PM_TOKEN_STRING_CONTENT);
12294 parser->
current.end = breakpoint + 1;
12303 pm_regexp_token_buffer_escape(parser, &token_buffer);
12304 uint8_t peeked = peek(parser);
12309 if (peek(parser) !=
'\n') {
12311 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12313 pm_regexp_token_buffer_push_byte(&token_buffer,
'\r');
12314 pm_token_buffer_push_byte(&token_buffer.
base,
'\r');
12323 parser_flush_heredoc_end(parser);
12324 pm_regexp_token_buffer_copy(parser, &token_buffer);
12325 LEX(PM_TOKEN_STRING_CONTENT);
12346 case '$':
case ')':
case '*':
case '+':
12347 case '.':
case '>':
case '?':
case ']':
12348 case '^':
case '|':
case '}':
12349 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12355 pm_regexp_token_buffer_push_byte(&token_buffer, peeked);
12356 pm_token_buffer_push_byte(&token_buffer.
base, peeked);
12361 if (peeked < 0x80) pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12362 pm_regexp_token_buffer_push_escaped(&token_buffer, parser);
12367 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12373 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12375 if (
type == PM_TOKEN_NOT_PROVIDED) {
12380 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12384 if (
type == PM_TOKEN_STRING_CONTENT) {
12385 pm_regexp_token_buffer_flush(parser, &token_buffer);
12391 assert(
false &&
"unreachable");
12397 pm_regexp_token_buffer_flush(parser, &token_buffer);
12398 LEX(PM_TOKEN_STRING_CONTENT);
12404 pm_regexp_token_buffer_flush(parser, &token_buffer);
12405 LEX(PM_TOKEN_STRING_CONTENT);
12407 case PM_LEX_STRING: {
12426 const uint8_t *breakpoints = lex_mode->
as.string.
breakpoints;
12427 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12433 while (breakpoint != NULL) {
12438 parser->
current.end = breakpoint + 1;
12439 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12444 bool is_terminator = (*breakpoint == term);
12449 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
12450 if (term ==
'\n') {
12451 is_terminator =
true;
12457 if (term ==
'\r') {
12458 is_terminator =
false;
12465 if (is_terminator) {
12469 parser->
current.end = breakpoint + 1;
12470 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12477 if (breakpoint > parser->
current.start) {
12478 parser->
current.end = breakpoint;
12479 pm_token_buffer_flush(parser, &token_buffer);
12480 LEX(PM_TOKEN_STRING_CONTENT);
12485 size_t eol_length = match_eol_at(parser, breakpoint);
12487 parser->
current.end = breakpoint + eol_length;
12490 parser->
current.end = breakpoint + 1;
12493 if (lex_mode->
as.string.
label_allowed && (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')) {
12495 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
12496 lex_mode_pop(parser);
12497 LEX(PM_TOKEN_LABEL_END);
12500 lex_state_set(parser, PM_LEX_STATE_END);
12501 lex_mode_pop(parser);
12502 LEX(PM_TOKEN_STRING_END);
12505 switch (*breakpoint) {
12508 parser->
current.end = breakpoint + 1;
12509 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12512 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12513 parser->
current.end = breakpoint + 1;
12514 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12521 parser->
current.end = breakpoint;
12522 pm_token_buffer_escape(parser, &token_buffer);
12523 token_buffer.
cursor = breakpoint;
12532 pm_newline_list_append(&parser->
newline_list, breakpoint);
12533 parser->
current.end = breakpoint + 1;
12534 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12538 parser->
current.end = breakpoint + 1;
12539 parser_flush_heredoc_end(parser);
12540 pm_token_buffer_flush(parser, &token_buffer);
12541 LEX(PM_TOKEN_STRING_CONTENT);
12544 parser->
current.end = breakpoint + 1;
12553 pm_token_buffer_escape(parser, &token_buffer);
12554 uint8_t peeked = peek(parser);
12558 pm_token_buffer_push_byte(&token_buffer,
'\\');
12563 if (peek(parser) !=
'\n') {
12565 pm_token_buffer_push_byte(&token_buffer,
'\\');
12567 pm_token_buffer_push_byte(&token_buffer,
'\r');
12573 pm_token_buffer_push_byte(&token_buffer,
'\\');
12574 pm_token_buffer_push_byte(&token_buffer,
'\n');
12581 parser_flush_heredoc_end(parser);
12582 pm_token_buffer_copy(parser, &token_buffer);
12583 LEX(PM_TOKEN_STRING_CONTENT);
12593 pm_token_buffer_push_byte(&token_buffer, peeked);
12596 pm_token_buffer_push_byte(&token_buffer, peeked);
12599 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12601 pm_token_buffer_push_byte(&token_buffer,
'\\');
12602 pm_token_buffer_push_escaped(&token_buffer, parser);
12609 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12613 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12615 if (
type == PM_TOKEN_NOT_PROVIDED) {
12620 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12624 if (
type == PM_TOKEN_STRING_CONTENT) {
12625 pm_token_buffer_flush(parser, &token_buffer);
12631 assert(
false &&
"unreachable");
12636 pm_token_buffer_flush(parser, &token_buffer);
12637 LEX(PM_TOKEN_STRING_CONTENT);
12643 pm_token_buffer_flush(parser, &token_buffer);
12644 LEX(PM_TOKEN_STRING_CONTENT);
12646 case PM_LEX_HEREDOC: {
12673 lex_state_set(parser, PM_LEX_STATE_END);
12674 lex_mode_pop(parser);
12675 LEX(PM_TOKEN_HEREDOC_END);
12678 const uint8_t *ident_start = heredoc_lex_mode->
ident_start;
12683 if (current_token_starts_line(parser)) {
12684 const uint8_t *start = parser->
current.start;
12686 if (!line_continuation && (start + ident_length <= parser->end)) {
12687 const uint8_t *newline = next_newline(start, parser->
end - start);
12688 const uint8_t *ident_end = newline;
12689 const uint8_t *terminator_end = newline;
12691 if (newline == NULL) {
12692 terminator_end = parser->
end;
12693 ident_end = parser->
end;
12696 if (newline[-1] ==
'\r') {
12701 const uint8_t *terminator_start = ident_end - ident_length;
12702 const uint8_t *cursor = start;
12704 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12705 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12711 (cursor == terminator_start) &&
12712 (memcmp(terminator_start, ident_start, ident_length) == 0)
12714 if (newline != NULL) {
12715 pm_newline_list_append(&parser->
newline_list, newline);
12718 parser->
current.end = terminator_end;
12726 lex_state_set(parser, PM_LEX_STATE_END);
12727 lex_mode_pop(parser);
12728 LEX(PM_TOKEN_HEREDOC_END);
12732 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, heredoc_lex_mode->
indent);
12734 heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE &&
12737 peek_at(parser, start) !=
'\n'
12746 uint8_t breakpoints[] =
"\r\n\\#";
12749 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12750 breakpoints[3] =
'\0';
12753 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12755 bool was_line_continuation =
false;
12757 while (breakpoint != NULL) {
12758 switch (*breakpoint) {
12761 parser->
current.end = breakpoint + 1;
12762 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12765 parser->
current.end = breakpoint + 1;
12767 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12768 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12775 pm_token_buffer_escape(parser, &token_buffer);
12776 token_buffer.
cursor = breakpoint;
12781 parser_flush_heredoc_end(parser);
12782 parser->
current.end = breakpoint + 1;
12783 pm_token_buffer_flush(parser, &token_buffer);
12784 LEX(PM_TOKEN_STRING_CONTENT);
12787 pm_newline_list_append(&parser->
newline_list, breakpoint);
12791 const uint8_t *start = breakpoint + 1;
12793 if (!was_line_continuation && (start + ident_length <= parser->end)) {
12796 const uint8_t *newline = next_newline(start, parser->
end - start);
12798 if (newline == NULL) {
12799 newline = parser->
end;
12800 }
else if (newline[-1] ==
'\r') {
12805 const uint8_t *terminator_start = newline - ident_length;
12809 const uint8_t *cursor = start;
12811 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12812 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12818 cursor == terminator_start &&
12819 (memcmp(terminator_start, ident_start, ident_length) == 0)
12821 parser->
current.end = breakpoint + 1;
12822 pm_token_buffer_flush(parser, &token_buffer);
12823 LEX(PM_TOKEN_STRING_CONTENT);
12827 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->
as.heredoc.
base.
indent);
12834 if (lex_mode->
as.heredoc.
base.
indent == PM_HEREDOC_INDENT_TILDE) {
12839 parser->
current.end = breakpoint + 1;
12840 pm_token_buffer_flush(parser, &token_buffer);
12841 LEX(PM_TOKEN_STRING_CONTENT);
12846 parser->
current.end = breakpoint + 1;
12847 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12857 parser->
current.end = breakpoint + 1;
12866 pm_token_buffer_escape(parser, &token_buffer);
12867 uint8_t peeked = peek(parser);
12869 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12873 if (peek(parser) !=
'\n') {
12874 pm_token_buffer_push_byte(&token_buffer,
'\\');
12875 pm_token_buffer_push_byte(&token_buffer,
'\r');
12880 pm_token_buffer_push_byte(&token_buffer,
'\\');
12881 pm_token_buffer_push_byte(&token_buffer,
'\n');
12883 breakpoint = parser->
current.end;
12886 pm_token_buffer_push_byte(&token_buffer,
'\\');
12887 pm_token_buffer_push_escaped(&token_buffer, parser);
12894 if (peek(parser) !=
'\n') {
12895 pm_token_buffer_push_byte(&token_buffer,
'\r');
12903 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12904 const uint8_t *end = parser->
current.end;
12909 parser->
current.end = breakpoint;
12910 pm_token_buffer_flush(parser, &token_buffer);
12914 parser->
current.end = end + 1;
12916 LEX(PM_TOKEN_STRING_CONTENT);
12919 was_line_continuation =
true;
12921 breakpoint = parser->
current.end;
12924 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12930 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12934 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12936 if (
type == PM_TOKEN_NOT_PROVIDED) {
12942 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12946 if (
type == PM_TOKEN_STRING_CONTENT) {
12947 pm_token_buffer_flush(parser, &token_buffer);
12953 assert(
false &&
"unreachable");
12956 was_line_continuation =
false;
12961 pm_token_buffer_flush(parser, &token_buffer);
12962 LEX(PM_TOKEN_STRING_CONTENT);
12968 pm_token_buffer_flush(parser, &token_buffer);
12969 LEX(PM_TOKEN_STRING_CONTENT);
12973 assert(
false &&
"unreachable");
12991 PM_BINDING_POWER_UNSET = 0,
12992 PM_BINDING_POWER_STATEMENT = 2,
12993 PM_BINDING_POWER_MODIFIER_RESCUE = 4,
12994 PM_BINDING_POWER_MODIFIER = 6,
12995 PM_BINDING_POWER_COMPOSITION = 8,
12996 PM_BINDING_POWER_NOT = 10,
12997 PM_BINDING_POWER_MATCH = 12,
12998 PM_BINDING_POWER_DEFINED = 14,
12999 PM_BINDING_POWER_MULTI_ASSIGNMENT = 16,
13000 PM_BINDING_POWER_ASSIGNMENT = 18,
13001 PM_BINDING_POWER_TERNARY = 20,
13002 PM_BINDING_POWER_RANGE = 22,
13003 PM_BINDING_POWER_LOGICAL_OR = 24,
13004 PM_BINDING_POWER_LOGICAL_AND = 26,
13005 PM_BINDING_POWER_EQUALITY = 28,
13006 PM_BINDING_POWER_COMPARISON = 30,
13007 PM_BINDING_POWER_BITWISE_OR = 32,
13008 PM_BINDING_POWER_BITWISE_AND = 34,
13009 PM_BINDING_POWER_SHIFT = 36,
13010 PM_BINDING_POWER_TERM = 38,
13011 PM_BINDING_POWER_FACTOR = 40,
13012 PM_BINDING_POWER_UMINUS = 42,
13013 PM_BINDING_POWER_EXPONENT = 44,
13014 PM_BINDING_POWER_UNARY = 46,
13015 PM_BINDING_POWER_INDEX = 48,
13016 PM_BINDING_POWER_CALL = 50,
13017 PM_BINDING_POWER_MAX = 52
13018} pm_binding_power_t;
13041#define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true, false }
13042#define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, false }
13043#define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true, false }
13044#define NON_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, true }
13045#define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false, false }
13049 [PM_TOKEN_KEYWORD_RESCUE_MODIFIER] = { PM_BINDING_POWER_MODIFIER_RESCUE, PM_BINDING_POWER_COMPOSITION,
true,
false },
13052 [PM_TOKEN_KEYWORD_IF_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
13053 [PM_TOKEN_KEYWORD_UNLESS_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
13054 [PM_TOKEN_KEYWORD_UNTIL_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
13055 [PM_TOKEN_KEYWORD_WHILE_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
13058 [PM_TOKEN_KEYWORD_AND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
13059 [PM_TOKEN_KEYWORD_OR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
13062 [PM_TOKEN_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
13063 [PM_TOKEN_KEYWORD_IN] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
13066 [PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
13067 [PM_TOKEN_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
13068 [PM_TOKEN_CARET_EQUAL] = BINDING_POWER_ASSIGNMENT,
13069 [PM_TOKEN_EQUAL] = BINDING_POWER_ASSIGNMENT,
13070 [PM_TOKEN_GREATER_GREATER_EQUAL] = BINDING_POWER_ASSIGNMENT,
13071 [PM_TOKEN_LESS_LESS_EQUAL] = BINDING_POWER_ASSIGNMENT,
13072 [PM_TOKEN_MINUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
13073 [PM_TOKEN_PERCENT_EQUAL] = BINDING_POWER_ASSIGNMENT,
13074 [PM_TOKEN_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
13075 [PM_TOKEN_PIPE_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
13076 [PM_TOKEN_PLUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
13077 [PM_TOKEN_SLASH_EQUAL] = BINDING_POWER_ASSIGNMENT,
13078 [PM_TOKEN_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
13079 [PM_TOKEN_STAR_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
13082 [PM_TOKEN_QUESTION_MARK] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_TERNARY),
13085 [PM_TOKEN_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
13086 [PM_TOKEN_DOT_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
13087 [PM_TOKEN_UDOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
13088 [PM_TOKEN_UDOT_DOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
13091 [PM_TOKEN_PIPE_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_OR),
13094 [PM_TOKEN_AMPERSAND_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_AND),
13097 [PM_TOKEN_BANG_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
13098 [PM_TOKEN_BANG_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
13099 [PM_TOKEN_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
13100 [PM_TOKEN_EQUAL_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
13101 [PM_TOKEN_EQUAL_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
13102 [PM_TOKEN_LESS_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
13105 [PM_TOKEN_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
13106 [PM_TOKEN_GREATER_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
13107 [PM_TOKEN_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
13108 [PM_TOKEN_LESS_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
13111 [PM_TOKEN_CARET] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
13112 [PM_TOKEN_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
13115 [PM_TOKEN_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_AND),
13118 [PM_TOKEN_GREATER_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
13119 [PM_TOKEN_LESS_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
13122 [PM_TOKEN_MINUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
13123 [PM_TOKEN_PLUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
13126 [PM_TOKEN_PERCENT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
13127 [PM_TOKEN_SLASH] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
13128 [PM_TOKEN_STAR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
13129 [PM_TOKEN_USTAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_FACTOR),
13132 [PM_TOKEN_UMINUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UMINUS),
13133 [PM_TOKEN_UMINUS_NUM] = { PM_BINDING_POWER_UMINUS, PM_BINDING_POWER_MAX,
false,
false },
13136 [PM_TOKEN_STAR_STAR] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_EXPONENT),
13137 [PM_TOKEN_USTAR_STAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13140 [PM_TOKEN_BANG] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13141 [PM_TOKEN_TILDE] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13142 [PM_TOKEN_UPLUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13145 [PM_TOKEN_BRACKET_LEFT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_INDEX),
13148 [PM_TOKEN_COLON_COLON] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
13149 [PM_TOKEN_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
13150 [PM_TOKEN_AMPERSAND_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL)
13153#undef BINDING_POWER_ASSIGNMENT
13154#undef LEFT_ASSOCIATIVE
13155#undef RIGHT_ASSOCIATIVE
13156#undef RIGHT_ASSOCIATIVE_UNARY
13170match2(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
13171 return match1(parser, type1) || match1(parser, type2);
13178match3(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3) {
13179 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3);
13186match4(
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) {
13187 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4);
13194match7(
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) {
13195 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7);
13202match8(
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) {
13203 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);
13214 if (match1(parser,
type)) {
13215 parser_lex(parser);
13226accept2(
pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
13227 if (match2(parser, type1, type2)) {
13228 parser_lex(parser);
13247 if (accept1(parser,
type))
return;
13250 pm_parser_err(parser, location, location, diag_id);
13262 if (accept2(parser, type1, type2))
return;
13265 pm_parser_err(parser, location, location, diag_id);
13276expect1_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
13277 if (match1(parser, PM_TOKEN_HEREDOC_END)) {
13278 parser_lex(parser);
13280 pm_parser_err_heredoc_term(parser, ident_start, ident_length);
13287parse_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);
13294parse_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) {
13295 pm_node_t *node = parse_expression(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
13296 pm_assert_value_expression(parser, node);
13319token_begins_expression_p(pm_token_type_t
type) {
13321 case PM_TOKEN_EQUAL_GREATER:
13322 case PM_TOKEN_KEYWORD_IN:
13326 case PM_TOKEN_BRACE_RIGHT:
13327 case PM_TOKEN_BRACKET_RIGHT:
13328 case PM_TOKEN_COLON:
13329 case PM_TOKEN_COMMA:
13330 case PM_TOKEN_EMBEXPR_END:
13332 case PM_TOKEN_LAMBDA_BEGIN:
13333 case PM_TOKEN_KEYWORD_DO:
13334 case PM_TOKEN_KEYWORD_DO_LOOP:
13335 case PM_TOKEN_KEYWORD_END:
13336 case PM_TOKEN_KEYWORD_ELSE:
13337 case PM_TOKEN_KEYWORD_ELSIF:
13338 case PM_TOKEN_KEYWORD_ENSURE:
13339 case PM_TOKEN_KEYWORD_THEN:
13340 case PM_TOKEN_KEYWORD_RESCUE:
13341 case PM_TOKEN_KEYWORD_WHEN:
13342 case PM_TOKEN_NEWLINE:
13343 case PM_TOKEN_PARENTHESIS_RIGHT:
13344 case PM_TOKEN_SEMICOLON:
13350 assert(pm_binding_powers[
type].left == PM_BINDING_POWER_UNSET);
13352 case PM_TOKEN_UAMPERSAND:
13356 case PM_TOKEN_UCOLON_COLON:
13357 case PM_TOKEN_UMINUS:
13358 case PM_TOKEN_UMINUS_NUM:
13359 case PM_TOKEN_UPLUS:
13360 case PM_TOKEN_BANG:
13361 case PM_TOKEN_TILDE:
13362 case PM_TOKEN_UDOT_DOT:
13363 case PM_TOKEN_UDOT_DOT_DOT:
13370 return pm_binding_powers[
type].
left == PM_BINDING_POWER_UNSET;
13379parse_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) {
13380 if (accept1(parser, PM_TOKEN_USTAR)) {
13382 pm_node_t *expression = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13383 return (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
13386 return parse_value_expression(parser, binding_power, accepts_command_call,
false, diag_id, depth);
13400 size_t length = constant->
length;
13401 uint8_t *name =
xcalloc(length + 1,
sizeof(uint8_t));
13402 if (name == NULL)
return;
13404 memcpy(name, constant->
start, length);
13405 name[length] =
'=';
13410 *name_field = pm_constant_pool_insert_owned(&parser->
constant_pool, name, length + 1);
13421 switch (PM_NODE_TYPE(target)) {
13422 case PM_SOURCE_ENCODING_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13423 case PM_FALSE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13424 case PM_SOURCE_FILE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13425 case PM_SOURCE_LINE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13426 case PM_NIL_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13427 case PM_SELF_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13428 case PM_TRUE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13435 pm_node_destroy(parser, target);
13448 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
13449 if (implicit_parameters->
nodes[index] == node) {
13453 if (index != implicit_parameters->
size - 1) {
13454 memcpy(&implicit_parameters->
nodes[index], &implicit_parameters->
nodes[index + 1], (implicit_parameters->
size - index - 1) *
sizeof(
pm_node_t *));
13457 implicit_parameters->
size--;
13473 switch (PM_NODE_TYPE(target)) {
13474 case PM_MISSING_NODE:
13476 case PM_SOURCE_ENCODING_NODE:
13477 case PM_FALSE_NODE:
13478 case PM_SOURCE_FILE_NODE:
13479 case PM_SOURCE_LINE_NODE:
13482 case PM_TRUE_NODE: {
13485 return parse_unwriteable_target(parser, target);
13487 case PM_CLASS_VARIABLE_READ_NODE:
13489 target->
type = PM_CLASS_VARIABLE_TARGET_NODE;
13491 case PM_CONSTANT_PATH_NODE:
13492 if (context_def_p(parser)) {
13493 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13497 target->
type = PM_CONSTANT_PATH_TARGET_NODE;
13500 case PM_CONSTANT_READ_NODE:
13501 if (context_def_p(parser)) {
13502 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13506 target->
type = PM_CONSTANT_TARGET_NODE;
13509 case PM_BACK_REFERENCE_READ_NODE:
13510 case PM_NUMBERED_REFERENCE_READ_NODE:
13511 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13513 case PM_GLOBAL_VARIABLE_READ_NODE:
13515 target->
type = PM_GLOBAL_VARIABLE_TARGET_NODE;
13517 case PM_LOCAL_VARIABLE_READ_NODE: {
13520 parse_target_implicit_parameter(parser, target);
13524 uint32_t name = cast->
name;
13525 uint32_t depth = cast->
depth;
13526 pm_locals_unread(&pm_parser_scope_find(parser, depth)->locals, name);
13529 target->
type = PM_LOCAL_VARIABLE_TARGET_NODE;
13533 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
13537 parse_target_implicit_parameter(parser, target);
13538 pm_node_destroy(parser, target);
13542 case PM_INSTANCE_VARIABLE_READ_NODE:
13544 target->
type = PM_INSTANCE_VARIABLE_TARGET_NODE;
13546 case PM_MULTI_TARGET_NODE:
13547 if (splat_parent) {
13550 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13554 case PM_SPLAT_NODE: {
13563 case PM_CALL_NODE: {
13575 (call->
block == NULL)
13590 pm_node_destroy(parser, target);
13592 return (
pm_node_t *) pm_local_variable_target_node_create(parser, &message_loc, name, 0);
13596 if (multiple && PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
13597 pm_parser_err_node(parser, (
const pm_node_t *) call, PM_ERR_UNEXPECTED_SAFE_NAVIGATION);
13600 parse_write_name(parser, &call->
name);
13601 return (
pm_node_t *) pm_call_target_node_create(parser, call);
13608 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
13609 return (
pm_node_t *) pm_index_target_node_create(parser, call);
13617 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13628 pm_node_t *result = parse_target(parser, target, multiple,
false);
13633 !match1(parser, PM_TOKEN_EQUAL) &&
13635 !(context_p(parser,
PM_CONTEXT_PARENS) && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
13637 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13651 if (shareable_constant != PM_SCOPE_SHAREABLE_CONSTANT_NONE) {
13652 return (
pm_node_t *) pm_shareable_constant_node_create(parser, write, shareable_constant);
13663 switch (PM_NODE_TYPE(target)) {
13664 case PM_MISSING_NODE:
13665 pm_node_destroy(parser, value);
13667 case PM_CLASS_VARIABLE_READ_NODE: {
13669 pm_node_destroy(parser, target);
13672 case PM_CONSTANT_PATH_NODE: {
13675 if (context_def_p(parser)) {
13676 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13679 return parse_shareable_constant_write(parser, node);
13681 case PM_CONSTANT_READ_NODE: {
13684 if (context_def_p(parser)) {
13685 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13688 pm_node_destroy(parser, target);
13689 return parse_shareable_constant_write(parser, node);
13691 case PM_BACK_REFERENCE_READ_NODE:
13692 case PM_NUMBERED_REFERENCE_READ_NODE:
13693 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13695 case PM_GLOBAL_VARIABLE_READ_NODE: {
13697 pm_node_destroy(parser, target);
13700 case PM_LOCAL_VARIABLE_READ_NODE: {
13706 uint32_t depth = local_read->
depth;
13707 pm_scope_t *scope = pm_parser_scope_find(parser, depth);
13710 pm_diagnostic_id_t diag_id = (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND) ? PM_ERR_EXPRESSION_NOT_WRITABLE_NUMBERED : PM_ERR_PARAMETER_NUMBERED_RESERVED;
13712 parse_target_implicit_parameter(parser, target);
13715 pm_locals_unread(&scope->
locals, name);
13716 pm_node_destroy(parser, target);
13718 return (
pm_node_t *) pm_local_variable_write_node_create(parser, name, depth, value, &name_loc,
operator);
13720 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
13724 parse_target_implicit_parameter(parser, target);
13725 pm_node_destroy(parser, target);
13729 case PM_INSTANCE_VARIABLE_READ_NODE: {
13731 pm_node_destroy(parser, target);
13734 case PM_MULTI_TARGET_NODE:
13736 case PM_SPLAT_NODE: {
13744 pm_multi_target_node_targets_append(parser, multi_target, (
pm_node_t *) splat);
13746 return (
pm_node_t *) pm_multi_write_node_create(parser, multi_target,
operator, value);
13748 case PM_CALL_NODE: {
13760 (call->
block == NULL)
13774 pm_parser_local_add_location(parser, message.
start, message.
end, 0);
13775 pm_node_destroy(parser, target);
13778 target = (
pm_node_t *) pm_local_variable_write_node_create(parser, constant_id, 0, value, &message,
operator);
13780 pm_refute_numbered_parameter(parser, message.
start, message.
end);
13798 pm_arguments_node_arguments_append(arguments, value);
13801 parse_write_name(parser, &call->
name);
13802 pm_node_flag_set((
pm_node_t *) call, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
13811 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
13813 call->
arguments = pm_arguments_node_create(parser);
13816 pm_arguments_node_arguments_append(call->
arguments, value);
13820 call->
name = pm_parser_constant_id_constant(parser,
"[]=", 3);
13824 pm_node_flag_set((
pm_node_t *) call, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
13834 pm_node_destroy(parser, value);
13841 pm_parser_err_token(parser,
operator, PM_ERR_WRITE_TARGET_UNEXPECTED);
13854 switch (PM_NODE_TYPE(target)) {
13855 case PM_SOURCE_ENCODING_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13856 case PM_FALSE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13857 case PM_SOURCE_FILE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13858 case PM_SOURCE_LINE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13859 case PM_NIL_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13860 case PM_SELF_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13861 case PM_TRUE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13868 pm_node_destroy(parser, target);
13883parse_targets(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13884 bool has_rest = PM_NODE_TYPE_P(first_target, PM_SPLAT_NODE);
13887 pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target,
true,
false));
13889 while (accept1(parser, PM_TOKEN_COMMA)) {
13890 if (accept1(parser, PM_TOKEN_USTAR)) {
13895 pm_parser_err_previous(parser, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
13901 if (token_begins_expression_p(parser->
current.type)) {
13902 name = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13903 name = parse_target(parser, name,
true,
true);
13906 pm_node_t *splat = (
pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
13907 pm_multi_target_node_targets_append(parser, result, splat);
13909 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
13911 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13912 target = parse_target(parser, target,
true,
false);
13914 pm_multi_target_node_targets_append(parser, result, target);
13915 context_pop(parser);
13916 }
else if (token_begins_expression_p(parser->
current.type)) {
13917 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13918 target = parse_target(parser, target,
true,
false);
13920 pm_multi_target_node_targets_append(parser, result, target);
13921 }
else if (!match1(parser, PM_TOKEN_EOF)) {
13925 pm_multi_target_node_targets_append(parser, result, rest);
13938parse_targets_validate(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13939 pm_node_t *result = parse_targets(parser, first_target, binding_power, depth);
13940 accept1(parser, PM_TOKEN_NEWLINE);
13943 if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
13944 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13957 while (accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE));
13960 if (context_terminator(context, &parser->
current))
return NULL;
13966 context_push(parser, context);
13969 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
13970 pm_statements_node_body_append(parser, statements, node,
true);
13983 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
13986 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13987 if (context_terminator(context, &parser->
current))
break;
13997 if (context_terminator(context, &parser->
current))
break;
14009 if (PM_NODE_TYPE_P(node, PM_MISSING_NODE)) {
14010 parser_lex(parser);
14016 if (match1(parser, PM_TOKEN_EOF)) {
14021 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
14022 if (context_terminator(context, &parser->
current))
break;
14023 }
else if (!accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_EOF)) {
14033 context_pop(parser);
14034 bool last_value =
true;
14038 last_value =
false;
14043 pm_void_statements_check(parser, statements, last_value);
14056 if (duplicated != NULL) {
14060 pm_diagnostic_list_append_format(
14064 PM_WARN_DUPLICATED_HASH_KEY,
14082 if ((previous = pm_static_literals_add(&parser->
newline_list, parser->
start_line, literals, node,
false)) != NULL) {
14083 pm_diagnostic_list_append_format(
14087 PM_WARN_DUPLICATED_WHEN_CLAUSE,
14099 assert(PM_NODE_TYPE_P(node, PM_HASH_NODE) || PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE));
14100 bool contains_keyword_splat =
false;
14105 switch (parser->
current.type) {
14106 case PM_TOKEN_USTAR_STAR: {
14107 parser_lex(parser);
14111 if (match1(parser, PM_TOKEN_BRACE_LEFT)) {
14117 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
14118 }
else if (token_begins_expression_p(parser->
current.type)) {
14119 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
14121 pm_parser_scope_forwarding_keywords_check(parser, &
operator);
14124 element = (
pm_node_t *) pm_assoc_splat_node_create(parser, value, &
operator);
14125 contains_keyword_splat =
true;
14128 case PM_TOKEN_LABEL: {
14130 parser_lex(parser);
14133 pm_hash_key_static_literals_add(parser, literals, key);
14138 if (token_begins_expression_p(parser->
current.type)) {
14139 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_EXPRESSION_AFTER_LABEL, (uint16_t) (depth + 1));
14142 pm_token_t constant = { .type = PM_TOKEN_CONSTANT, .start = label.
start, .end = label.
end - 1 };
14143 value = (
pm_node_t *) pm_constant_read_node_create(parser, &constant);
14148 if (identifier.
end[-1] ==
'!' || identifier.
end[-1] ==
'?') {
14149 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, identifier, PM_ERR_INVALID_LOCAL_VARIABLE_READ);
14151 depth = pm_parser_local_depth(parser, &identifier);
14155 value = (
pm_node_t *) pm_call_node_variable_call_create(parser, &identifier);
14157 value = (
pm_node_t *) pm_local_variable_read_node_create(parser, &identifier, (uint32_t) depth);
14162 value = (
pm_node_t *) pm_implicit_node_create(parser, value);
14165 element = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
14169 pm_node_t *key = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_HASH_KEY, (uint16_t) (depth + 1));
14173 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
14174 pm_node_flag_set(key, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
14177 pm_hash_key_static_literals_add(parser, literals, key);
14180 if (pm_symbol_node_label_p(key)) {
14181 operator = not_provided(parser);
14183 expect1(parser, PM_TOKEN_EQUAL_GREATER, PM_ERR_HASH_ROCKET);
14187 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
14188 element = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
14193 if (PM_NODE_TYPE_P(node, PM_HASH_NODE)) {
14200 if (!accept1(parser, PM_TOKEN_COMMA))
break;
14204 if (match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL))
continue;
14208 if (token_begins_expression_p(parser->
current.type))
continue;
14214 return contains_keyword_splat;
14223 arguments->
arguments = pm_arguments_node_create(parser);
14226 pm_arguments_node_arguments_append(arguments->
arguments, argument);
14233parse_arguments(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_forwarding, pm_token_type_t terminator, uint16_t depth) {
14234 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].
left;
14239 match2(parser, terminator, PM_TOKEN_EOF) ||
14240 (binding_power != PM_BINDING_POWER_UNSET && binding_power < PM_BINDING_POWER_RANGE) ||
14246 bool parsed_first_argument =
false;
14247 bool parsed_bare_hash =
false;
14248 bool parsed_block_argument =
false;
14249 bool parsed_forwarding_arguments =
false;
14251 while (!match1(parser, PM_TOKEN_EOF)) {
14252 if (parsed_forwarding_arguments) {
14253 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES);
14258 switch (parser->
current.type) {
14259 case PM_TOKEN_USTAR_STAR:
14260 case PM_TOKEN_LABEL: {
14261 if (parsed_bare_hash) {
14262 pm_parser_err_current(parser, PM_ERR_ARGUMENT_BARE_HASH);
14269 bool contains_keyword_splat = parse_assocs(parser, &hash_keys, (
pm_node_t *) hash, (uint16_t) (depth + 1));
14271 parse_arguments_append(parser, arguments, argument);
14273 pm_node_flags_t flags = PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
14274 if (contains_keyword_splat) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
14277 pm_static_literals_free(&hash_keys);
14278 parsed_bare_hash =
true;
14282 case PM_TOKEN_UAMPERSAND: {
14283 parser_lex(parser);
14287 if (token_begins_expression_p(parser->
current.type)) {
14288 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14290 pm_parser_scope_forwarding_block_check(parser, &
operator);
14293 argument = (
pm_node_t *) pm_block_argument_node_create(parser, &
operator, expression);
14294 if (parsed_block_argument) {
14295 parse_arguments_append(parser, arguments, argument);
14297 arguments->
block = argument;
14300 if (match1(parser, PM_TOKEN_COMMA)) {
14301 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK);
14304 parsed_block_argument =
true;
14307 case PM_TOKEN_USTAR: {
14308 parser_lex(parser);
14311 if (match4(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_SEMICOLON, PM_TOKEN_BRACKET_RIGHT)) {
14312 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
14313 argument = (
pm_node_t *) pm_splat_node_create(parser, &
operator, NULL);
14314 if (parsed_bare_hash) {
14315 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
14318 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT, (uint16_t) (depth + 1));
14320 if (parsed_bare_hash) {
14321 pm_parser_err(parser,
operator.start, expression->
location.
end, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
14324 argument = (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
14327 parse_arguments_append(parser, arguments, argument);
14330 case PM_TOKEN_UDOT_DOT_DOT: {
14331 if (accepts_forwarding) {
14332 parser_lex(parser);
14334 if (token_begins_expression_p(parser->
current.type)) {
14339 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_RANGE,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
14344 if (PM_NODE_TYPE_P(right, PM_RANGE_NODE)) {
14346 pm_parser_err(parser, range->operator_loc.start, range->operator_loc.end, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
14349 argument = (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
14351 pm_parser_scope_forwarding_all_check(parser, &parser->
previous);
14352 if (parsed_first_argument && terminator == PM_TOKEN_EOF) {
14353 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORWARDING_UNBOUND);
14356 argument = (
pm_node_t *) pm_forwarding_arguments_node_create(parser, &parser->
previous);
14357 parse_arguments_append(parser, arguments, argument);
14358 pm_node_flag_set((
pm_node_t *) arguments->
arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING);
14360 parsed_forwarding_arguments =
true;
14367 if (argument == NULL) {
14368 argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, !parsed_first_argument,
true, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14371 bool contains_keywords =
false;
14372 bool contains_keyword_splat =
false;
14374 if (pm_symbol_node_label_p(argument) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
14375 if (parsed_bare_hash) {
14376 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
14380 if (parser->
previous.
type == PM_TOKEN_EQUAL_GREATER) {
14383 operator = not_provided(parser);
14387 contains_keywords =
true;
14391 pm_hash_key_static_literals_add(parser, &hash_keys, argument);
14394 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
14395 argument = (
pm_node_t *) pm_assoc_node_create(parser, argument, &
operator, value);
14397 pm_keyword_hash_node_elements_append(bare_hash, argument);
14401 if (accept1(parser, PM_TOKEN_COMMA) && (
14402 token_begins_expression_p(parser->
current.type) ||
14403 match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL)
14405 contains_keyword_splat = parse_assocs(parser, &hash_keys, (
pm_node_t *) bare_hash, (uint16_t) (depth + 1));
14408 pm_static_literals_free(&hash_keys);
14409 parsed_bare_hash =
true;
14412 parse_arguments_append(parser, arguments, argument);
14414 pm_node_flags_t flags = 0;
14415 if (contains_keywords) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
14416 if (contains_keyword_splat) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
14423 parsed_first_argument =
true;
14426 if (PM_NODE_TYPE_P(argument, PM_MISSING_NODE) || parser->
recovering)
break;
14431 bool accepted_newline =
false;
14432 if (terminator != PM_TOKEN_EOF) {
14433 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
14436 if (parser->
previous.
type == PM_TOKEN_COMMA && parsed_bare_hash) {
14440 }
else if (accept1(parser, PM_TOKEN_COMMA)) {
14443 if (accepted_newline) {
14444 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14454 if (match1(parser, terminator))
break;
14469parse_required_destructured_parameter(
pm_parser_t *parser) {
14470 expect1(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_ERR_EXPECT_LPAREN_REQ_PARAMETER);
14473 pm_multi_target_node_opening_set(node, &parser->
previous);
14482 if (node->
lefts.
size > 0 && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
14484 pm_multi_target_node_targets_append(parser, node, param);
14485 pm_parser_err_current(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14489 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
14490 param = (
pm_node_t *) parse_required_destructured_parameter(parser);
14491 }
else if (accept1(parser, PM_TOKEN_USTAR)) {
14495 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14497 value = (
pm_node_t *) pm_required_parameter_node_create(parser, &name);
14498 if (pm_parser_parameter_name_check(parser, &name)) {
14499 pm_node_flag_set_repeated_parameter(value);
14501 pm_parser_local_add_token(parser, &name, 1);
14504 param = (
pm_node_t *) pm_splat_node_create(parser, &star, value);
14506 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EXPECT_IDENT_REQ_PARAMETER);
14509 param = (
pm_node_t *) pm_required_parameter_node_create(parser, &name);
14510 if (pm_parser_parameter_name_check(parser, &name)) {
14511 pm_node_flag_set_repeated_parameter(param);
14513 pm_parser_local_add_token(parser, &name, 1);
14516 pm_multi_target_node_targets_append(parser, node, param);
14517 }
while (accept1(parser, PM_TOKEN_COMMA));
14519 accept1(parser, PM_TOKEN_NEWLINE);
14520 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN_REQ_PARAMETER);
14521 pm_multi_target_node_closing_set(node, &parser->
previous);
14531 PM_PARAMETERS_NO_CHANGE = 0,
14532 PM_PARAMETERS_ORDER_NOTHING_AFTER = 1,
14533 PM_PARAMETERS_ORDER_KEYWORDS_REST,
14534 PM_PARAMETERS_ORDER_KEYWORDS,
14535 PM_PARAMETERS_ORDER_REST,
14536 PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14537 PM_PARAMETERS_ORDER_OPTIONAL,
14538 PM_PARAMETERS_ORDER_NAMED,
14539 PM_PARAMETERS_ORDER_NONE,
14540} pm_parameters_order_t;
14545static pm_parameters_order_t parameters_ordering[PM_TOKEN_MAXIMUM] = {
14546 [0] = PM_PARAMETERS_NO_CHANGE,
14547 [PM_TOKEN_UAMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14548 [PM_TOKEN_AMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14549 [PM_TOKEN_UDOT_DOT_DOT] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14550 [PM_TOKEN_IDENTIFIER] = PM_PARAMETERS_ORDER_NAMED,
14551 [PM_TOKEN_PARENTHESIS_LEFT] = PM_PARAMETERS_ORDER_NAMED,
14552 [PM_TOKEN_EQUAL] = PM_PARAMETERS_ORDER_OPTIONAL,
14553 [PM_TOKEN_LABEL] = PM_PARAMETERS_ORDER_KEYWORDS,
14554 [PM_TOKEN_USTAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14555 [PM_TOKEN_STAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14556 [PM_TOKEN_USTAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST,
14557 [PM_TOKEN_STAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST
14569 pm_parameters_order_t state = parameters_ordering[token->type];
14570 if (state == PM_PARAMETERS_NO_CHANGE)
return true;
14574 if (*current == PM_PARAMETERS_ORDER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14575 *current = PM_PARAMETERS_ORDER_AFTER_OPTIONAL;
14577 }
else if (*current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14581 if (token->type == PM_TOKEN_USTAR && *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14582 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_STAR);
14584 }
else if (token->type == PM_TOKEN_UDOT_DOT_DOT && (*current >= PM_PARAMETERS_ORDER_KEYWORDS_REST && *current <= PM_PARAMETERS_ORDER_AFTER_OPTIONAL)) {
14585 pm_parser_err_token(parser, token, *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL ? PM_ERR_PARAMETER_FORWARDING_AFTER_REST : PM_ERR_PARAMETER_ORDER);
14587 }
else if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
14589 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_ORDER);
14593 if (state < *current) *current = state;
14603 pm_binding_power_t binding_power,
14604 bool uses_parentheses,
14605 bool allows_trailing_comma,
14606 bool allows_forwarding_parameters,
14607 bool accepts_blocks_in_defaults,
14611 pm_do_loop_stack_push(parser,
false);
14614 pm_parameters_order_t order = PM_PARAMETERS_ORDER_NONE;
14617 bool parsing =
true;
14619 switch (parser->
current.type) {
14620 case PM_TOKEN_PARENTHESIS_LEFT: {
14621 update_parameter_state(parser, &parser->
current, &order);
14624 if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14625 pm_parameters_node_requireds_append(params, param);
14627 pm_parameters_node_posts_append(params, param);
14631 case PM_TOKEN_UAMPERSAND:
14632 case PM_TOKEN_AMPERSAND: {
14633 update_parameter_state(parser, &parser->
current, &order);
14634 parser_lex(parser);
14639 bool repeated =
false;
14640 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14642 repeated = pm_parser_parameter_name_check(parser, &name);
14643 pm_parser_local_add_token(parser, &name, 1);
14645 name = not_provided(parser);
14651 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14653 if (params->
block == NULL) {
14654 pm_parameters_node_block_set(params, param);
14656 pm_parser_err_node(parser, (
pm_node_t *) param, PM_ERR_PARAMETER_BLOCK_MULTI);
14657 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14662 case PM_TOKEN_UDOT_DOT_DOT: {
14663 if (!allows_forwarding_parameters) {
14664 pm_parser_err_current(parser, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
14667 bool succeeded = update_parameter_state(parser, &parser->
current, &order);
14668 parser_lex(parser);
14677 pm_parameters_node_posts_append(params, keyword_rest);
14678 if (succeeded) pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD);
14682 pm_parameters_node_keyword_rest_set(params, (
pm_node_t *) param);
14685 case PM_TOKEN_CLASS_VARIABLE:
14686 case PM_TOKEN_IDENTIFIER:
14687 case PM_TOKEN_CONSTANT:
14688 case PM_TOKEN_INSTANCE_VARIABLE:
14689 case PM_TOKEN_GLOBAL_VARIABLE:
14690 case PM_TOKEN_METHOD_NAME: {
14691 parser_lex(parser);
14693 case PM_TOKEN_CONSTANT:
14694 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14696 case PM_TOKEN_INSTANCE_VARIABLE:
14697 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
14699 case PM_TOKEN_GLOBAL_VARIABLE:
14700 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
14702 case PM_TOKEN_CLASS_VARIABLE:
14703 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
14705 case PM_TOKEN_METHOD_NAME:
14706 pm_parser_err_previous(parser, PM_ERR_PARAMETER_METHOD_NAME);
14711 if (parser->
current.type == PM_TOKEN_EQUAL) {
14712 update_parameter_state(parser, &parser->
current, &order);
14714 update_parameter_state(parser, &parser->
previous, &order);
14718 bool repeated = pm_parser_parameter_name_check(parser, &name);
14719 pm_parser_local_add_token(parser, &name, 1);
14721 if (match1(parser, PM_TOKEN_EQUAL)) {
14724 parser_lex(parser);
14729 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14730 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
14731 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14736 pm_node_flag_set_repeated_parameter((
pm_node_t *) param);
14738 pm_parameters_node_optionals_append(params, param);
14744 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, name, PM_ERR_PARAMETER_CIRCULAR);
14747 context_pop(parser);
14756 }
else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14759 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14761 pm_parameters_node_requireds_append(params, (
pm_node_t *) param);
14765 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14767 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14772 case PM_TOKEN_LABEL: {
14773 if (!uses_parentheses && !in_block) parser->
in_keyword_arg =
true;
14774 update_parameter_state(parser, &parser->
current, &order);
14777 parser_lex(parser);
14784 pm_parser_err(parser, local.
start, local.
end, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14785 }
else if (local.
end[-1] ==
'!' || local.
end[-1] ==
'?') {
14786 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
14789 bool repeated = pm_parser_parameter_name_check(parser, &local);
14790 pm_parser_local_add_token(parser, &local, 1);
14792 switch (parser->
current.type) {
14793 case PM_TOKEN_COMMA:
14794 case PM_TOKEN_PARENTHESIS_RIGHT:
14795 case PM_TOKEN_PIPE: {
14796 context_pop(parser);
14798 pm_node_t *param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14800 pm_node_flag_set_repeated_parameter(param);
14803 pm_parameters_node_keywords_append(params, param);
14806 case PM_TOKEN_SEMICOLON:
14807 case PM_TOKEN_NEWLINE: {
14808 context_pop(parser);
14810 if (uses_parentheses) {
14815 pm_node_t *param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14817 pm_node_flag_set_repeated_parameter(param);
14820 pm_parameters_node_keywords_append(params, param);
14826 if (token_begins_expression_p(parser->
current.type)) {
14830 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14831 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT_KW, (uint16_t) (depth + 1));
14832 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14835 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_PARAMETER_CIRCULAR);
14838 param = (
pm_node_t *) pm_optional_keyword_parameter_node_create(parser, &name, value);
14841 param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14845 pm_node_flag_set_repeated_parameter(param);
14848 context_pop(parser);
14849 pm_parameters_node_keywords_append(params, param);
14864 case PM_TOKEN_USTAR:
14865 case PM_TOKEN_STAR: {
14866 update_parameter_state(parser, &parser->
current, &order);
14867 parser_lex(parser);
14871 bool repeated =
false;
14873 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14875 repeated = pm_parser_parameter_name_check(parser, &name);
14876 pm_parser_local_add_token(parser, &name, 1);
14878 name = not_provided(parser);
14882 pm_node_t *param = (
pm_node_t *) pm_rest_parameter_node_create(parser, &
operator, &name);
14884 pm_node_flag_set_repeated_parameter(param);
14887 if (params->
rest == NULL) {
14888 pm_parameters_node_rest_set(params, param);
14890 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_SPLAT_MULTI);
14891 pm_parameters_node_posts_append(params, param);
14896 case PM_TOKEN_STAR_STAR:
14897 case PM_TOKEN_USTAR_STAR: {
14898 pm_parameters_order_t previous_order = order;
14899 update_parameter_state(parser, &parser->
current, &order);
14900 parser_lex(parser);
14905 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
14906 if (previous_order <= PM_PARAMETERS_ORDER_KEYWORDS) {
14907 pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_NO_KW);
14910 param = (
pm_node_t *) pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous);
14914 bool repeated =
false;
14915 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14917 repeated = pm_parser_parameter_name_check(parser, &name);
14918 pm_parser_local_add_token(parser, &name, 1);
14920 name = not_provided(parser);
14924 param = (
pm_node_t *) pm_keyword_rest_parameter_node_create(parser, &
operator, &name);
14926 pm_node_flag_set_repeated_parameter(param);
14931 pm_parameters_node_keyword_rest_set(params, param);
14933 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI);
14934 pm_parameters_node_posts_append(params, param);
14941 if (allows_trailing_comma && order >= PM_PARAMETERS_ORDER_NAMED) {
14946 if (params->
rest == NULL) {
14947 pm_parameters_node_rest_set(params, param);
14949 pm_parser_err_node(parser, (
pm_node_t *) param, PM_ERR_PARAMETER_SPLAT_MULTI);
14950 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14953 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14964 if (!parsing)
break;
14966 bool accepted_newline =
false;
14967 if (uses_parentheses) {
14968 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
14971 if (accept1(parser, PM_TOKEN_COMMA)) {
14974 if (accepted_newline) {
14975 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14983 pm_do_loop_stack_pop(parser);
14987 pm_node_destroy(parser, (
pm_node_t *) params);
15019token_column(
const pm_parser_t *parser,
size_t newline_index,
const pm_token_t *token,
bool break_on_non_space) {
15021 const uint8_t *end = token->start;
15025 newline_index == 0 &&
15026 parser->
start[0] == 0xef &&
15027 parser->
start[1] == 0xbb &&
15028 parser->
start[2] == 0xbf
15031 int64_t column = 0;
15032 for (; cursor < end; cursor++) {
15035 column = ((column / PM_TAB_WHITESPACE_SIZE) + 1) * PM_TAB_WHITESPACE_SIZE;
15042 if (break_on_non_space)
return -1;
15055parser_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) {
15060 size_t closing_newline_index = token_newline_index(parser);
15061 if (opening_newline_index == closing_newline_index)
return;
15066 int64_t opening_column = token_column(parser, opening_newline_index, opening_token, !if_after_else);
15067 if (!if_after_else && (opening_column == -1))
return;
15074 int64_t closing_column = token_column(parser, closing_newline_index, closing_token,
true);
15075 if ((closing_column == -1) || (opening_column == closing_column))
return;
15079 if (allow_indent && (closing_column > opening_column))
return;
15082 PM_PARSER_WARN_FORMAT(
15084 closing_token->
start,
15085 closing_token->
end,
15086 PM_WARN_INDENTATION_MISMATCH,
15087 (
int) (closing_token->
end - closing_token->
start),
15088 (
const char *) closing_token->
start,
15089 (
int) (opening_token->
end - opening_token->
start),
15090 (
const char *) opening_token->
start,
15091 ((int32_t) opening_newline_index) + parser->
start_line
15096 PM_RESCUES_BEGIN = 1,
15103} pm_rescues_type_t;
15113 while (match1(parser, PM_TOKEN_KEYWORD_RESCUE)) {
15114 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15115 parser_lex(parser);
15119 switch (parser->
current.type) {
15120 case PM_TOKEN_EQUAL_GREATER: {
15124 parser_lex(parser);
15125 pm_rescue_node_operator_set(rescue, &parser->
previous);
15127 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15128 reference = parse_target(parser, reference,
false,
false);
15130 pm_rescue_node_reference_set(rescue, reference);
15133 case PM_TOKEN_NEWLINE:
15134 case PM_TOKEN_SEMICOLON:
15135 case PM_TOKEN_KEYWORD_THEN:
15140 if (token_begins_expression_p(parser->
current.type) || match1(parser, PM_TOKEN_USTAR)) {
15145 pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED,
false, PM_ERR_RESCUE_EXPRESSION, (uint16_t) (depth + 1));
15146 pm_rescue_node_exceptions_append(rescue, expression);
15150 if (match3(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_THEN))
break;
15154 if (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
15155 pm_rescue_node_operator_set(rescue, &parser->
previous);
15157 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15158 reference = parse_target(parser, reference,
false,
false);
15160 pm_rescue_node_reference_set(rescue, reference);
15163 }
while (accept1(parser, PM_TOKEN_COMMA));
15168 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
15169 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
15173 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_RESCUE_TERM);
15177 if (!match3(parser, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_END)) {
15178 pm_accepts_block_stack_push(parser,
true);
15193 if (statements != NULL) pm_rescue_node_statements_set(rescue, statements);
15195 pm_accepts_block_stack_pop(parser);
15196 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15199 if (current == NULL) {
15200 pm_begin_node_rescue_clause_set(parent_node, rescue);
15202 pm_rescue_node_subsequent_set(current, rescue);
15211 if (current != NULL) {
15215 while (clause != NULL) {
15222 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
15223 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15224 opening_newline_index = token_newline_index(parser);
15226 else_keyword = parser->
current;
15227 opening = &else_keyword;
15229 parser_lex(parser);
15230 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15233 if (!match2(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_ENSURE)) {
15234 pm_accepts_block_stack_push(parser,
true);
15248 else_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15249 pm_accepts_block_stack_pop(parser);
15251 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15254 pm_else_node_t *else_clause = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
current);
15255 pm_begin_node_else_clause_set(parent_node, else_clause);
15259 if (current == NULL) pm_parser_err_node(parser, (
pm_node_t *) else_clause, PM_ERR_BEGIN_LONELY_ELSE);
15262 if (match1(parser, PM_TOKEN_KEYWORD_ENSURE)) {
15263 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15266 parser_lex(parser);
15267 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15270 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
15271 pm_accepts_block_stack_push(parser,
true);
15285 ensure_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15286 pm_accepts_block_stack_pop(parser);
15288 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15291 pm_ensure_node_t *ensure_clause = pm_ensure_node_create(parser, &ensure_keyword, ensure_statements, &parser->
current);
15292 pm_begin_node_ensure_clause_set(parent_node, ensure_clause);
15295 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
15296 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15297 pm_begin_node_end_keyword_set(parent_node, &parser->
current);
15300 pm_begin_node_end_keyword_set(parent_node, &end_keyword);
15310 pm_token_t begin_keyword = not_provided(parser);
15311 pm_begin_node_t *node = pm_begin_node_create(parser, &begin_keyword, statements);
15313 parse_rescues(parser, opening_newline_index, opening, node,
type, (uint16_t) (depth + 1));
15323parse_block_parameters(
15325 bool allows_trailing_comma,
15327 bool is_lambda_literal,
15328 bool accepts_blocks_in_defaults,
15332 if (!match1(parser, PM_TOKEN_SEMICOLON)) {
15333 parameters = parse_parameters(
15335 is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
15337 allows_trailing_comma,
15339 accepts_blocks_in_defaults,
15341 (uint16_t) (depth + 1)
15346 if ((opening->
type != PM_TOKEN_NOT_PROVIDED)) {
15347 accept1(parser, PM_TOKEN_NEWLINE);
15349 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
15351 switch (parser->
current.type) {
15352 case PM_TOKEN_CONSTANT:
15353 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
15354 parser_lex(parser);
15356 case PM_TOKEN_INSTANCE_VARIABLE:
15357 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
15358 parser_lex(parser);
15360 case PM_TOKEN_GLOBAL_VARIABLE:
15361 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
15362 parser_lex(parser);
15364 case PM_TOKEN_CLASS_VARIABLE:
15365 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
15366 parser_lex(parser);
15369 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_BLOCK_PARAM_LOCAL_VARIABLE);
15373 bool repeated = pm_parser_parameter_name_check(parser, &parser->
previous);
15374 pm_parser_local_add_token(parser, &parser->
previous, 1);
15377 if (repeated) pm_node_flag_set_repeated_parameter((
pm_node_t *) local);
15379 pm_block_parameters_node_append_local(block_parameters, local);
15380 }
while (accept1(parser, PM_TOKEN_COMMA));
15384 return block_parameters;
15392outer_scope_using_numbered_parameters_p(
pm_parser_t *parser) {
15394 if (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND)
return true;
15405static const char *
const pm_numbered_parameter_names[] = {
15406 "_1",
"_2",
"_3",
"_4",
"_5",
"_6",
"_7",
"_8",
"_9"
15420 if (parameters != NULL) {
15422 if (implicit_parameters->
size > 0) {
15425 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
15426 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_ORDINARY);
15427 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
15428 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_ORDINARY);
15430 assert(
false &&
"unreachable");
15439 if (implicit_parameters->
size == 0) {
15446 uint8_t numbered_parameter = 0;
15447 bool it_parameter =
false;
15449 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
15452 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
15453 if (it_parameter) {
15454 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_IT);
15455 }
else if (outer_scope_using_numbered_parameters_p(parser)) {
15456 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_OUTER_BLOCK);
15458 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK);
15460 numbered_parameter = MAX(numbered_parameter, (uint8_t) (node->
location.
start[1] -
'0'));
15462 assert(
false &&
"unreachable");
15464 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
15465 if (numbered_parameter > 0) {
15466 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_NUMBERED);
15468 it_parameter =
true;
15473 if (numbered_parameter > 0) {
15477 scope->
parameters |= PM_SCOPE_PARAMETERS_NUMBERED_INNER;
15481 return (
pm_node_t *) pm_numbered_parameters_node_create(parser, &location, numbered_parameter);
15484 if (it_parameter) {
15485 return (
pm_node_t *) pm_it_parameters_node_create(parser, opening, closing);
15495parse_block(
pm_parser_t *parser, uint16_t depth) {
15497 accept1(parser, PM_TOKEN_NEWLINE);
15499 pm_accepts_block_stack_push(parser,
true);
15500 pm_parser_scope_push(parser,
false);
15504 if (accept1(parser, PM_TOKEN_PIPE)) {
15506 if (match1(parser, PM_TOKEN_PIPE)) {
15507 block_parameters = pm_block_parameters_node_create(parser, NULL, &block_parameters_opening);
15509 parser_lex(parser);
15511 block_parameters = parse_block_parameters(parser,
true, &block_parameters_opening,
false,
true, (uint16_t) (depth + 1));
15512 accept1(parser, PM_TOKEN_NEWLINE);
15514 expect1(parser, PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM);
15517 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
15520 accept1(parser, PM_TOKEN_NEWLINE);
15523 if (opening.
type == PM_TOKEN_BRACE_LEFT) {
15524 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
15528 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE);
15530 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
15531 if (!match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE)) {
15532 pm_accepts_block_stack_push(parser,
true);
15534 pm_accepts_block_stack_pop(parser);
15537 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
15538 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
15539 statements = (
pm_node_t *) parse_rescues_implicit_begin(parser, 0, NULL, opening.
start, (
pm_statements_node_t *) statements, PM_RESCUES_BLOCK, (uint16_t) (depth + 1));
15543 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END);
15547 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
15550 pm_parser_scope_pop(parser);
15551 pm_accepts_block_stack_pop(parser);
15553 return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->
previous);
15562parse_arguments_list(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_block,
bool accepts_command_call, uint16_t depth) {
15563 bool found =
false;
15565 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
15569 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
15572 pm_accepts_block_stack_push(parser,
true);
15573 parse_arguments(parser, arguments, accepts_block, PM_TOKEN_PARENTHESIS_RIGHT, (uint16_t) (depth + 1));
15575 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
15581 pm_accepts_block_stack_pop(parser);
15584 }
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)) {
15586 pm_accepts_block_stack_push(parser,
false);
15591 parse_arguments(parser, arguments, accepts_block, PM_TOKEN_EOF, (uint16_t) (depth + 1));
15596 if (parser->
previous.
type == PM_TOKEN_COMMA && !match1(parser, PM_TOKEN_SEMICOLON)) {
15600 pm_accepts_block_stack_pop(parser);
15606 if (accepts_block) {
15609 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
15611 block = parse_block(parser, (uint16_t) (depth + 1));
15612 pm_arguments_validate_block(parser, arguments, block);
15613 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
15615 block = parse_block(parser, (uint16_t) (depth + 1));
15618 if (block != NULL) {
15622 pm_parser_err_node(parser, (
pm_node_t *) block, PM_ERR_ARGUMENT_BLOCK_MULTI);
15624 if (arguments->
block != NULL) {
15626 arguments->
arguments = pm_arguments_node_create(parser);
15628 pm_arguments_node_arguments_append(arguments->
arguments, arguments->
block);
15644 bool in_sclass =
false;
15646 switch (context_node->
context) {
15691 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15713 assert(
false &&
"unreachable");
15718 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15729 switch (context_node->
context) {
15803 assert(
false &&
"unreachable");
15817 return previous_block_exits;
15831 switch (PM_NODE_TYPE(block_exit)) {
15832 case PM_BREAK_NODE:
type =
"break";
break;
15833 case PM_NEXT_NODE:
type =
"next";
break;
15834 case PM_REDO_NODE:
type =
"redo";
break;
15835 default: assert(
false &&
"unreachable");
type =
"";
break;
15838 PM_PARSER_ERR_NODE_FORMAT(parser, block_exit, PM_ERR_INVALID_BLOCK_EXIT,
type);
15850 if (match2(parser, PM_TOKEN_KEYWORD_WHILE_MODIFIER, PM_TOKEN_KEYWORD_UNTIL_MODIFIER)) {
15855 }
else if (previous_block_exits != NULL) {
15867 flush_block_exits(parser, previous_block_exits);
15875 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, error_id, (uint16_t) (depth + 1));
15878 bool predicate_closed = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15880 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
15881 predicate_closed =
true;
15885 if (!predicate_closed) {
15886 pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
15889 context_pop(parser);
15894parse_conditional(
pm_parser_t *parser,
pm_context_t context,
size_t opening_newline_index,
bool if_after_else, uint16_t depth) {
15896 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
15899 pm_token_t then_keyword = not_provided(parser);
15901 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context, &then_keyword, (uint16_t) (depth + 1));
15904 if (!match3(parser, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
15905 pm_accepts_block_stack_push(parser,
true);
15906 statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15907 pm_accepts_block_stack_pop(parser);
15908 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15911 pm_token_t end_keyword = not_provided(parser);
15916 parent = (
pm_node_t *) pm_if_node_create(parser, &keyword, predicate, &then_keyword, statements, NULL, &end_keyword);
15919 parent = (
pm_node_t *) pm_unless_node_create(parser, &keyword, predicate, &then_keyword, statements);
15922 assert(
false &&
"unreachable");
15931 while (match1(parser, PM_TOKEN_KEYWORD_ELSIF)) {
15932 if (parser_end_of_line_p(parser)) {
15933 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
15936 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15938 parser_lex(parser);
15940 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER,
PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1));
15941 pm_accepts_block_stack_push(parser,
true);
15944 pm_accepts_block_stack_pop(parser);
15945 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15947 pm_node_t *elsif = (
pm_node_t *) pm_if_node_create(parser, &elsif_keyword, predicate, &then_keyword, statements, NULL, &end_keyword);
15953 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
15954 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15955 opening_newline_index = token_newline_index(parser);
15957 parser_lex(parser);
15960 pm_accepts_block_stack_push(parser,
true);
15962 pm_accepts_block_stack_pop(parser);
15964 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15965 parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword,
false,
false);
15966 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE);
15968 pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
previous);
15978 assert(
false &&
"unreachable");
15982 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else,
false);
15983 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM);
15990 bool recursing =
true;
15992 while (recursing) {
15993 switch (PM_NODE_TYPE(current)) {
15997 recursing = current != NULL;
16015 assert(
false &&
"unreachable");
16019 pop_block_exits(parser, previous_block_exits);
16020 pm_node_list_free(¤t_block_exits);
16029#define PM_CASE_KEYWORD PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
16030 case PM_TOKEN_KEYWORD_ALIAS: case PM_TOKEN_KEYWORD_AND: case PM_TOKEN_KEYWORD_BEGIN: case PM_TOKEN_KEYWORD_BEGIN_UPCASE: \
16031 case PM_TOKEN_KEYWORD_BREAK: case PM_TOKEN_KEYWORD_CASE: case PM_TOKEN_KEYWORD_CLASS: case PM_TOKEN_KEYWORD_DEF: \
16032 case PM_TOKEN_KEYWORD_DEFINED: case PM_TOKEN_KEYWORD_DO: case PM_TOKEN_KEYWORD_DO_LOOP: case PM_TOKEN_KEYWORD_ELSE: \
16033 case PM_TOKEN_KEYWORD_ELSIF: case PM_TOKEN_KEYWORD_END: case PM_TOKEN_KEYWORD_END_UPCASE: case PM_TOKEN_KEYWORD_ENSURE: \
16034 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD_FOR: case PM_TOKEN_KEYWORD_IF: case PM_TOKEN_KEYWORD_IN: \
16035 case PM_TOKEN_KEYWORD_MODULE: case PM_TOKEN_KEYWORD_NEXT: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_NOT: \
16036 case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_KEYWORD_REDO: case PM_TOKEN_KEYWORD_RESCUE: case PM_TOKEN_KEYWORD_RETRY: \
16037 case PM_TOKEN_KEYWORD_RETURN: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_SUPER: case PM_TOKEN_KEYWORD_THEN: \
16038 case PM_TOKEN_KEYWORD_TRUE: case PM_TOKEN_KEYWORD_UNDEF: case PM_TOKEN_KEYWORD_UNLESS: case PM_TOKEN_KEYWORD_UNTIL: \
16039 case PM_TOKEN_KEYWORD_WHEN: case PM_TOKEN_KEYWORD_WHILE: case PM_TOKEN_KEYWORD_YIELD
16045#define PM_CASE_OPERATOR PM_TOKEN_AMPERSAND: case PM_TOKEN_BACKTICK: case PM_TOKEN_BANG_EQUAL: \
16046 case PM_TOKEN_BANG_TILDE: case PM_TOKEN_BANG: case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL: \
16047 case PM_TOKEN_BRACKET_LEFT_RIGHT: case PM_TOKEN_CARET: case PM_TOKEN_EQUAL_EQUAL_EQUAL: case PM_TOKEN_EQUAL_EQUAL: \
16048 case PM_TOKEN_EQUAL_TILDE: case PM_TOKEN_GREATER_EQUAL: case PM_TOKEN_GREATER_GREATER: case PM_TOKEN_GREATER: \
16049 case PM_TOKEN_LESS_EQUAL_GREATER: case PM_TOKEN_LESS_EQUAL: case PM_TOKEN_LESS_LESS: case PM_TOKEN_LESS: \
16050 case PM_TOKEN_MINUS: case PM_TOKEN_PERCENT: case PM_TOKEN_PIPE: case PM_TOKEN_PLUS: case PM_TOKEN_SLASH: \
16051 case PM_TOKEN_STAR_STAR: case PM_TOKEN_STAR: case PM_TOKEN_TILDE: case PM_TOKEN_UAMPERSAND: case PM_TOKEN_UMINUS: \
16052 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_UPLUS: case PM_TOKEN_USTAR: case PM_TOKEN_USTAR_STAR
16059#define PM_CASE_PRIMITIVE PM_TOKEN_INTEGER: case PM_TOKEN_INTEGER_IMAGINARY: case PM_TOKEN_INTEGER_RATIONAL: \
16060 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: case PM_TOKEN_FLOAT: case PM_TOKEN_FLOAT_IMAGINARY: \
16061 case PM_TOKEN_FLOAT_RATIONAL: case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY: case PM_TOKEN_SYMBOL_BEGIN: \
16062 case PM_TOKEN_REGEXP_BEGIN: case PM_TOKEN_BACKTICK: case PM_TOKEN_PERCENT_LOWER_X: case PM_TOKEN_PERCENT_LOWER_I: \
16063 case PM_TOKEN_PERCENT_LOWER_W: case PM_TOKEN_PERCENT_UPPER_I: case PM_TOKEN_PERCENT_UPPER_W: \
16064 case PM_TOKEN_STRING_BEGIN: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_TRUE: \
16065 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
16066 case PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_MINUS_GREATER: case PM_TOKEN_HEREDOC_START: \
16067 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_CHARACTER_LITERAL
16073#define PM_CASE_PARAMETER PM_TOKEN_UAMPERSAND: case PM_TOKEN_AMPERSAND: case PM_TOKEN_UDOT_DOT_DOT: \
16074 case PM_TOKEN_IDENTIFIER: case PM_TOKEN_LABEL: case PM_TOKEN_USTAR: case PM_TOKEN_STAR: case PM_TOKEN_STAR_STAR: \
16075 case PM_TOKEN_USTAR_STAR: case PM_TOKEN_CONSTANT: case PM_TOKEN_INSTANCE_VARIABLE: case PM_TOKEN_GLOBAL_VARIABLE: \
16076 case PM_TOKEN_CLASS_VARIABLE
16082#define PM_CASE_WRITABLE PM_CLASS_VARIABLE_READ_NODE: case PM_CONSTANT_PATH_NODE: \
16083 case PM_CONSTANT_READ_NODE: case PM_GLOBAL_VARIABLE_READ_NODE: case PM_LOCAL_VARIABLE_READ_NODE: \
16084 case PM_INSTANCE_VARIABLE_READ_NODE: case PM_MULTI_TARGET_NODE: case PM_BACK_REFERENCE_READ_NODE: \
16085 case PM_NUMBERED_REFERENCE_READ_NODE: case PM_IT_LOCAL_VARIABLE_READ_NODE
16089PM_STATIC_ASSERT(__LINE__, ((
int) PM_STRING_FLAGS_FORCED_UTF8_ENCODING) == ((
int) PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING),
"Expected the flags to match.");
16095static inline pm_node_flags_t
16096parse_unescaped_encoding(
const pm_parser_t *parser) {
16101 return PM_STRING_FLAGS_FORCED_UTF8_ENCODING;
16107 return PM_STRING_FLAGS_FORCED_BINARY_ENCODING;
16118parse_string_part(
pm_parser_t *parser, uint16_t depth) {
16119 switch (parser->
current.type) {
16126 case PM_TOKEN_STRING_CONTENT: {
16131 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16133 parser_lex(parser);
16142 case PM_TOKEN_EMBEXPR_BEGIN: {
16151 lex_state_set(parser, PM_LEX_STATE_BEG);
16152 parser_lex(parser);
16157 if (!match1(parser, PM_TOKEN_EMBEXPR_END)) {
16158 pm_accepts_block_stack_push(parser,
true);
16160 pm_accepts_block_stack_pop(parser);
16164 lex_state_set(parser, state);
16166 expect1(parser, PM_TOKEN_EMBEXPR_END, PM_ERR_EMBEXPR_END);
16172 if (statements != NULL && statements->
body.
size == 1) {
16173 pm_node_flag_unset(statements->
body.
nodes[0], PM_NODE_FLAG_NEWLINE);
16176 return (
pm_node_t *) pm_embedded_statements_node_create(parser, &opening, statements, &closing);
16185 case PM_TOKEN_EMBVAR: {
16190 lex_state_set(parser, PM_LEX_STATE_BEG);
16191 parser_lex(parser);
16196 switch (parser->
current.type) {
16199 case PM_TOKEN_BACK_REFERENCE:
16200 parser_lex(parser);
16201 variable = (
pm_node_t *) pm_back_reference_read_node_create(parser, &parser->
previous);
16205 case PM_TOKEN_NUMBERED_REFERENCE:
16206 parser_lex(parser);
16207 variable = (
pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->
previous);
16211 case PM_TOKEN_GLOBAL_VARIABLE:
16212 parser_lex(parser);
16213 variable = (
pm_node_t *) pm_global_variable_read_node_create(parser, &parser->
previous);
16217 case PM_TOKEN_INSTANCE_VARIABLE:
16218 parser_lex(parser);
16219 variable = (
pm_node_t *) pm_instance_variable_read_node_create(parser, &parser->
previous);
16223 case PM_TOKEN_CLASS_VARIABLE:
16224 parser_lex(parser);
16225 variable = (
pm_node_t *) pm_class_variable_read_node_create(parser, &parser->
previous);
16231 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EMBVAR_INVALID);
16236 return (
pm_node_t *) pm_embedded_variable_node_create(parser, &
operator, variable);
16239 parser_lex(parser);
16240 pm_parser_err_previous(parser, PM_ERR_CANNOT_PARSE_STRING_PART);
16250static const uint8_t *
16251parse_operator_symbol_name(
const pm_token_t *name) {
16252 switch (name->
type) {
16253 case PM_TOKEN_TILDE:
16254 case PM_TOKEN_BANG:
16255 if (name->
end[-1] ==
'@')
return name->
end - 1;
16267 const uint8_t *end = parse_operator_symbol_name(&parser->
current);
16269 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16270 parser_lex(parser);
16273 pm_node_flag_set((
pm_node_t *) symbol, PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING);
16287 if (lex_mode->
mode != PM_LEX_STRING) {
16288 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16290 switch (parser->
current.type) {
16291 case PM_CASE_OPERATOR:
16292 return parse_operator_symbol(parser, &opening, next_state == PM_LEX_STATE_NONE ? PM_LEX_STATE_ENDFN : next_state);
16293 case PM_TOKEN_IDENTIFIER:
16294 case PM_TOKEN_CONSTANT:
16295 case PM_TOKEN_INSTANCE_VARIABLE:
16296 case PM_TOKEN_METHOD_NAME:
16297 case PM_TOKEN_CLASS_VARIABLE:
16298 case PM_TOKEN_GLOBAL_VARIABLE:
16299 case PM_TOKEN_NUMBERED_REFERENCE:
16300 case PM_TOKEN_BACK_REFERENCE:
16301 case PM_CASE_KEYWORD:
16302 parser_lex(parser);
16305 expect2(parser, PM_TOKEN_IDENTIFIER, PM_TOKEN_METHOD_NAME, PM_ERR_SYMBOL_INVALID);
16313 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16320 if (match1(parser, PM_TOKEN_STRING_END)) {
16321 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16322 parser_lex(parser);
16326 return (
pm_node_t *) pm_symbol_node_create(parser, &opening, &content, &closing);
16330 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
16334 if (part && PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16335 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16336 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16342 if (part) pm_interpolated_symbol_node_append(symbol, part);
16344 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16345 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16346 pm_interpolated_symbol_node_append(symbol, part);
16350 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16351 if (match1(parser, PM_TOKEN_EOF)) {
16352 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16354 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16357 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
16364 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16367 parser_lex(parser);
16378 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16382 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &unescaped);
16383 pm_interpolated_symbol_node_append(symbol, part);
16386 pm_interpolated_symbol_node_append(symbol, part);
16388 if (next_state != PM_LEX_STATE_NONE) {
16389 lex_state_set(parser, next_state);
16392 parser_lex(parser);
16393 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
16395 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
16400 pm_string_shared_init(&unescaped, content.
start, content.
end);
16403 if (next_state != PM_LEX_STATE_NONE) {
16404 lex_state_set(parser, next_state);
16407 if (match1(parser, PM_TOKEN_EOF)) {
16408 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_DYNAMIC);
16410 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
16413 return (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
false));
16421parse_undef_argument(
pm_parser_t *parser, uint16_t depth) {
16422 switch (parser->
current.type) {
16423 case PM_CASE_OPERATOR: {
16424 const pm_token_t opening = not_provided(parser);
16425 return parse_operator_symbol(parser, &opening, PM_LEX_STATE_NONE);
16427 case PM_CASE_KEYWORD:
16428 case PM_TOKEN_CONSTANT:
16429 case PM_TOKEN_IDENTIFIER:
16430 case PM_TOKEN_METHOD_NAME: {
16431 parser_lex(parser);
16438 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16442 case PM_TOKEN_SYMBOL_BEGIN: {
16444 parser_lex(parser);
16446 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16449 pm_parser_err_current(parser, PM_ERR_UNDEF_ARGUMENT);
16461parse_alias_argument(
pm_parser_t *parser,
bool first, uint16_t depth) {
16462 switch (parser->
current.type) {
16463 case PM_CASE_OPERATOR: {
16464 const pm_token_t opening = not_provided(parser);
16465 return parse_operator_symbol(parser, &opening, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
16467 case PM_CASE_KEYWORD:
16468 case PM_TOKEN_CONSTANT:
16469 case PM_TOKEN_IDENTIFIER:
16470 case PM_TOKEN_METHOD_NAME: {
16471 if (first) lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
16472 parser_lex(parser);
16479 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16483 case PM_TOKEN_SYMBOL_BEGIN: {
16485 parser_lex(parser);
16487 return parse_symbol(parser, &lex_mode, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16489 case PM_TOKEN_BACK_REFERENCE:
16490 parser_lex(parser);
16491 return (
pm_node_t *) pm_back_reference_read_node_create(parser, &parser->
previous);
16492 case PM_TOKEN_NUMBERED_REFERENCE:
16493 parser_lex(parser);
16494 return (
pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->
previous);
16495 case PM_TOKEN_GLOBAL_VARIABLE:
16496 parser_lex(parser);
16497 return (
pm_node_t *) pm_global_variable_read_node_create(parser, &parser->
previous);
16499 pm_parser_err_current(parser, PM_ERR_ALIAS_ARGUMENT);
16514 if (!is_numbered_param && ((depth = pm_parser_local_depth_constant_id(parser, name_id)) != -1)) {
16515 return (
pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, (uint32_t) depth,
false);
16519 if (!current_scope->
closed && !(current_scope->
parameters & PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED)) {
16520 if (is_numbered_param) {
16525 uint8_t maximum = (uint8_t) (parser->
previous.
start[1] -
'0');
16526 for (uint8_t number = 1; number <= maximum; number++) {
16527 pm_parser_local_add_constant(parser, pm_numbered_parameter_names[number - 1], 2);
16530 if (!match1(parser, PM_TOKEN_EQUAL)) {
16534 pm_node_t *node = (
pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, 0,
false);
16554 pm_node_flags_t flags = 0;
16556 if (!match1(parser, PM_TOKEN_PARENTHESIS_LEFT) && (parser->
previous.
end[-1] !=
'!') && (parser->
previous.
end[-1] !=
'?')) {
16557 pm_node_t *node = parse_variable(parser);
16558 if (node != NULL)
return node;
16559 flags |= PM_CALL_NODE_FLAGS_VARIABLE_CALL;
16563 pm_node_flag_set((
pm_node_t *)node, flags);
16574parse_method_definition_name(
pm_parser_t *parser) {
16575 switch (parser->
current.type) {
16576 case PM_CASE_KEYWORD:
16577 case PM_TOKEN_CONSTANT:
16578 case PM_TOKEN_METHOD_NAME:
16579 parser_lex(parser);
16581 case PM_TOKEN_IDENTIFIER:
16582 pm_refute_numbered_parameter(parser, parser->
current.start, parser->
current.end);
16583 parser_lex(parser);
16585 case PM_CASE_OPERATOR:
16586 lex_state_set(parser, PM_LEX_STATE_ENDFN);
16587 parser_lex(parser);
16596parse_heredoc_dedent_string(
pm_string_t *
string,
size_t common_whitespace) {
16599 pm_string_ensure_owned(
string);
16605 const uint8_t *source_cursor = (uint8_t *) string->
source;
16606 const uint8_t *source_end = source_cursor + dest_length;
16611 size_t trimmed_whitespace = 0;
16617 while ((source_cursor < source_end) && pm_char_is_inline_whitespace(*source_cursor) && trimmed_whitespace < common_whitespace) {
16618 if (*source_cursor ==
'\t') {
16619 trimmed_whitespace = (trimmed_whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
16620 if (trimmed_whitespace > common_whitespace)
break;
16622 trimmed_whitespace++;
16629 memmove((uint8_t *) string->source, source_cursor, (
size_t) (source_end - source_cursor));
16630 string->length = dest_length;
16640 bool dedent_next =
true;
16645 size_t write_index = 0;
16652 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE)) {
16653 nodes->
nodes[write_index++] = node;
16654 dedent_next =
false;
16660 parse_heredoc_dedent_string(&string_node->
unescaped, common_whitespace);
16664 pm_node_destroy(parser, node);
16666 nodes->
nodes[write_index++] = node;
16670 dedent_next =
true;
16673 nodes->
size = write_index;
16680parse_strings_empty_content(
const uint8_t *location) {
16681 return (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = location, .end = location };
16689 assert(parser->
current.type == PM_TOKEN_STRING_BEGIN);
16690 bool concating =
false;
16692 while (match1(parser, PM_TOKEN_STRING_BEGIN)) {
16698 assert(lex_mode->
mode == PM_LEX_STRING);
16700 bool label_allowed = lex_mode->
as.string.
label_allowed && accepts_label;
16703 parser_lex(parser);
16705 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16706 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16715 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16725 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16726 }
else if (!lex_interpolation) {
16732 if (match1(parser, PM_TOKEN_EOF)) {
16734 content = not_provided(parser);
16737 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_EXPECT_STRING_CONTENT);
16752 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16755 pm_token_t delimiters = not_provided(parser);
16756 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &delimiters, &content, &delimiters, &unescaped);
16757 pm_node_list_append(&parts, part);
16760 part = (
pm_node_t *) pm_string_node_create_current_string(parser, &delimiters, &parser->
current, &delimiters);
16761 pm_node_list_append(&parts, part);
16762 parser_lex(parser);
16763 }
while (match1(parser, PM_TOKEN_STRING_CONTENT));
16765 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16766 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16768 pm_node_list_free(&parts);
16769 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16770 node = (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true));
16771 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16772 }
else if (match1(parser, PM_TOKEN_EOF)) {
16773 pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
16774 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
16775 }
else if (accept1(parser, PM_TOKEN_STRING_END)) {
16776 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped);
16781 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped);
16783 }
else if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16790 parser_lex(parser);
16792 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16793 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
16794 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16800 if (!accept1(parser, PM_TOKEN_STRING_END)) {
16802 if (location > parser->
start && location[-1] ==
'\n') location--;
16803 pm_parser_err(parser, location, location, PM_ERR_STRING_LITERAL_EOF);
16808 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16809 node = (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true));
16810 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16815 pm_token_t string_opening = not_provided(parser);
16816 pm_token_t string_closing = not_provided(parser);
16818 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &string_opening, &parser->
previous, &string_closing, &unescaped);
16819 pm_node_flag_set(part, parse_unescaped_encoding(parser));
16820 pm_node_list_append(&parts, part);
16822 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16823 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16824 pm_node_list_append(&parts, part);
16828 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16829 node = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous);
16830 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16831 }
else if (match1(parser, PM_TOKEN_EOF)) {
16832 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16833 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current);
16835 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16836 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16839 pm_node_list_free(&parts);
16848 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16849 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16850 pm_node_list_append(&parts, part);
16854 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16855 node = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous);
16856 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16857 }
else if (match1(parser, PM_TOKEN_EOF)) {
16858 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16859 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current);
16861 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16862 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16865 pm_node_list_free(&parts);
16868 if (current == NULL) {
16872 if (PM_NODE_TYPE_P(node, PM_SYMBOL_NODE) || PM_NODE_TYPE_P(node, PM_INTERPOLATED_SYMBOL_NODE)) {
16883 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE) && !PM_NODE_TYPE_P(node, PM_INTERPOLATED_STRING_NODE)) {
16884 pm_parser_err_node(parser, node, PM_ERR_STRING_CONCATENATION);
16890 if (!PM_NODE_TYPE_P(current, PM_STRING_NODE) && !PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
16891 pm_parser_err_node(parser, current, PM_ERR_STRING_CONCATENATION);
16898 pm_interpolated_string_node_append(container, current);
16909#define PM_PARSE_PATTERN_SINGLE 0
16910#define PM_PARSE_PATTERN_TOP 1
16911#define PM_PARSE_PATTERN_MULTI 2
16924 if (*location->
start ==
'_')
return;
16926 if (pm_constant_id_list_includes(captures, capture)) {
16927 pm_parser_err(parser, location->
start, location->
end, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
16929 pm_constant_id_list_append(captures, capture);
16940 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
16942 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
16943 node = (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
16949 if (!match2(parser, PM_TOKEN_BRACKET_LEFT, PM_TOKEN_PARENTHESIS_LEFT)) {
16957 if (accept1(parser, PM_TOKEN_BRACKET_LEFT)) {
16959 accept1(parser, PM_TOKEN_NEWLINE);
16961 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
16962 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16963 accept1(parser, PM_TOKEN_NEWLINE);
16964 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET);
16969 parser_lex(parser);
16971 accept1(parser, PM_TOKEN_NEWLINE);
16973 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
16974 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
16975 accept1(parser, PM_TOKEN_NEWLINE);
16976 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
16985 return (
pm_node_t *) pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
16992 switch (PM_NODE_TYPE(inner)) {
16993 case PM_ARRAY_PATTERN_NODE: {
17001 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17002 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17009 case PM_FIND_PATTERN_NODE: {
17017 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17018 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17025 case PM_HASH_PATTERN_NODE: {
17033 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17034 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17048 pm_array_pattern_node_t *pattern_node = pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
17049 pm_array_pattern_node_requireds_append(pattern_node, inner);
17065 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
17067 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &identifier);
17070 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17071 pm_parser_local_add(parser, constant_id, identifier.
start, identifier.
end, 0);
17074 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&identifier));
17075 name = (
pm_node_t *) pm_local_variable_target_node_create(
17077 &PM_LOCATION_TOKEN_VALUE(&identifier),
17079 (uint32_t) (depth == -1 ? 0 : depth)
17084 return pm_splat_node_create(parser, &
operator, name);
17092 assert(parser->
current.type == PM_TOKEN_USTAR_STAR);
17093 parser_lex(parser);
17098 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
17099 return (
pm_node_t *) pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous);
17102 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
17106 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17110 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17111 value = (
pm_node_t *) pm_local_variable_target_node_create(
17113 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17115 (uint32_t) (depth == -1 ? 0 : depth)
17119 return (
pm_node_t *) pm_assoc_splat_node_create(parser, value, &
operator);
17127pm_slice_is_valid_local(
const pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
17128 ptrdiff_t length = end - start;
17129 if (length == 0)
return false;
17132 size_t width = char_is_identifier_start(parser, start, end - start);
17133 if (width == 0)
return false;
17139 if (pm_encoding_utf_8_isupper_char(start, length))
return false;
17144 const uint8_t *cursor = start + width;
17145 while ((width = char_is_identifier(parser, cursor, end - cursor))) cursor += width;
17146 return cursor == end;
17160 if (pm_slice_is_valid_local(parser, value_loc->
start, value_loc->
end)) {
17161 depth = pm_parser_local_depth_constant_id(parser, constant_id);
17163 pm_parser_err(parser, key->base.location.start, key->base.location.end, PM_ERR_PATTERN_HASH_KEY_LOCALS);
17165 if ((value_loc->
end > value_loc->
start) && ((value_loc->
end[-1] ==
'!') || (value_loc->
end[-1] ==
'?'))) {
17166 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);
17171 pm_parser_local_add(parser, constant_id, value_loc->
start, value_loc->
end, 0);
17174 parse_pattern_capture(parser, captures, constant_id, value_loc);
17179 (uint32_t) (depth == -1 ? 0 : depth)
17192 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
17205 switch (PM_NODE_TYPE(first_node)) {
17206 case PM_ASSOC_SPLAT_NODE:
17207 case PM_NO_KEYWORDS_PARAMETER_NODE:
17210 case PM_SYMBOL_NODE: {
17211 if (pm_symbol_node_label_p(first_node)) {
17212 parse_pattern_hash_key(parser, &keys, first_node);
17215 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)) {
17218 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) first_node);
17222 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17226 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, first_node, &
operator, value);
17228 pm_node_list_append(&assocs, assoc);
17237 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;
17238 pm_parser_err_node(parser, first_node, diag_id);
17242 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, first_node, &
operator, value);
17244 pm_node_list_append(&assocs, assoc);
17250 while (accept1(parser, PM_TOKEN_COMMA)) {
17252 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)) {
17254 if (rest != NULL) {
17255 pm_parser_err_token(parser, &parser->
current, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17261 if (match1(parser, PM_TOKEN_USTAR_STAR)) {
17262 pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures);
17264 if (rest == NULL) {
17267 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17268 pm_node_list_append(&assocs, assoc);
17273 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
17274 key = parse_strings(parser, NULL,
true, (uint16_t) (depth + 1));
17276 if (PM_NODE_TYPE_P(key, PM_INTERPOLATED_SYMBOL_NODE)) {
17277 pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
17278 }
else if (!pm_symbol_node_label_p(key)) {
17279 pm_parser_err_node(parser, key, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17282 expect1(parser, PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17286 parse_pattern_hash_key(parser, &keys, key);
17289 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)) {
17290 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) key);
17292 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17296 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
17298 if (rest != NULL) {
17299 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17302 pm_node_list_append(&assocs, assoc);
17309 pm_static_literals_free(&keys);
17318 switch (parser->
current.type) {
17319 case PM_TOKEN_IDENTIFIER:
17320 case PM_TOKEN_METHOD_NAME: {
17321 parser_lex(parser);
17325 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17329 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17330 return (
pm_node_t *) pm_local_variable_target_node_create(
17332 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17334 (uint32_t) (depth == -1 ? 0 : depth)
17337 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
17339 parser_lex(parser);
17341 if (accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17344 return (
pm_node_t *) pm_array_pattern_node_empty_create(parser, &opening, &parser->
previous);
17349 pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
17351 accept1(parser, PM_TOKEN_NEWLINE);
17352 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET);
17355 switch (PM_NODE_TYPE(inner)) {
17356 case PM_ARRAY_PATTERN_NODE: {
17362 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17363 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17370 case PM_FIND_PATTERN_NODE: {
17376 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17377 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17389 pm_array_pattern_node_requireds_append(node, inner);
17392 case PM_TOKEN_BRACE_LEFT: {
17398 parser_lex(parser);
17400 if (accept1(parser, PM_TOKEN_BRACE_RIGHT)) {
17403 node = pm_hash_pattern_node_empty_create(parser, &opening, &parser->
previous);
17407 switch (parser->
current.type) {
17408 case PM_TOKEN_LABEL:
17409 parser_lex(parser);
17410 first_node = (
pm_node_t *) pm_symbol_node_label_create(parser, &parser->
previous);
17412 case PM_TOKEN_USTAR_STAR:
17413 first_node = parse_pattern_keyword_rest(parser, captures);
17415 case PM_TOKEN_STRING_BEGIN:
17416 first_node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, PM_ERR_PATTERN_HASH_KEY_LABEL, (uint16_t) (depth + 1));
17420 parser_lex(parser);
17427 node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
17429 accept1(parser, PM_TOKEN_NEWLINE);
17430 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE);
17436 node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17437 node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17443 case PM_TOKEN_UDOT_DOT:
17444 case PM_TOKEN_UDOT_DOT_DOT: {
17446 parser_lex(parser);
17450 switch (parser->
current.type) {
17451 case PM_CASE_PRIMITIVE: {
17452 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
17453 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
17456 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
17457 pm_node_t *right = (
pm_node_t *) pm_missing_node_create(parser,
operator.start,
operator.end);
17458 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
17462 case PM_CASE_PRIMITIVE: {
17463 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, diag_id, (uint16_t) (depth + 1));
17466 if (pm_symbol_node_label_p(node))
return node;
17469 if (PM_NODE_TYPE(node) == PM_CALL_NODE) {
17470 pm_parser_err_node(parser, node, diag_id);
17472 pm_node_destroy(parser, node);
17477 if (accept2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
17483 switch (parser->
current.type) {
17484 case PM_CASE_PRIMITIVE: {
17485 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
17486 return (
pm_node_t *) pm_range_node_create(parser, node, &
operator, right);
17489 return (
pm_node_t *) pm_range_node_create(parser, node, &
operator, NULL);
17495 case PM_TOKEN_CARET: {
17496 parser_lex(parser);
17501 switch (parser->
current.type) {
17502 case PM_TOKEN_IDENTIFIER: {
17503 parser_lex(parser);
17506 if (variable == NULL) {
17507 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
previous, PM_ERR_NO_LOCAL_VARIABLE);
17508 variable = (
pm_node_t *) pm_local_variable_read_node_missing_create(parser, &parser->
previous, 0);
17511 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17513 case PM_TOKEN_INSTANCE_VARIABLE: {
17514 parser_lex(parser);
17517 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17519 case PM_TOKEN_CLASS_VARIABLE: {
17520 parser_lex(parser);
17523 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17525 case PM_TOKEN_GLOBAL_VARIABLE: {
17526 parser_lex(parser);
17529 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17531 case PM_TOKEN_NUMBERED_REFERENCE: {
17532 parser_lex(parser);
17535 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17537 case PM_TOKEN_BACK_REFERENCE: {
17538 parser_lex(parser);
17541 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17543 case PM_TOKEN_PARENTHESIS_LEFT: {
17548 parser_lex(parser);
17550 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN, (uint16_t) (depth + 1));
17553 accept1(parser, PM_TOKEN_NEWLINE);
17554 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
17555 return (
pm_node_t *) pm_pinned_expression_node_create(parser, expression, &
operator, &lparen, &parser->
previous);
17560 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
17561 pm_node_t *variable = (
pm_node_t *) pm_missing_node_create(parser,
operator.start,
operator.end);
17562 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17566 case PM_TOKEN_UCOLON_COLON: {
17568 parser_lex(parser);
17570 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
17573 return parse_pattern_constant_path(parser, captures, (
pm_node_t *) node, (uint16_t) (depth + 1));
17575 case PM_TOKEN_CONSTANT: {
17577 parser_lex(parser);
17580 return parse_pattern_constant_path(parser, captures, node, (uint16_t) (depth + 1));
17583 pm_parser_err_current(parser, diag_id);
17596 while ((node == NULL) || accept1(parser, PM_TOKEN_PIPE)) {
17599 switch (parser->
current.type) {
17600 case PM_TOKEN_IDENTIFIER:
17601 case PM_TOKEN_BRACKET_LEFT_ARRAY:
17602 case PM_TOKEN_BRACE_LEFT:
17603 case PM_TOKEN_CARET:
17604 case PM_TOKEN_CONSTANT:
17605 case PM_TOKEN_UCOLON_COLON:
17606 case PM_TOKEN_UDOT_DOT:
17607 case PM_TOKEN_UDOT_DOT_DOT:
17608 case PM_CASE_PRIMITIVE: {
17609 if (node == NULL) {
17610 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17612 pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
17613 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17618 case PM_TOKEN_PARENTHESIS_LEFT:
17619 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
17621 parser_lex(parser);
17623 pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
17624 accept1(parser, PM_TOKEN_NEWLINE);
17625 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
17628 if (node == NULL) {
17631 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17637 pm_parser_err_current(parser, diag_id);
17640 if (node == NULL) {
17643 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17653 while (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
17655 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_PATTERN_IDENT_AFTER_HROCKET);
17660 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17664 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17667 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17669 (uint32_t) (depth == -1 ? 0 : depth)
17672 node = (
pm_node_t *) pm_capture_pattern_node_create(parser, node, target, &
operator);
17685 bool leading_rest =
false;
17686 bool trailing_rest =
false;
17688 switch (parser->
current.type) {
17689 case PM_TOKEN_LABEL: {
17690 parser_lex(parser);
17692 node = (
pm_node_t *) parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1));
17694 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17695 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17700 case PM_TOKEN_USTAR_STAR: {
17701 node = parse_pattern_keyword_rest(parser, captures);
17702 node = (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17704 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17705 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17710 case PM_TOKEN_STRING_BEGIN: {
17713 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17715 if (pm_symbol_node_label_p(node)) {
17716 node = (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17718 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17719 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17725 node = parse_pattern_primitives(parser, captures, node, diag_id, (uint16_t) (depth + 1));
17728 case PM_TOKEN_USTAR: {
17729 if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
17730 parser_lex(parser);
17731 node = (
pm_node_t *) parse_pattern_rest(parser, captures);
17732 leading_rest =
true;
17738 node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1));
17744 if (pm_symbol_node_label_p(node)) {
17745 return (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17748 if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser, PM_TOKEN_COMMA)) {
17753 pm_node_list_append(&nodes, node);
17756 while (accept1(parser, PM_TOKEN_COMMA)) {
17758 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)) {
17760 pm_node_list_append(&nodes, node);
17761 trailing_rest =
true;
17765 if (accept1(parser, PM_TOKEN_USTAR)) {
17766 node = (
pm_node_t *) parse_pattern_rest(parser, captures);
17771 if (trailing_rest) {
17772 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
17775 trailing_rest =
true;
17777 node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
17780 pm_node_list_append(&nodes, node);
17787 if (leading_rest && PM_NODE_TYPE_P(nodes.
nodes[nodes.
size - 1], PM_SPLAT_NODE)) {
17788 node = (
pm_node_t *) pm_find_pattern_node_create(parser, &nodes);
17790 if (nodes.
size == 2) {
17791 pm_parser_err_node(parser, node, PM_ERR_PATTERN_FIND_MISSING_INNER);
17794 node = (
pm_node_t *) pm_array_pattern_node_node_list_create(parser, &nodes);
17796 if (leading_rest && trailing_rest) {
17797 pm_parser_err_node(parser, node, PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS);
17802 }
else if (leading_rest) {
17805 node = (
pm_node_t *) pm_array_pattern_node_rest_create(parser, node);
17817parse_negative_numeric(
pm_node_t *node) {
17818 switch (PM_NODE_TYPE(node)) {
17819 case PM_INTEGER_NODE: {
17825 case PM_FLOAT_NODE: {
17831 case PM_RATIONAL_NODE: {
17837 case PM_IMAGINARY_NODE:
17842 assert(
false &&
"unreachable");
17855 case PM_ERR_HASH_KEY: {
17859 case PM_ERR_HASH_VALUE:
17860 case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: {
17864 case PM_ERR_UNARY_RECEIVER: {
17869 case PM_ERR_UNARY_DISALLOWED:
17870 case PM_ERR_EXPECT_ARGUMENT: {
17875 pm_parser_err_previous(parser, diag_id);
17885#define CONTEXT_NONE 0
17886#define CONTEXT_THROUGH_ENSURE 1
17887#define CONTEXT_THROUGH_ELSE 2
17890 int context = CONTEXT_NONE;
17892 while (context_node != NULL) {
17893 switch (context_node->
context) {
17914 if (context == CONTEXT_NONE) {
17915 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_WITHOUT_RESCUE);
17916 }
else if (context == CONTEXT_THROUGH_ENSURE) {
17917 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ENSURE);
17918 }
else if (context == CONTEXT_THROUGH_ELSE) {
17919 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ELSE);
17931 context = CONTEXT_THROUGH_ELSE;
17942 context = CONTEXT_THROUGH_ENSURE;
17946 assert(
false &&
"unreachable");
17976 context_node = context_node->
prev;
17980#undef CONTEXT_ENSURE
17991 while (context_node != NULL) {
17992 switch (context_node->
context) {
18017 pm_parser_err_node(parser, node, PM_ERR_INVALID_YIELD);
18021 assert(
false &&
"unreachable");
18062 context_node = context_node->
prev;
18094parse_regular_expression_error(
const uint8_t *start,
const uint8_t *end,
const char *message,
void *data) {
18098 if (callback_data->
shared) {
18104 PM_PARSER_ERR_FORMAT(callback_data->
parser, location.
start, location.
end, PM_ERR_REGEXP_PARSE_ERROR, message);
18117 .shared = unescaped->
type == PM_STRING_SHARED
18120 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);
18127parse_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) {
18128 switch (parser->
current.type) {
18129 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
18130 parser_lex(parser);
18133 pm_accepts_block_stack_push(parser,
true);
18134 bool parsed_bare_hash =
false;
18136 while (!match2(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_EOF)) {
18137 bool accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
18141 if (accepted_newline && match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
18147 if (accept1(parser, PM_TOKEN_COMMA)) {
18150 if (accepted_newline) {
18151 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
18167 if (match1(parser, PM_TOKEN_BRACKET_RIGHT))
break;
18171 if (accept1(parser, PM_TOKEN_USTAR)) {
18175 if (match3(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_EOF)) {
18176 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
18178 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
18181 element = (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
18182 }
else if (match2(parser, PM_TOKEN_LABEL, PM_TOKEN_USTAR_STAR)) {
18183 if (parsed_bare_hash) {
18184 pm_parser_err_current(parser, PM_ERR_EXPRESSION_BARE_HASH);
18187 element = (
pm_node_t *) pm_keyword_hash_node_create(parser);
18190 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)) {
18191 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
18194 pm_static_literals_free(&hash_keys);
18195 parsed_bare_hash =
true;
18197 element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_ARRAY_EXPRESSION, (uint16_t) (depth + 1));
18199 if (pm_symbol_node_label_p(element) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
18200 if (parsed_bare_hash) {
18201 pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
18206 pm_hash_key_static_literals_add(parser, &hash_keys, element);
18209 if (parser->
previous.
type == PM_TOKEN_EQUAL_GREATER) {
18212 operator = not_provided(parser);
18215 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
18216 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, element, &
operator, value);
18217 pm_keyword_hash_node_elements_append(hash, assoc);
18220 if (accept1(parser, PM_TOKEN_COMMA) && !match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
18221 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
18224 pm_static_literals_free(&hash_keys);
18225 parsed_bare_hash =
true;
18229 pm_array_node_elements_append(array, element);
18230 if (PM_NODE_TYPE_P(element, PM_MISSING_NODE))
break;
18233 accept1(parser, PM_TOKEN_NEWLINE);
18235 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
18241 pm_array_node_close_set(array, &parser->
previous);
18242 pm_accepts_block_stack_pop(parser);
18246 case PM_TOKEN_PARENTHESIS_LEFT:
18247 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
18249 pm_node_flags_t flags = 0;
18252 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18254 parser_lex(parser);
18256 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
18257 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
18258 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
18265 if (match2(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_EOF)) {
18266 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
18268 pop_block_exits(parser, previous_block_exits);
18269 pm_node_list_free(¤t_block_exits);
18271 return (
pm_node_t *) pm_parentheses_node_create(parser, &opening, NULL, &parser->
previous, flags);
18276 pm_accepts_block_stack_push(parser,
true);
18278 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
18279 context_pop(parser);
18284 bool terminator_found =
false;
18286 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
18287 terminator_found =
true;
18288 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
18289 }
else if (accept1(parser, PM_TOKEN_NEWLINE)) {
18290 terminator_found =
true;
18293 if (terminator_found) {
18295 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
18296 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
18297 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
18306 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18307 if (opening.
type == PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
18308 lex_state_set(parser, PM_LEX_STATE_ENDARG);
18311 parser_lex(parser);
18312 pm_accepts_block_stack_pop(parser);
18314 pop_block_exits(parser, previous_block_exits);
18315 pm_node_list_free(¤t_block_exits);
18317 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) || PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
18323 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) && ((
pm_multi_target_node_t *) statement)->lparen_loc.start == NULL) {
18326 multi_target = pm_multi_target_node_create(parser);
18327 pm_multi_target_node_targets_append(parser, multi_target, statement);
18330 pm_location_t lparen_loc = PM_LOCATION_TOKEN_VALUE(&opening);
18339 if (match1(parser, PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
18340 result = parse_targets(parser, (
pm_node_t *) multi_target, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18341 accept1(parser, PM_TOKEN_NEWLINE);
18352 }
else if (binding_power != PM_BINDING_POWER_STATEMENT) {
18355 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
18356 }
else if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
18360 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
18370 pm_statements_node_body_append(parser, statements, statement,
true);
18379 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
18382 pm_statements_node_body_append(parser, statements, statement,
true);
18386 if (!terminator_found && !match1(parser, PM_TOKEN_EOF)) {
18392 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
18393 pm_statements_node_body_append(parser, statements, node,
true);
18400 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) parser->
recovering =
false;
18406 if (PM_NODE_TYPE_P(node, PM_MISSING_NODE))
break;
18410 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18411 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18412 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
break;
18413 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18415 }
else if (!match1(parser, PM_TOKEN_EOF)) {
18422 context_pop(parser);
18423 pm_accepts_block_stack_pop(parser);
18424 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
18433 if (PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
18435 pm_multi_target_node_targets_append(parser, multi_target, statement);
18437 statement = (
pm_node_t *) multi_target;
18441 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE)) {
18443 pm_token_t operator = { .
type = PM_TOKEN_EQUAL, .start = offset, .end = offset };
18449 pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
18453 pop_block_exits(parser, previous_block_exits);
18454 pm_node_list_free(¤t_block_exits);
18456 pm_void_statements_check(parser, statements,
true);
18459 case PM_TOKEN_BRACE_LEFT: {
18470 pm_accepts_block_stack_push(parser,
true);
18471 parser_lex(parser);
18475 if (!match2(parser, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_EOF)) {
18476 if (current_hash_keys != NULL) {
18477 parse_assocs(parser, current_hash_keys, (
pm_node_t *) node, (uint16_t) (depth + 1));
18480 parse_assocs(parser, &hash_keys, (
pm_node_t *) node, (uint16_t) (depth + 1));
18481 pm_static_literals_free(&hash_keys);
18484 accept1(parser, PM_TOKEN_NEWLINE);
18487 pm_accepts_block_stack_pop(parser);
18488 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM);
18489 pm_hash_node_closing_loc_set(node, &parser->
previous);
18493 case PM_TOKEN_CHARACTER_LITERAL: {
18498 .type = PM_TOKEN_STRING_BEGIN,
18499 .start = parser->
current.start,
18500 .end = parser->
current.start + 1
18503 .type = PM_TOKEN_STRING_CONTENT,
18504 .start = parser->
current.start + 1,
18510 pm_node_flag_set(node, parse_unescaped_encoding(parser));
18514 parser_lex(parser);
18518 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
18519 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18524 case PM_TOKEN_CLASS_VARIABLE: {
18525 parser_lex(parser);
18528 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18529 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18534 case PM_TOKEN_CONSTANT: {
18535 parser_lex(parser);
18541 match1(parser, PM_TOKEN_PARENTHESIS_LEFT) ||
18542 (accepts_command_call && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
18543 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
18544 match1(parser, PM_TOKEN_BRACE_LEFT)
18547 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18548 return (
pm_node_t *) pm_call_node_fcall_create(parser, &constant, &arguments);
18553 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
18556 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18561 case PM_TOKEN_UCOLON_COLON: {
18562 parser_lex(parser);
18565 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
18568 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
18569 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18574 case PM_TOKEN_UDOT_DOT:
18575 case PM_TOKEN_UDOT_DOT_DOT: {
18577 parser_lex(parser);
18579 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));
18585 if (match2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
18586 pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
18589 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
18591 case PM_TOKEN_FLOAT:
18592 parser_lex(parser);
18594 case PM_TOKEN_FLOAT_IMAGINARY:
18595 parser_lex(parser);
18596 return (
pm_node_t *) pm_float_node_imaginary_create(parser, &parser->
previous);
18597 case PM_TOKEN_FLOAT_RATIONAL:
18598 parser_lex(parser);
18600 case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY:
18601 parser_lex(parser);
18602 return (
pm_node_t *) pm_float_node_rational_imaginary_create(parser, &parser->
previous);
18603 case PM_TOKEN_NUMBERED_REFERENCE: {
18604 parser_lex(parser);
18607 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18608 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18613 case PM_TOKEN_GLOBAL_VARIABLE: {
18614 parser_lex(parser);
18617 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18618 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18623 case PM_TOKEN_BACK_REFERENCE: {
18624 parser_lex(parser);
18627 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18628 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18633 case PM_TOKEN_IDENTIFIER:
18634 case PM_TOKEN_METHOD_NAME: {
18635 parser_lex(parser);
18637 pm_node_t *node = parse_variable_call(parser);
18639 if (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
18647 if (parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1))) {
18650 pm_node_flag_unset((
pm_node_t *)call, PM_CALL_NODE_FLAGS_VARIABLE_CALL);
18657 const uint8_t *end = pm_arguments_end(&arguments);
18668 (accepts_command_call && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
18669 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
18670 match1(parser, PM_TOKEN_BRACE_LEFT)
18673 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18674 pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
18676 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
18680 parse_target_implicit_parameter(parser, node);
18686 assert(PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE));
18688 if (pm_token_is_numbered_parameter(identifier.
start, identifier.
end)) {
18689 parse_target_implicit_parameter(parser, node);
18692 pm_locals_unread(&pm_parser_scope_find(parser, cast->
depth)->
locals, cast->
name);
18696 pm_node_destroy(parser, node);
18701 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
18702 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18707 case PM_TOKEN_HEREDOC_START: {
18713 size_t common_whitespace = (size_t) -1;
18716 parser_lex(parser);
18722 if (match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18728 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18735 }
else if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) == NULL) {
18743 }
else if (PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18748 pm_node_flag_set(part, parse_unescaped_encoding(parser));
18751 cast->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
18755 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18757 cast->
base.
type = PM_X_STRING_NODE;
18760 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18761 parse_heredoc_dedent_string(&cast->
unescaped, common_whitespace);
18771 pm_node_list_append(&parts, part);
18773 while (!match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18774 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
18775 pm_node_list_append(&parts, part);
18781 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18783 cast->
parts = parts;
18786 pm_interpolated_xstring_node_closing_set(cast, &parser->
previous);
18792 pm_node_list_free(&parts);
18795 pm_interpolated_string_node_closing_set(cast, &parser->
previous);
18803 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18805 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18811 parse_heredoc_dedent(parser, nodes, common_whitespace);
18815 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
18816 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18821 case PM_TOKEN_INSTANCE_VARIABLE: {
18822 parser_lex(parser);
18825 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18826 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18831 case PM_TOKEN_INTEGER: {
18833 parser_lex(parser);
18836 case PM_TOKEN_INTEGER_IMAGINARY: {
18838 parser_lex(parser);
18839 return (
pm_node_t *) pm_integer_node_imaginary_create(parser, base, &parser->
previous);
18841 case PM_TOKEN_INTEGER_RATIONAL: {
18843 parser_lex(parser);
18844 return (
pm_node_t *) pm_integer_node_rational_create(parser, base, &parser->
previous);
18846 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: {
18848 parser_lex(parser);
18849 return (
pm_node_t *) pm_integer_node_rational_imaginary_create(parser, base, &parser->
previous);
18851 case PM_TOKEN_KEYWORD___ENCODING__:
18852 parser_lex(parser);
18853 return (
pm_node_t *) pm_source_encoding_node_create(parser, &parser->
previous);
18854 case PM_TOKEN_KEYWORD___FILE__:
18855 parser_lex(parser);
18857 case PM_TOKEN_KEYWORD___LINE__:
18858 parser_lex(parser);
18860 case PM_TOKEN_KEYWORD_ALIAS: {
18861 if (binding_power != PM_BINDING_POWER_STATEMENT) {
18862 pm_parser_err_current(parser, PM_ERR_STATEMENT_ALIAS);
18865 parser_lex(parser);
18868 pm_node_t *new_name = parse_alias_argument(parser,
true, (uint16_t) (depth + 1));
18869 pm_node_t *old_name = parse_alias_argument(parser,
false, (uint16_t) (depth + 1));
18871 switch (PM_NODE_TYPE(new_name)) {
18872 case PM_BACK_REFERENCE_READ_NODE:
18873 case PM_NUMBERED_REFERENCE_READ_NODE:
18874 case PM_GLOBAL_VARIABLE_READ_NODE: {
18875 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)) {
18876 if (PM_NODE_TYPE_P(old_name, PM_NUMBERED_REFERENCE_READ_NODE)) {
18877 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE);
18880 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18883 return (
pm_node_t *) pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name);
18885 case PM_SYMBOL_NODE:
18886 case PM_INTERPOLATED_SYMBOL_NODE: {
18887 if (!PM_NODE_TYPE_P(old_name, PM_SYMBOL_NODE) && !PM_NODE_TYPE_P(old_name, PM_INTERPOLATED_SYMBOL_NODE)) {
18888 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18893 return (
pm_node_t *) pm_alias_method_node_create(parser, &keyword, new_name, old_name);
18896 case PM_TOKEN_KEYWORD_CASE: {
18897 size_t opening_newline_index = token_newline_index(parser);
18898 parser_lex(parser);
18904 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18906 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18907 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18909 }
else if (match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_END)) {
18911 }
else if (!token_begins_expression_p(parser->
current.type)) {
18914 predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CASE_EXPRESSION_AFTER_CASE, (uint16_t) (depth + 1));
18915 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18918 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
18919 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18920 parser_lex(parser);
18922 pop_block_exits(parser, previous_block_exits);
18923 pm_node_list_free(¤t_block_exits);
18925 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18926 return (
pm_node_t *) pm_case_node_create(parser, &case_keyword, predicate, &parser->
previous);
18931 pm_token_t end_keyword = not_provided(parser);
18934 if (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18935 pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, &end_keyword);
18941 while (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18942 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18943 parser_lex(parser);
18946 pm_when_node_t *when_node = pm_when_node_create(parser, &when_keyword);
18949 if (accept1(parser, PM_TOKEN_USTAR)) {
18951 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
18953 pm_splat_node_t *splat_node = pm_splat_node_create(parser, &
operator, expression);
18954 pm_when_node_conditions_append(when_node, (
pm_node_t *) splat_node);
18956 if (PM_NODE_TYPE_P(expression, PM_MISSING_NODE))
break;
18958 pm_node_t *condition = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_CASE_EXPRESSION_AFTER_WHEN, (uint16_t) (depth + 1));
18959 pm_when_node_conditions_append(when_node, condition);
18963 if (PM_NODE_TYPE_P(condition, PM_MISSING_NODE))
break;
18967 if (PM_NODE_TYPE_P(condition, PM_STRING_NODE)) {
18968 pm_node_flag_set(condition, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
18969 }
else if (PM_NODE_TYPE_P(condition, PM_SOURCE_FILE_NODE)) {
18970 pm_node_flag_set(condition, PM_NODE_FLAG_STATIC_LITERAL);
18973 pm_when_clause_static_literals_add(parser, &literals, condition);
18975 }
while (accept1(parser, PM_TOKEN_COMMA));
18977 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18978 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
18979 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
18982 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_WHEN_DELIMITER);
18983 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
18986 if (!match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18988 if (statements != NULL) {
18989 pm_when_node_statements_set(when_node, statements);
18993 pm_case_node_condition_append(case_node, (
pm_node_t *) when_node);
18999 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
19002 pm_static_literals_free(&literals);
19005 pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate, &end_keyword);
19009 if (predicate == NULL) {
19010 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MATCH_MISSING_PREDICATE);
19016 while (match1(parser, PM_TOKEN_KEYWORD_IN)) {
19017 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
19022 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
19024 parser_lex(parser);
19029 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));
19032 pm_constant_id_list_free(&captures);
19037 if (accept1(parser, PM_TOKEN_KEYWORD_IF_MODIFIER)) {
19039 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
19040 pattern = (
pm_node_t *) pm_if_node_modifier_create(parser, pattern, &keyword, predicate);
19041 }
else if (accept1(parser, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) {
19043 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
19044 pattern = (
pm_node_t *) pm_unless_node_modifier_create(parser, pattern, &keyword, predicate);
19051 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
19052 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
19055 then_keyword = not_provided(parser);
19058 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_IN_DELIMITER);
19065 if (match3(parser, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19073 pm_node_t *condition = (
pm_node_t *) pm_in_node_create(parser, pattern, statements, &in_keyword, &then_keyword);
19074 pm_case_match_node_condition_append(case_node, condition);
19080 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
19086 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19087 if (accept1(parser, PM_TOKEN_KEYWORD_ELSE)) {
19091 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19092 else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser,
PM_CONTEXT_ELSE, (uint16_t) (depth + 1)), &parser->
current);
19094 else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->
current);
19097 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
19098 pm_case_node_else_clause_set((
pm_case_node_t *) node, else_node);
19104 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
19105 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM);
19107 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
19113 pop_block_exits(parser, previous_block_exits);
19114 pm_node_list_free(¤t_block_exits);
19118 case PM_TOKEN_KEYWORD_BEGIN: {
19119 size_t opening_newline_index = token_newline_index(parser);
19120 parser_lex(parser);
19123 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19126 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19129 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19130 pm_accepts_block_stack_push(parser,
true);
19131 begin_statements = parse_statements(parser,
PM_CONTEXT_BEGIN, (uint16_t) (depth + 1));
19132 pm_accepts_block_stack_pop(parser);
19133 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19136 pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
19137 parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
19138 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM);
19141 pm_begin_node_end_keyword_set(begin_node, &parser->
previous);
19143 pop_block_exits(parser, previous_block_exits);
19144 pm_node_list_free(¤t_block_exits);
19148 case PM_TOKEN_KEYWORD_BEGIN_UPCASE: {
19150 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19152 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19153 pm_parser_err_current(parser, PM_ERR_STATEMENT_PREEXE_BEGIN);
19156 parser_lex(parser);
19159 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_BEGIN_UPCASE_BRACE);
19163 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM);
19166 pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
19169 flush_block_exits(parser, previous_block_exits);
19170 pm_node_list_free(¤t_block_exits);
19172 return (
pm_node_t *) pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous);
19174 case PM_TOKEN_KEYWORD_BREAK:
19175 case PM_TOKEN_KEYWORD_NEXT:
19176 case PM_TOKEN_KEYWORD_RETURN: {
19177 parser_lex(parser);
19183 token_begins_expression_p(parser->
current.type) ||
19184 match2(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)
19186 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].
left;
19188 if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
19190 parse_arguments(parser, &arguments,
false, PM_TOKEN_EOF, (uint16_t) (depth + 1));
19193 if (!accepts_command_call && arguments.
arguments != NULL) {
19199 switch (keyword.
type) {
19200 case PM_TOKEN_KEYWORD_BREAK: {
19205 case PM_TOKEN_KEYWORD_NEXT: {
19210 case PM_TOKEN_KEYWORD_RETURN: {
19212 parse_return(parser, node);
19216 assert(
false &&
"unreachable");
19220 case PM_TOKEN_KEYWORD_SUPER: {
19221 parser_lex(parser);
19225 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
19230 ((arguments.
block == NULL) || PM_NODE_TYPE_P(arguments.
block, PM_BLOCK_NODE))
19232 return (
pm_node_t *) pm_forwarding_super_node_create(parser, &keyword, &arguments);
19235 return (
pm_node_t *) pm_super_node_create(parser, &keyword, &arguments);
19237 case PM_TOKEN_KEYWORD_YIELD: {
19238 parser_lex(parser);
19242 parse_arguments_list(parser, &arguments,
false, accepts_command_call, (uint16_t) (depth + 1));
19248 if (arguments.
block != NULL) {
19249 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
19250 pm_node_destroy(parser, arguments.
block);
19251 arguments.
block = NULL;
19259 case PM_TOKEN_KEYWORD_CLASS: {
19260 size_t opening_newline_index = token_newline_index(parser);
19261 parser_lex(parser);
19264 pm_do_loop_stack_push(parser,
false);
19267 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19269 if (accept1(parser, PM_TOKEN_LESS_LESS)) {
19271 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));
19273 pm_parser_scope_push(parser,
true);
19274 if (!match2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
19279 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19280 pm_accepts_block_stack_push(parser,
true);
19282 pm_accepts_block_stack_pop(parser);
19285 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
19286 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
19287 statements = (
pm_node_t *) 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));
19289 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
19292 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
19297 pm_parser_scope_pop(parser);
19298 pm_do_loop_stack_pop(parser);
19300 flush_block_exits(parser, previous_block_exits);
19301 pm_node_list_free(¤t_block_exits);
19303 return (
pm_node_t *) pm_singleton_class_node_create(parser, &locals, &class_keyword, &
operator, expression, statements, &parser->
previous);
19306 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_CLASS_NAME, (uint16_t) (depth + 1));
19308 if (name.
type != PM_TOKEN_CONSTANT) {
19309 pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME);
19315 if (match1(parser, PM_TOKEN_LESS)) {
19316 inheritance_operator = parser->
current;
19317 lex_state_set(parser, PM_LEX_STATE_BEG);
19320 parser_lex(parser);
19322 superclass = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CLASS_SUPERCLASS, (uint16_t) (depth + 1));
19324 inheritance_operator = not_provided(parser);
19328 pm_parser_scope_push(parser,
true);
19330 if (inheritance_operator.
type != PM_TOKEN_NOT_PROVIDED) {
19331 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CLASS_UNEXPECTED_END);
19333 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19337 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19338 pm_accepts_block_stack_push(parser,
true);
19340 pm_accepts_block_stack_pop(parser);
19343 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
19344 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
19345 statements = (
pm_node_t *) 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));
19347 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
19350 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
19352 if (context_def_p(parser)) {
19353 pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
19359 pm_parser_scope_pop(parser);
19360 pm_do_loop_stack_pop(parser);
19362 if (!PM_NODE_TYPE_P(constant_path, PM_CONSTANT_PATH_NODE) && !(PM_NODE_TYPE_P(constant_path, PM_CONSTANT_READ_NODE))) {
19363 pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
19366 pop_block_exits(parser, previous_block_exits);
19367 pm_node_list_free(¤t_block_exits);
19369 return (
pm_node_t *) pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, &inheritance_operator, superclass, statements, &parser->
previous);
19371 case PM_TOKEN_KEYWORD_DEF: {
19373 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19376 size_t opening_newline_index = token_newline_index(parser);
19386 parser_lex(parser);
19390 bool valid_name =
true;
19392 switch (parser->
current.type) {
19393 case PM_CASE_OPERATOR:
19394 pm_parser_scope_push(parser,
true);
19395 lex_state_set(parser, PM_LEX_STATE_ENDFN);
19396 parser_lex(parser);
19400 case PM_TOKEN_IDENTIFIER: {
19401 parser_lex(parser);
19403 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
19404 receiver = parse_variable_call(parser);
19406 pm_parser_scope_push(parser,
true);
19407 lex_state_set(parser, PM_LEX_STATE_FNAME);
19408 parser_lex(parser);
19411 name = parse_method_definition_name(parser);
19414 pm_parser_scope_push(parser,
true);
19421 case PM_TOKEN_INSTANCE_VARIABLE:
19422 case PM_TOKEN_CLASS_VARIABLE:
19423 case PM_TOKEN_GLOBAL_VARIABLE:
19424 valid_name =
false;
19426 case PM_TOKEN_CONSTANT:
19427 case PM_TOKEN_KEYWORD_NIL:
19428 case PM_TOKEN_KEYWORD_SELF:
19429 case PM_TOKEN_KEYWORD_TRUE:
19430 case PM_TOKEN_KEYWORD_FALSE:
19431 case PM_TOKEN_KEYWORD___FILE__:
19432 case PM_TOKEN_KEYWORD___LINE__:
19433 case PM_TOKEN_KEYWORD___ENCODING__: {
19434 pm_parser_scope_push(parser,
true);
19435 parser_lex(parser);
19439 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
19440 lex_state_set(parser, PM_LEX_STATE_FNAME);
19441 parser_lex(parser);
19444 switch (identifier.
type) {
19445 case PM_TOKEN_CONSTANT:
19446 receiver = (
pm_node_t *) pm_constant_read_node_create(parser, &identifier);
19448 case PM_TOKEN_INSTANCE_VARIABLE:
19449 receiver = (
pm_node_t *) pm_instance_variable_read_node_create(parser, &identifier);
19451 case PM_TOKEN_CLASS_VARIABLE:
19452 receiver = (
pm_node_t *) pm_class_variable_read_node_create(parser, &identifier);
19454 case PM_TOKEN_GLOBAL_VARIABLE:
19455 receiver = (
pm_node_t *) pm_global_variable_read_node_create(parser, &identifier);
19457 case PM_TOKEN_KEYWORD_NIL:
19458 receiver = (
pm_node_t *) pm_nil_node_create(parser, &identifier);
19460 case PM_TOKEN_KEYWORD_SELF:
19461 receiver = (
pm_node_t *) pm_self_node_create(parser, &identifier);
19463 case PM_TOKEN_KEYWORD_TRUE:
19464 receiver = (
pm_node_t *) pm_true_node_create(parser, &identifier);
19466 case PM_TOKEN_KEYWORD_FALSE:
19467 receiver = (
pm_node_t *) pm_false_node_create(parser, &identifier);
19469 case PM_TOKEN_KEYWORD___FILE__:
19470 receiver = (
pm_node_t *) pm_source_file_node_create(parser, &identifier);
19472 case PM_TOKEN_KEYWORD___LINE__:
19473 receiver = (
pm_node_t *) pm_source_line_node_create(parser, &identifier);
19475 case PM_TOKEN_KEYWORD___ENCODING__:
19476 receiver = (
pm_node_t *) pm_source_encoding_node_create(parser, &identifier);
19482 name = parse_method_definition_name(parser);
19492 case PM_TOKEN_PARENTHESIS_LEFT: {
19497 context_pop(parser);
19498 parser_lex(parser);
19501 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEF_RECEIVER, (uint16_t) (depth + 1));
19503 accept1(parser, PM_TOKEN_NEWLINE);
19504 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19507 lex_state_set(parser, PM_LEX_STATE_FNAME);
19508 expect2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON, PM_ERR_DEF_RECEIVER_TERM);
19511 receiver = (
pm_node_t *) pm_parentheses_node_create(parser, &lparen, expression, &rparen, 0);
19515 pm_parser_scope_push(parser,
true);
19517 name = parse_method_definition_name(parser);
19521 pm_parser_scope_push(parser,
true);
19522 name = parse_method_definition_name(parser);
19530 switch (parser->
current.type) {
19531 case PM_TOKEN_PARENTHESIS_LEFT: {
19532 parser_lex(parser);
19535 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19538 params = parse_parameters(parser, PM_BINDING_POWER_DEFINED,
true,
false,
true,
true,
false, (uint16_t) (depth + 1));
19541 lex_state_set(parser, PM_LEX_STATE_BEG);
19544 context_pop(parser);
19545 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19554 case PM_CASE_PARAMETER: {
19557 if (parser->
current.type == PM_TOKEN_LABEL) {
19558 lex_state_set(parser, parser->
lex_state | PM_LEX_STATE_LABEL);
19561 lparen = not_provided(parser);
19562 rparen = not_provided(parser);
19563 params = parse_parameters(parser, PM_BINDING_POWER_DEFINED,
false,
false,
true,
true,
false, (uint16_t) (depth + 1));
19565 context_pop(parser);
19569 lparen = not_provided(parser);
19570 rparen = not_provided(parser);
19573 context_pop(parser);
19582 if (accept1(parser, PM_TOKEN_EQUAL)) {
19583 if (token_is_setter_name(&name)) {
19584 pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
19589 pm_do_loop_stack_push(parser,
false);
19590 statements = (
pm_node_t *) pm_statements_node_create(parser);
19592 bool allow_command_call;
19594 allow_command_call = accepts_command_call;
19597 allow_command_call = binding_power == PM_BINDING_POWER_ASSIGNMENT || binding_power < PM_BINDING_POWER_COMPOSITION;
19600 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_DEFINED + 1, allow_command_call,
false, PM_ERR_DEF_ENDLESS, (uint16_t) (depth + 1));
19602 if (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
19606 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));
19607 context_pop(parser);
19609 statement = (
pm_node_t *) pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value);
19612 pm_statements_node_body_append(parser, (
pm_statements_node_t *) statements, statement,
false);
19613 pm_do_loop_stack_pop(parser);
19614 context_pop(parser);
19615 end_keyword = not_provided(parser);
19617 equal = not_provided(parser);
19619 if (lparen.
type == PM_TOKEN_NOT_PROVIDED) {
19620 lex_state_set(parser, PM_LEX_STATE_BEG);
19622 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_DEF_PARAMS_TERM);
19624 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19627 pm_accepts_block_stack_push(parser,
true);
19628 pm_do_loop_stack_push(parser,
false);
19630 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19631 pm_accepts_block_stack_push(parser,
true);
19633 pm_accepts_block_stack_pop(parser);
19636 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
19637 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
19638 statements = (
pm_node_t *) 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));
19640 parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword,
false,
false);
19643 pm_accepts_block_stack_pop(parser);
19644 pm_do_loop_stack_pop(parser);
19646 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_DEF_TERM);
19652 pm_parser_scope_pop(parser);
19659 pm_constant_id_t name_id = pm_parser_constant_id_location(parser, name.
start, parse_operator_symbol_name(&name));
19661 flush_block_exits(parser, previous_block_exits);
19662 pm_node_list_free(¤t_block_exits);
19664 return (
pm_node_t *) pm_def_node_create(
19680 case PM_TOKEN_KEYWORD_DEFINED: {
19681 parser_lex(parser);
19689 bool newline = accept1(parser, PM_TOKEN_NEWLINE);
19691 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19694 if (newline && accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19695 expression = (
pm_node_t *) pm_parentheses_node_create(parser, &lparen, NULL, &parser->
previous, 0);
19696 lparen = not_provided(parser);
19697 rparen = not_provided(parser);
19699 expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19702 rparen = not_provided(parser);
19704 accept1(parser, PM_TOKEN_NEWLINE);
19705 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19710 lparen = not_provided(parser);
19711 rparen = not_provided(parser);
19712 expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19715 context_pop(parser);
19716 return (
pm_node_t *) pm_defined_node_create(
19721 &PM_LOCATION_TOKEN_VALUE(&keyword)
19724 case PM_TOKEN_KEYWORD_END_UPCASE: {
19725 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19726 pm_parser_err_current(parser, PM_ERR_STATEMENT_POSTEXE_END);
19729 parser_lex(parser);
19732 if (context_def_p(parser)) {
19733 pm_parser_warn_token(parser, &keyword, PM_WARN_END_IN_METHOD);
19736 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_END_UPCASE_BRACE);
19740 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM);
19741 return (
pm_node_t *) pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous);
19743 case PM_TOKEN_KEYWORD_FALSE:
19744 parser_lex(parser);
19746 case PM_TOKEN_KEYWORD_FOR: {
19747 size_t opening_newline_index = token_newline_index(parser);
19748 parser_lex(parser);
19756 if (accept1(parser, PM_TOKEN_USTAR)) {
19760 if (token_begins_expression_p(parser->
current.type)) {
19761 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19764 index = (
pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
19765 }
else if (token_begins_expression_p(parser->
current.type)) {
19766 index = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
19768 pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX);
19769 index = (
pm_node_t *) pm_missing_node_create(parser, for_keyword.
start, for_keyword.
end);
19773 if (match1(parser, PM_TOKEN_COMMA)) {
19774 index = parse_targets(parser, index, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19776 index = parse_target(parser, index,
false,
false);
19779 context_pop(parser);
19780 pm_do_loop_stack_push(parser,
true);
19782 expect1(parser, PM_TOKEN_KEYWORD_IN, PM_ERR_FOR_IN);
19785 pm_node_t *collection = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_FOR_COLLECTION, (uint16_t) (depth + 1));
19786 pm_do_loop_stack_pop(parser);
19789 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19792 do_keyword = not_provided(parser);
19793 if (!match2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE)) {
19799 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19800 statements = parse_statements(parser,
PM_CONTEXT_FOR, (uint16_t) (depth + 1));
19803 parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword,
false,
false);
19804 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM);
19806 return (
pm_node_t *) pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, &do_keyword, &parser->
previous);
19808 case PM_TOKEN_KEYWORD_IF:
19809 if (parser_end_of_line_p(parser)) {
19810 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
19813 size_t opening_newline_index = token_newline_index(parser);
19814 bool if_after_else = parser->
previous.
type == PM_TOKEN_KEYWORD_ELSE;
19815 parser_lex(parser);
19817 return parse_conditional(parser,
PM_CONTEXT_IF, opening_newline_index, if_after_else, (uint16_t) (depth + 1));
19818 case PM_TOKEN_KEYWORD_UNDEF: {
19819 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19820 pm_parser_err_current(parser, PM_ERR_STATEMENT_UNDEF);
19823 parser_lex(parser);
19825 pm_node_t *name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19827 if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) {
19828 pm_node_destroy(parser, name);
19830 pm_undef_node_append(undef, name);
19832 while (match1(parser, PM_TOKEN_COMMA)) {
19833 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
19834 parser_lex(parser);
19835 name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19837 if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) {
19838 pm_node_destroy(parser, name);
19842 pm_undef_node_append(undef, name);
19848 case PM_TOKEN_KEYWORD_NOT: {
19849 parser_lex(parser);
19858 if (!accepts_command_call && !match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19859 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES)) {
19860 pm_parser_err(parser, parser->
previous.
end, parser->
previous.
end + 1, PM_ERR_EXPECT_LPAREN_AFTER_NOT_LPAREN);
19862 accept1(parser, PM_TOKEN_NEWLINE);
19863 pm_parser_err_current(parser, PM_ERR_EXPECT_LPAREN_AFTER_NOT_OTHER);
19869 accept1(parser, PM_TOKEN_NEWLINE);
19871 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19874 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19875 receiver = (
pm_node_t *) pm_parentheses_node_create(parser, &lparen, NULL, &parser->
previous, 0);
19877 arguments.
opening_loc = PM_LOCATION_TOKEN_VALUE(&lparen);
19878 receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19881 accept1(parser, PM_TOKEN_NEWLINE);
19882 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19887 receiver = parse_expression(parser, PM_BINDING_POWER_NOT,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19890 return (
pm_node_t *) pm_call_node_not_create(parser, receiver, &message, &arguments);
19892 case PM_TOKEN_KEYWORD_UNLESS: {
19893 size_t opening_newline_index = token_newline_index(parser);
19894 parser_lex(parser);
19896 return parse_conditional(parser,
PM_CONTEXT_UNLESS, opening_newline_index,
false, (uint16_t) (depth + 1));
19898 case PM_TOKEN_KEYWORD_MODULE: {
19900 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19902 size_t opening_newline_index = token_newline_index(parser);
19903 parser_lex(parser);
19906 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_MODULE_NAME, (uint16_t) (depth + 1));
19911 if (PM_NODE_TYPE_P(constant_path, PM_MISSING_NODE)) {
19912 pop_block_exits(parser, previous_block_exits);
19913 pm_node_list_free(¤t_block_exits);
19916 return (
pm_node_t *) pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing);
19919 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
19922 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
19923 constant_path = (
pm_node_t *) pm_constant_path_node_create(parser, constant_path, &double_colon, &parser->
previous);
19930 if (name.
type != PM_TOKEN_CONSTANT) {
19931 pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
19934 pm_parser_scope_push(parser,
true);
19935 accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE);
19938 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19939 pm_accepts_block_stack_push(parser,
true);
19941 pm_accepts_block_stack_pop(parser);
19944 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
19945 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
19946 statements = (
pm_node_t *) 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));
19948 parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword,
false,
false);
19954 pm_parser_scope_pop(parser);
19955 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM);
19957 if (context_def_p(parser)) {
19958 pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
19961 pop_block_exits(parser, previous_block_exits);
19962 pm_node_list_free(¤t_block_exits);
19964 return (
pm_node_t *) pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->
previous);
19966 case PM_TOKEN_KEYWORD_NIL:
19967 parser_lex(parser);
19969 case PM_TOKEN_KEYWORD_REDO: {
19970 parser_lex(parser);
19977 case PM_TOKEN_KEYWORD_RETRY: {
19978 parser_lex(parser);
19981 parse_retry(parser, node);
19985 case PM_TOKEN_KEYWORD_SELF:
19986 parser_lex(parser);
19988 case PM_TOKEN_KEYWORD_TRUE:
19989 parser_lex(parser);
19991 case PM_TOKEN_KEYWORD_UNTIL: {
19992 size_t opening_newline_index = token_newline_index(parser);
19995 pm_do_loop_stack_push(parser,
true);
19997 parser_lex(parser);
19999 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
20001 pm_do_loop_stack_pop(parser);
20002 context_pop(parser);
20005 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
20008 do_keyword = not_provided(parser);
20009 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
20013 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
20014 pm_accepts_block_stack_push(parser,
true);
20015 statements = parse_statements(parser,
PM_CONTEXT_UNTIL, (uint16_t) (depth + 1));
20016 pm_accepts_block_stack_pop(parser);
20017 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
20020 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
20021 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM);
20023 return (
pm_node_t *) pm_until_node_create(parser, &keyword, &do_keyword, &parser->
previous, predicate, statements, 0);
20025 case PM_TOKEN_KEYWORD_WHILE: {
20026 size_t opening_newline_index = token_newline_index(parser);
20029 pm_do_loop_stack_push(parser,
true);
20031 parser_lex(parser);
20033 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
20035 pm_do_loop_stack_pop(parser);
20036 context_pop(parser);
20039 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
20042 do_keyword = not_provided(parser);
20043 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
20047 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
20048 pm_accepts_block_stack_push(parser,
true);
20049 statements = parse_statements(parser,
PM_CONTEXT_WHILE, (uint16_t) (depth + 1));
20050 pm_accepts_block_stack_pop(parser);
20051 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
20054 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
20055 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM);
20057 return (
pm_node_t *) pm_while_node_create(parser, &keyword, &do_keyword, &parser->
previous, predicate, statements, 0);
20059 case PM_TOKEN_PERCENT_LOWER_I: {
20060 parser_lex(parser);
20064 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20065 accept1(parser, PM_TOKEN_WORDS_SEP);
20066 if (match1(parser, PM_TOKEN_STRING_END))
break;
20068 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20071 pm_array_node_elements_append(array, (
pm_node_t *) pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing));
20074 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_LOWER_ELEMENT);
20078 if (match1(parser, PM_TOKEN_EOF)) {
20079 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
20082 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_LOWER_TERM);
20084 pm_array_node_close_set(array, &closing);
20088 case PM_TOKEN_PERCENT_UPPER_I: {
20089 parser_lex(parser);
20097 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20098 switch (parser->
current.type) {
20099 case PM_TOKEN_WORDS_SEP: {
20100 if (current == NULL) {
20106 pm_array_node_elements_append(array, current);
20110 parser_lex(parser);
20113 case PM_TOKEN_STRING_CONTENT: {
20117 if (current == NULL) {
20121 current = (
pm_node_t *) pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing);
20122 parser_lex(parser);
20123 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
20128 parser_lex(parser);
20131 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20140 pm_node_t *second_string = (
pm_node_t *) pm_string_node_create_current_string(parser, &opening, &parser->
previous, &closing);
20141 parser_lex(parser);
20144 pm_interpolated_symbol_node_append(interpolated, first_string);
20145 pm_interpolated_symbol_node_append(interpolated, second_string);
20150 assert(
false &&
"unreachable");
20155 case PM_TOKEN_EMBVAR: {
20156 bool start_location_set =
false;
20157 if (current == NULL) {
20163 current = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
20164 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20173 pm_interpolated_symbol_node_append(interpolated, current);
20175 start_location_set =
true;
20182 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20184 if (!start_location_set) {
20189 case PM_TOKEN_EMBEXPR_BEGIN: {
20190 bool start_location_set =
false;
20191 if (current == NULL) {
20197 current = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
20198 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20208 pm_interpolated_symbol_node_append(interpolated, current);
20210 start_location_set =
true;
20212 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
20216 assert(
false &&
"unreachable");
20219 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20221 if (!start_location_set) {
20227 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_UPPER_ELEMENT);
20228 parser_lex(parser);
20235 pm_array_node_elements_append(array, current);
20239 if (match1(parser, PM_TOKEN_EOF)) {
20240 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_UPPER_TERM);
20243 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_UPPER_TERM);
20245 pm_array_node_close_set(array, &closing);
20249 case PM_TOKEN_PERCENT_LOWER_W: {
20250 parser_lex(parser);
20255 accept1(parser, PM_TOKEN_WORDS_SEP);
20257 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20258 accept1(parser, PM_TOKEN_WORDS_SEP);
20259 if (match1(parser, PM_TOKEN_STRING_END))
break;
20261 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20266 pm_array_node_elements_append(array,
string);
20269 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_LOWER_ELEMENT);
20273 if (match1(parser, PM_TOKEN_EOF)) {
20274 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_LOWER_TERM);
20277 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_LOWER_TERM);
20280 pm_array_node_close_set(array, &closing);
20283 case PM_TOKEN_PERCENT_UPPER_W: {
20284 parser_lex(parser);
20292 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20293 switch (parser->
current.type) {
20294 case PM_TOKEN_WORDS_SEP: {
20299 if (current == NULL) {
20306 pm_array_node_elements_append(array, current);
20310 parser_lex(parser);
20313 case PM_TOKEN_STRING_CONTENT: {
20318 pm_node_flag_set(
string, parse_unescaped_encoding(parser));
20319 parser_lex(parser);
20321 if (current == NULL) {
20327 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
20332 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20338 pm_interpolated_string_node_append(interpolated, current);
20339 pm_interpolated_string_node_append(interpolated,
string);
20342 assert(
false &&
"unreachable");
20347 case PM_TOKEN_EMBVAR: {
20348 if (current == NULL) {
20355 current = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
20356 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20364 pm_interpolated_string_node_append(interpolated, current);
20372 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20376 case PM_TOKEN_EMBEXPR_BEGIN: {
20377 if (current == NULL) {
20384 current = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
20385 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20393 pm_interpolated_string_node_append(interpolated, current);
20395 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
20400 assert(
false &&
"unreachable");
20403 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20408 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_UPPER_ELEMENT);
20409 parser_lex(parser);
20416 pm_array_node_elements_append(array, current);
20420 if (match1(parser, PM_TOKEN_EOF)) {
20421 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_UPPER_TERM);
20424 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_UPPER_TERM);
20427 pm_array_node_close_set(array, &closing);
20430 case PM_TOKEN_REGEXP_BEGIN: {
20432 parser_lex(parser);
20434 if (match1(parser, PM_TOKEN_REGEXP_END)) {
20439 .
type = PM_TOKEN_STRING_CONTENT,
20444 parser_lex(parser);
20447 pm_node_flag_set(node, PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING);
20454 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20462 parser_lex(parser);
20467 if (accept1(parser, PM_TOKEN_REGEXP_END)) {
20474 if (!match1(parser, PM_TOKEN_EQUAL_TILDE)) {
20475 parse_regular_expression_errors(parser, node);
20478 pm_node_flag_set((
pm_node_t *) node, parse_and_validate_regular_expression_encoding(parser, &unescaped, ascii_only, node->base.
flags));
20484 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20494 pm_node_flag_set(part, PM_STRING_FLAGS_FORCED_BINARY_ENCODING);
20497 pm_interpolated_regular_expression_node_append(interpolated, part);
20502 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20508 while (!match2(parser, PM_TOKEN_REGEXP_END, PM_TOKEN_EOF)) {
20509 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20510 pm_interpolated_regular_expression_node_append(interpolated, part);
20515 if (match1(parser, PM_TOKEN_EOF)) {
20516 pm_parser_err_token(parser, &opening, PM_ERR_REGEXP_TERM);
20519 expect1(parser, PM_TOKEN_REGEXP_END, PM_ERR_REGEXP_TERM);
20522 pm_interpolated_regular_expression_node_closing_set(parser, interpolated, &closing);
20525 case PM_TOKEN_BACKTICK:
20526 case PM_TOKEN_PERCENT_LOWER_X: {
20527 parser_lex(parser);
20534 if (match1(parser, PM_TOKEN_STRING_END)) {
20539 .
type = PM_TOKEN_STRING_CONTENT,
20544 parser_lex(parser);
20545 return (
pm_node_t *) pm_xstring_node_create(parser, &opening, &content, &parser->
previous);
20550 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20557 parser_lex(parser);
20559 if (match1(parser, PM_TOKEN_STRING_END)) {
20560 pm_node_t *node = (
pm_node_t *) pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
20561 pm_node_flag_set(node, parse_unescaped_encoding(parser));
20562 parser_lex(parser);
20568 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20574 pm_node_flag_set(part, parse_unescaped_encoding(parser));
20576 pm_interpolated_xstring_node_append(node, part);
20581 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20585 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20586 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20587 pm_interpolated_xstring_node_append(node, part);
20592 if (match1(parser, PM_TOKEN_EOF)) {
20593 pm_parser_err_token(parser, &opening, PM_ERR_XSTRING_TERM);
20596 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_XSTRING_TERM);
20598 pm_interpolated_xstring_node_closing_set(node, &closing);
20602 case PM_TOKEN_USTAR: {
20603 parser_lex(parser);
20608 if (binding_power != PM_BINDING_POWER_STATEMENT) {
20609 pm_parser_err_prefix(parser, diag_id);
20616 if (token_begins_expression_p(parser->
current.type)) {
20617 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
20622 if (match1(parser, PM_TOKEN_COMMA)) {
20623 return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
20625 return parse_target_validate(parser, splat,
true);
20628 case PM_TOKEN_BANG: {
20629 if (binding_power > PM_BINDING_POWER_UNARY) {
20630 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20633 parser_lex(parser);
20636 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));
20637 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"!");
20639 pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
20642 case PM_TOKEN_TILDE: {
20643 if (binding_power > PM_BINDING_POWER_UNARY) {
20644 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20646 parser_lex(parser);
20649 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20650 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"~");
20654 case PM_TOKEN_UMINUS: {
20655 if (binding_power > PM_BINDING_POWER_UNARY) {
20656 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20658 parser_lex(parser);
20661 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20662 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"-@");
20666 case PM_TOKEN_UMINUS_NUM: {
20667 parser_lex(parser);
20670 pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20672 if (accept1(parser, PM_TOKEN_STAR_STAR)) {
20674 pm_node_t *exponent = parse_expression(parser, pm_binding_powers[exponent_operator.
type].right,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
20675 node = (
pm_node_t *) pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0);
20676 node = (
pm_node_t *) pm_call_node_unary_create(parser, &
operator, node,
"-@");
20678 switch (PM_NODE_TYPE(node)) {
20679 case PM_INTEGER_NODE:
20680 case PM_FLOAT_NODE:
20681 case PM_RATIONAL_NODE:
20682 case PM_IMAGINARY_NODE:
20683 parse_negative_numeric(node);
20686 node = (
pm_node_t *) pm_call_node_unary_create(parser, &
operator, node,
"-@");
20693 case PM_TOKEN_MINUS_GREATER: {
20697 size_t opening_newline_index = token_newline_index(parser);
20698 pm_accepts_block_stack_push(parser,
true);
20699 parser_lex(parser);
20702 pm_parser_scope_push(parser,
false);
20706 switch (parser->
current.type) {
20707 case PM_TOKEN_PARENTHESIS_LEFT: {
20709 parser_lex(parser);
20711 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
20712 block_parameters = pm_block_parameters_node_create(parser, NULL, &opening);
20714 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
true, (uint16_t) (depth + 1));
20717 accept1(parser, PM_TOKEN_NEWLINE);
20718 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
20720 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
20723 case PM_CASE_PARAMETER: {
20724 pm_accepts_block_stack_push(parser,
false);
20726 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
false, (uint16_t) (depth + 1));
20727 pm_accepts_block_stack_pop(parser);
20731 block_parameters = NULL;
20740 if (accept1(parser, PM_TOKEN_LAMBDA_BEGIN)) {
20743 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
20747 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20748 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE);
20750 expect1(parser, PM_TOKEN_KEYWORD_DO, PM_ERR_LAMBDA_OPEN);
20753 if (!match3(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20754 pm_accepts_block_stack_push(parser,
true);
20756 pm_accepts_block_stack_pop(parser);
20759 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20760 assert(body == NULL || PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE));
20761 body = (
pm_node_t *) parse_rescues_implicit_begin(parser, opening_newline_index, &
operator, opening.
start, (
pm_statements_node_t *) body, PM_RESCUES_LAMBDA, (uint16_t) (depth + 1));
20763 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20766 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END);
20770 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
20773 pm_parser_scope_pop(parser);
20774 pm_accepts_block_stack_pop(parser);
20776 return (
pm_node_t *) pm_lambda_node_create(parser, &locals, &
operator, &opening, &parser->
previous, parameters, body);
20778 case PM_TOKEN_UPLUS: {
20779 if (binding_power > PM_BINDING_POWER_UNARY) {
20780 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20782 parser_lex(parser);
20785 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20786 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"+@");
20790 case PM_TOKEN_STRING_BEGIN:
20791 return parse_strings(parser, NULL, accepts_label, (uint16_t) (depth + 1));
20792 case PM_TOKEN_SYMBOL_BEGIN: {
20794 parser_lex(parser);
20796 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_END, (uint16_t) (depth + 1));
20807 if (diag_id != PM_ERR_CANNOT_PARSE_EXPRESSION) {
20808 pm_parser_err_prefix(parser, diag_id);
20814 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT,
pm_token_type_human(parser->
current.type), context_human(recoverable));
20815 }
else if (diag_id == PM_ERR_CANNOT_PARSE_EXPRESSION) {
20821 pm_parser_err_prefix(parser, diag_id);
20839parse_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) {
20840 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));
20844 if (match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
20848 parser_lex(parser);
20850 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));
20851 context_pop(parser);
20853 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
20865 switch (PM_NODE_TYPE(node)) {
20866 case PM_BEGIN_NODE: {
20871 case PM_LOCAL_VARIABLE_WRITE_NODE: {
20873 pm_locals_read(&pm_parser_scope_find(parser, cast->
depth)->
locals, cast->
name);
20876 case PM_PARENTHESES_NODE: {
20878 if (cast->
body != NULL) parse_assignment_value_local(parser, cast->
body);
20881 case PM_STATEMENTS_NODE: {
20886 parse_assignment_value_local(parser, statement);
20908parse_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) {
20909 bool permitted =
true;
20910 if (previous_binding_power != PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_USTAR)) permitted =
false;
20912 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));
20913 if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE);
20915 parse_assignment_value_local(parser, value);
20916 bool single_value =
true;
20918 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && (PM_NODE_TYPE_P(value, PM_SPLAT_NODE) || match1(parser, PM_TOKEN_COMMA))) {
20919 single_value =
false;
20924 pm_array_node_elements_append(array, value);
20927 while (accept1(parser, PM_TOKEN_COMMA)) {
20928 pm_node_t *element = parse_starred_expression(parser, binding_power,
false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1));
20930 pm_array_node_elements_append(array, element);
20931 if (PM_NODE_TYPE_P(element, PM_MISSING_NODE))
break;
20933 parse_assignment_value_local(parser, element);
20939 if ((single_value || (binding_power == (PM_BINDING_POWER_MULTI_ASSIGNMENT + 1))) && match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
20943 parser_lex(parser);
20945 bool accepts_command_call_inner =
false;
20949 if (PM_NODE_TYPE_P(value, PM_CALL_NODE)) {
20952 accepts_command_call_inner =
true;
20956 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));
20957 context_pop(parser);
20959 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
20975 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_ARGUMENTS);
20980 if (call_node->
block != NULL) {
20981 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_BLOCK);
20983 call_node->
block = NULL;
21012static inline const uint8_t *
21013pm_named_capture_escape_hex(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
21016 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
21017 uint8_t value = escape_hexadecimal_digit(*cursor);
21020 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
21021 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(*cursor));
21025 pm_buffer_append_byte(unescaped, value);
21027 pm_buffer_append_string(unescaped,
"\\x", 2);
21033static inline const uint8_t *
21034pm_named_capture_escape_octal(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
21035 uint8_t value = (uint8_t) (*cursor -
'0');
21038 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
21039 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
21042 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
21043 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
21048 pm_buffer_append_byte(unescaped, value);
21052static inline const uint8_t *
21053pm_named_capture_escape_unicode(
pm_parser_t *parser,
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
21054 const uint8_t *start = cursor - 1;
21057 if (cursor >= end) {
21058 pm_buffer_append_string(unescaped,
"\\u", 2);
21062 if (*cursor !=
'{') {
21063 size_t length = pm_strspn_hexadecimal_digit(cursor, MIN(end - cursor, 4));
21064 uint32_t value = escape_unicode(parser, cursor, length);
21066 if (!pm_buffer_append_unicode_codepoint(unescaped, value)) {
21067 pm_buffer_append_string(unescaped, (
const char *) start, (
size_t) ((cursor + length) - start));
21070 return cursor + length;
21075 while (cursor < end && *cursor ==
' ') cursor++;
21077 if (cursor >= end)
break;
21078 if (*cursor ==
'}') {
21083 size_t length = pm_strspn_hexadecimal_digit(cursor, end - cursor);
21084 uint32_t value = escape_unicode(parser, cursor, length);
21086 (void) pm_buffer_append_unicode_codepoint(unescaped, value);
21094pm_named_capture_escape(
pm_parser_t *parser,
pm_buffer_t *unescaped,
const uint8_t *source,
const size_t length,
const uint8_t *cursor) {
21095 const uint8_t *end = source + length;
21096 pm_buffer_append_string(unescaped, (
const char *) source, (
size_t) (cursor - source));
21099 if (++cursor >= end) {
21100 pm_buffer_append_byte(unescaped,
'\\');
21106 cursor = pm_named_capture_escape_hex(unescaped, cursor, end);
21108 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
21109 cursor = pm_named_capture_escape_octal(unescaped, cursor, end);
21112 cursor = pm_named_capture_escape_unicode(parser, unescaped, cursor, end);
21115 pm_buffer_append_byte(unescaped,
'\\');
21119 const uint8_t *next_cursor = pm_memchr(cursor,
'\\', (
size_t) (end - cursor), parser->
encoding_changed, parser->
encoding);
21120 if (next_cursor == NULL)
break;
21122 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (next_cursor - cursor));
21123 cursor = next_cursor;
21126 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (end - cursor));
21134parse_regular_expression_named_capture(
const pm_string_t *capture,
void *data) {
21155 pm_named_capture_escape(parser, &unescaped, source, length, cursor);
21165 if (!pm_slice_is_valid_local(parser, source, source + length)) {
21170 if (callback_data->
shared) {
21174 name = pm_parser_constant_id_location(parser, location.
start, location.
end);
21180 void *memory =
xmalloc(length);
21181 if (memory == NULL) abort();
21183 memcpy(memory, source, length);
21184 name = pm_parser_constant_id_owned(parser, (uint8_t *) memory, length);
21189 if (name != 0 && !pm_constant_id_list_includes(names, name)) {
21190 pm_constant_id_list_append(names, name);
21193 if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
21196 if (pm_local_is_keyword((
const char *) source, length)) {
21203 pm_parser_local_add(parser, name, location.
start, location.
end, 0);
21208 if (callback_data->
match == NULL) {
21209 callback_data->
match = pm_match_write_node_create(parser, call);
21214 pm_node_t *target = (
pm_node_t *) pm_local_variable_target_node_create(parser, &location, name, depth == -1 ? 0 : (uint32_t) depth);
21215 pm_node_list_append(&callback_data->
match->
targets, target);
21231 .shared = content->
type == PM_STRING_SHARED
21238 .shared = content->
type == PM_STRING_SHARED
21241 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);
21242 pm_constant_id_list_free(&callback_data.
names);
21244 if (callback_data.
match != NULL) {
21252parse_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) {
21255 switch (token.type) {
21256 case PM_TOKEN_EQUAL: {
21257 switch (PM_NODE_TYPE(node)) {
21258 case PM_CALL_NODE: {
21264 if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21269 case PM_CASE_WRITABLE: {
21273 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
21277 parser_lex(parser);
21278 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));
21280 if (PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) && previous_binding_power != PM_BINDING_POWER_STATEMENT) {
21281 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_MULTI_WRITE);
21284 return parse_write(parser, node, &token, value);
21286 case PM_SPLAT_NODE: {
21288 pm_multi_target_node_targets_append(parser, multi_target, node);
21290 parser_lex(parser);
21291 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));
21292 return parse_write(parser, (
pm_node_t *) multi_target, &token, value);
21294 case PM_SOURCE_ENCODING_NODE:
21295 case PM_FALSE_NODE:
21296 case PM_SOURCE_FILE_NODE:
21297 case PM_SOURCE_LINE_NODE:
21300 case PM_TRUE_NODE: {
21303 parser_lex(parser);
21304 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));
21305 return parse_unwriteable_write(parser, node, &token, value);
21311 parser_lex(parser);
21312 pm_parser_err_token(parser, &token, PM_ERR_EXPRESSION_NOT_WRITABLE);
21316 case PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL: {
21317 switch (PM_NODE_TYPE(node)) {
21318 case PM_BACK_REFERENCE_READ_NODE:
21319 case PM_NUMBERED_REFERENCE_READ_NODE:
21320 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21322 case PM_GLOBAL_VARIABLE_READ_NODE: {
21323 parser_lex(parser);
21325 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));
21326 pm_node_t *result = (
pm_node_t *) pm_global_variable_and_write_node_create(parser, node, &token, value);
21328 pm_node_destroy(parser, node);
21331 case PM_CLASS_VARIABLE_READ_NODE: {
21332 parser_lex(parser);
21334 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));
21337 pm_node_destroy(parser, node);
21340 case PM_CONSTANT_PATH_NODE: {
21341 parser_lex(parser);
21343 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));
21346 return parse_shareable_constant_write(parser, write);
21348 case PM_CONSTANT_READ_NODE: {
21349 parser_lex(parser);
21351 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));
21354 pm_node_destroy(parser, node);
21355 return parse_shareable_constant_write(parser, write);
21357 case PM_INSTANCE_VARIABLE_READ_NODE: {
21358 parser_lex(parser);
21360 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));
21363 pm_node_destroy(parser, node);
21366 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21368 parser_lex(parser);
21370 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));
21371 pm_node_t *result = (
pm_node_t *) pm_local_variable_and_write_node_create(parser, node, &token, value, name, 0);
21373 parse_target_implicit_parameter(parser, node);
21374 pm_node_destroy(parser, node);
21377 case PM_LOCAL_VARIABLE_READ_NODE: {
21380 parse_target_implicit_parameter(parser, node);
21384 parser_lex(parser);
21386 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));
21389 pm_node_destroy(parser, node);
21392 case PM_CALL_NODE: {
21398 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21400 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21403 parser_lex(parser);
21405 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));
21406 pm_node_t *result = (
pm_node_t *) pm_local_variable_and_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21408 pm_node_destroy(parser, (
pm_node_t *) cast);
21414 parser_lex(parser);
21419 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21420 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));
21421 return (
pm_node_t *) pm_index_and_write_node_create(parser, cast, &token, value);
21425 if (pm_call_node_writable_p(parser, cast)) {
21426 parse_write_name(parser, &cast->
name);
21428 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21431 parse_call_operator_write(parser, cast, &token);
21432 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));
21433 return (
pm_node_t *) pm_call_and_write_node_create(parser, cast, &token, value);
21435 case PM_MULTI_WRITE_NODE: {
21436 parser_lex(parser);
21437 pm_parser_err_token(parser, &token, PM_ERR_AMPAMPEQ_MULTI_ASSIGN);
21441 parser_lex(parser);
21446 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
21450 case PM_TOKEN_PIPE_PIPE_EQUAL: {
21451 switch (PM_NODE_TYPE(node)) {
21452 case PM_BACK_REFERENCE_READ_NODE:
21453 case PM_NUMBERED_REFERENCE_READ_NODE:
21454 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21456 case PM_GLOBAL_VARIABLE_READ_NODE: {
21457 parser_lex(parser);
21459 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));
21460 pm_node_t *result = (
pm_node_t *) pm_global_variable_or_write_node_create(parser, node, &token, value);
21462 pm_node_destroy(parser, node);
21465 case PM_CLASS_VARIABLE_READ_NODE: {
21466 parser_lex(parser);
21468 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));
21471 pm_node_destroy(parser, node);
21474 case PM_CONSTANT_PATH_NODE: {
21475 parser_lex(parser);
21477 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));
21480 return parse_shareable_constant_write(parser, write);
21482 case PM_CONSTANT_READ_NODE: {
21483 parser_lex(parser);
21485 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));
21488 pm_node_destroy(parser, node);
21489 return parse_shareable_constant_write(parser, write);
21491 case PM_INSTANCE_VARIABLE_READ_NODE: {
21492 parser_lex(parser);
21494 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));
21497 pm_node_destroy(parser, node);
21500 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21502 parser_lex(parser);
21504 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));
21505 pm_node_t *result = (
pm_node_t *) pm_local_variable_or_write_node_create(parser, node, &token, value, name, 0);
21507 parse_target_implicit_parameter(parser, node);
21508 pm_node_destroy(parser, node);
21511 case PM_LOCAL_VARIABLE_READ_NODE: {
21514 parse_target_implicit_parameter(parser, node);
21518 parser_lex(parser);
21520 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));
21523 pm_node_destroy(parser, node);
21526 case PM_CALL_NODE: {
21532 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21534 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21537 parser_lex(parser);
21539 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));
21540 pm_node_t *result = (
pm_node_t *) pm_local_variable_or_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21542 pm_node_destroy(parser, (
pm_node_t *) cast);
21548 parser_lex(parser);
21553 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21554 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));
21555 return (
pm_node_t *) pm_index_or_write_node_create(parser, cast, &token, value);
21559 if (pm_call_node_writable_p(parser, cast)) {
21560 parse_write_name(parser, &cast->
name);
21562 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21565 parse_call_operator_write(parser, cast, &token);
21566 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));
21567 return (
pm_node_t *) pm_call_or_write_node_create(parser, cast, &token, value);
21569 case PM_MULTI_WRITE_NODE: {
21570 parser_lex(parser);
21571 pm_parser_err_token(parser, &token, PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN);
21575 parser_lex(parser);
21580 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
21584 case PM_TOKEN_AMPERSAND_EQUAL:
21585 case PM_TOKEN_CARET_EQUAL:
21586 case PM_TOKEN_GREATER_GREATER_EQUAL:
21587 case PM_TOKEN_LESS_LESS_EQUAL:
21588 case PM_TOKEN_MINUS_EQUAL:
21589 case PM_TOKEN_PERCENT_EQUAL:
21590 case PM_TOKEN_PIPE_EQUAL:
21591 case PM_TOKEN_PLUS_EQUAL:
21592 case PM_TOKEN_SLASH_EQUAL:
21593 case PM_TOKEN_STAR_EQUAL:
21594 case PM_TOKEN_STAR_STAR_EQUAL: {
21595 switch (PM_NODE_TYPE(node)) {
21596 case PM_BACK_REFERENCE_READ_NODE:
21597 case PM_NUMBERED_REFERENCE_READ_NODE:
21598 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21600 case PM_GLOBAL_VARIABLE_READ_NODE: {
21601 parser_lex(parser);
21603 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));
21604 pm_node_t *result = (
pm_node_t *) pm_global_variable_operator_write_node_create(parser, node, &token, value);
21606 pm_node_destroy(parser, node);
21609 case PM_CLASS_VARIABLE_READ_NODE: {
21610 parser_lex(parser);
21612 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));
21615 pm_node_destroy(parser, node);
21618 case PM_CONSTANT_PATH_NODE: {
21619 parser_lex(parser);
21621 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));
21624 return parse_shareable_constant_write(parser, write);
21626 case PM_CONSTANT_READ_NODE: {
21627 parser_lex(parser);
21629 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));
21632 pm_node_destroy(parser, node);
21633 return parse_shareable_constant_write(parser, write);
21635 case PM_INSTANCE_VARIABLE_READ_NODE: {
21636 parser_lex(parser);
21638 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));
21641 pm_node_destroy(parser, node);
21644 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21646 parser_lex(parser);
21648 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));
21649 pm_node_t *result = (
pm_node_t *) pm_local_variable_operator_write_node_create(parser, node, &token, value, name, 0);
21651 parse_target_implicit_parameter(parser, node);
21652 pm_node_destroy(parser, node);
21655 case PM_LOCAL_VARIABLE_READ_NODE: {
21658 parse_target_implicit_parameter(parser, node);
21662 parser_lex(parser);
21664 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));
21665 pm_node_t *result = (
pm_node_t *) pm_local_variable_operator_write_node_create(parser, node, &token, value, cast->
name, cast->
depth);
21667 pm_node_destroy(parser, node);
21670 case PM_CALL_NODE: {
21671 parser_lex(parser);
21677 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21679 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21682 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));
21683 pm_node_t *result = (
pm_node_t *) pm_local_variable_operator_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21685 pm_node_destroy(parser, (
pm_node_t *) cast);
21692 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21693 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));
21694 return (
pm_node_t *) pm_index_operator_write_node_create(parser, cast, &token, value);
21698 if (pm_call_node_writable_p(parser, cast)) {
21699 parse_write_name(parser, &cast->
name);
21701 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21704 parse_call_operator_write(parser, cast, &token);
21705 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));
21706 return (
pm_node_t *) pm_call_operator_write_node_create(parser, cast, &token, value);
21708 case PM_MULTI_WRITE_NODE: {
21709 parser_lex(parser);
21710 pm_parser_err_token(parser, &token, PM_ERR_OPERATOR_MULTI_ASSIGN);
21714 parser_lex(parser);
21723 case PM_TOKEN_AMPERSAND_AMPERSAND:
21724 case PM_TOKEN_KEYWORD_AND: {
21725 parser_lex(parser);
21727 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));
21728 return (
pm_node_t *) pm_and_node_create(parser, node, &token, right);
21730 case PM_TOKEN_KEYWORD_OR:
21731 case PM_TOKEN_PIPE_PIPE: {
21732 parser_lex(parser);
21734 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));
21735 return (
pm_node_t *) pm_or_node_create(parser, node, &token, right);
21737 case PM_TOKEN_EQUAL_TILDE: {
21745 parser_lex(parser);
21746 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21749 pm_call_node_t *call = pm_call_node_binary_create(parser, node, &token, argument, 0);
21755 if (PM_NODE_TYPE_P(node, PM_INTERPOLATED_REGULAR_EXPRESSION_NODE)) {
21762 bool interpolated =
false;
21763 size_t total_length = 0;
21767 if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
21770 interpolated =
true;
21775 if (!interpolated && total_length > 0) {
21776 void *memory =
xmalloc(total_length);
21777 if (!memory) abort();
21779 uint8_t *cursor = memory;
21789 pm_string_owned_init(&owned, (uint8_t *) memory, total_length);
21791 result = parse_regular_expression_named_captures(parser, &owned, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
21794 }
else if (PM_NODE_TYPE_P(node, PM_REGULAR_EXPRESSION_NODE)) {
21798 result = parse_regular_expression_named_captures(parser, content, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
21803 case PM_TOKEN_UAMPERSAND:
21804 case PM_TOKEN_USTAR:
21805 case PM_TOKEN_USTAR_STAR:
21808 case PM_TOKEN_BANG_EQUAL:
21809 case PM_TOKEN_BANG_TILDE:
21810 case PM_TOKEN_EQUAL_EQUAL:
21811 case PM_TOKEN_EQUAL_EQUAL_EQUAL:
21812 case PM_TOKEN_LESS_EQUAL_GREATER:
21813 case PM_TOKEN_CARET:
21814 case PM_TOKEN_PIPE:
21815 case PM_TOKEN_AMPERSAND:
21816 case PM_TOKEN_GREATER_GREATER:
21817 case PM_TOKEN_LESS_LESS:
21818 case PM_TOKEN_MINUS:
21819 case PM_TOKEN_PLUS:
21820 case PM_TOKEN_PERCENT:
21821 case PM_TOKEN_SLASH:
21822 case PM_TOKEN_STAR:
21823 case PM_TOKEN_STAR_STAR: {
21824 parser_lex(parser);
21826 switch (PM_NODE_TYPE(node)) {
21827 case PM_RESCUE_MODIFIER_NODE: {
21830 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21834 case PM_AND_NODE: {
21836 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21837 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21843 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21844 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21852 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21853 return (
pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument, 0);
21855 case PM_TOKEN_GREATER:
21856 case PM_TOKEN_GREATER_EQUAL:
21857 case PM_TOKEN_LESS:
21858 case PM_TOKEN_LESS_EQUAL: {
21859 if (PM_NODE_TYPE_P(node, PM_CALL_NODE) && PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_COMPARISON)) {
21860 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_COMPARISON_AFTER_COMPARISON);
21863 parser_lex(parser);
21864 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21865 return (
pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON);
21867 case PM_TOKEN_AMPERSAND_DOT:
21868 case PM_TOKEN_DOT: {
21869 parser_lex(parser);
21874 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
21875 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21876 return (
pm_node_t *) pm_call_node_shorthand_create(parser, node, &
operator, &arguments);
21879 switch (PM_NODE_TYPE(node)) {
21880 case PM_RESCUE_MODIFIER_NODE: {
21883 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21887 case PM_AND_NODE: {
21889 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21890 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21896 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21897 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21907 switch (parser->
current.type) {
21908 case PM_CASE_OPERATOR:
21909 case PM_CASE_KEYWORD:
21910 case PM_TOKEN_CONSTANT:
21911 case PM_TOKEN_IDENTIFIER:
21912 case PM_TOKEN_METHOD_NAME: {
21913 parser_lex(parser);
21923 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21924 pm_call_node_t *call = pm_call_node_call_create(parser, node, &
operator, &message, &arguments);
21927 (previous_binding_power == PM_BINDING_POWER_STATEMENT) &&
21930 match1(parser, PM_TOKEN_COMMA)
21932 return parse_targets_validate(parser, (
pm_node_t *) call, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21937 case PM_TOKEN_DOT_DOT:
21938 case PM_TOKEN_DOT_DOT_DOT: {
21939 parser_lex(parser);
21942 if (token_begins_expression_p(parser->
current.type)) {
21943 right = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21946 return (
pm_node_t *) pm_range_node_create(parser, node, &token, right);
21948 case PM_TOKEN_KEYWORD_IF_MODIFIER: {
21950 parser_lex(parser);
21952 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
21953 return (
pm_node_t *) pm_if_node_modifier_create(parser, node, &keyword, predicate);
21955 case PM_TOKEN_KEYWORD_UNLESS_MODIFIER: {
21957 parser_lex(parser);
21959 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
21960 return (
pm_node_t *) pm_unless_node_modifier_create(parser, node, &keyword, predicate);
21962 case PM_TOKEN_KEYWORD_UNTIL_MODIFIER: {
21963 parser_lex(parser);
21965 pm_statements_node_body_append(parser, statements, node,
true);
21967 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
21968 return (
pm_node_t *) pm_until_node_modifier_create(parser, &token, predicate, statements, PM_NODE_TYPE_P(node, PM_BEGIN_NODE) ? PM_LOOP_FLAGS_BEGIN_MODIFIER : 0);
21970 case PM_TOKEN_KEYWORD_WHILE_MODIFIER: {
21971 parser_lex(parser);
21973 pm_statements_node_body_append(parser, statements, node,
true);
21975 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
21976 return (
pm_node_t *) pm_while_node_modifier_create(parser, &token, predicate, statements, PM_NODE_TYPE_P(node, PM_BEGIN_NODE) ? PM_LOOP_FLAGS_BEGIN_MODIFIER : 0);
21978 case PM_TOKEN_QUESTION_MARK: {
21981 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
21984 parser_lex(parser);
21986 pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_TRUE, (uint16_t) (depth + 1));
21998 context_pop(parser);
21999 pop_block_exits(parser, previous_block_exits);
22000 pm_node_list_free(¤t_block_exits);
22002 return (
pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
22005 accept1(parser, PM_TOKEN_NEWLINE);
22006 expect1(parser, PM_TOKEN_COLON, PM_ERR_TERNARY_COLON);
22009 pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_FALSE, (uint16_t) (depth + 1));
22011 context_pop(parser);
22012 pop_block_exits(parser, previous_block_exits);
22013 pm_node_list_free(¤t_block_exits);
22015 return (
pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
22017 case PM_TOKEN_COLON_COLON: {
22018 parser_lex(parser);
22021 switch (parser->
current.type) {
22022 case PM_TOKEN_CONSTANT: {
22023 parser_lex(parser);
22027 (parser->
current.type == PM_TOKEN_PARENTHESIS_LEFT) ||
22028 (accepts_command_call && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)))
22039 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
22040 path = (
pm_node_t *) pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
22043 path = (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
22047 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
22048 return parse_targets_validate(parser, path, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22053 case PM_CASE_OPERATOR:
22054 case PM_CASE_KEYWORD:
22055 case PM_TOKEN_IDENTIFIER:
22056 case PM_TOKEN_METHOD_NAME: {
22057 parser_lex(parser);
22063 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
22064 pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
22067 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
22068 return parse_targets_validate(parser, (
pm_node_t *) call, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22073 case PM_TOKEN_PARENTHESIS_LEFT: {
22077 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
22079 return (
pm_node_t *) pm_call_node_shorthand_create(parser, node, &delimiter, &arguments);
22082 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
22083 return (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
22087 case PM_TOKEN_KEYWORD_RESCUE_MODIFIER: {
22089 parser_lex(parser);
22090 accept1(parser, PM_TOKEN_NEWLINE);
22092 pm_node_t *value = parse_expression(parser, binding_power,
true,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
22093 context_pop(parser);
22095 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, node, &token, value);
22097 case PM_TOKEN_BRACKET_LEFT: {
22098 parser_lex(parser);
22103 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
22104 pm_accepts_block_stack_push(parser,
true);
22105 parse_arguments(parser, &arguments,
false, PM_TOKEN_BRACKET_RIGHT, (uint16_t) (depth + 1));
22106 pm_accepts_block_stack_pop(parser);
22107 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_EXPECT_RBRACKET);
22114 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
22115 pm_call_node_t *aref = pm_call_node_aref_create(parser, node, &arguments);
22116 return parse_targets_validate(parser, (
pm_node_t *) aref, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22123 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
22124 block = parse_block(parser, (uint16_t) (depth + 1));
22125 pm_arguments_validate_block(parser, &arguments, block);
22126 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
22127 block = parse_block(parser, (uint16_t) (depth + 1));
22130 if (block != NULL) {
22131 if (arguments.
block != NULL) {
22132 pm_parser_err_node(parser, (
pm_node_t *) block, PM_ERR_ARGUMENT_AFTER_BLOCK);
22134 arguments.
arguments = pm_arguments_node_create(parser);
22136 pm_arguments_node_arguments_append(arguments.
arguments, arguments.
block);
22142 return (
pm_node_t *) pm_call_node_aref_create(parser, node, &arguments);
22144 case PM_TOKEN_KEYWORD_IN: {
22150 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
22151 parser_lex(parser);
22154 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));
22157 pm_constant_id_list_free(&captures);
22159 return (
pm_node_t *) pm_match_predicate_node_create(parser, node, pattern, &
operator);
22161 case PM_TOKEN_EQUAL_GREATER: {
22167 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
22168 parser_lex(parser);
22171 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));
22174 pm_constant_id_list_free(&captures);
22176 return (
pm_node_t *) pm_match_required_node_create(parser, node, pattern, &
operator);
22179 assert(
false &&
"unreachable");
22184#undef PM_PARSE_PATTERN_SINGLE
22185#undef PM_PARSE_PATTERN_TOP
22186#undef PM_PARSE_PATTERN_MULTI
22196 (node->
block == NULL || PM_NODE_TYPE_P(node->
block, PM_BLOCK_ARGUMENT_NODE)) &&
22210parse_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) {
22212 pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
22216 pm_node_t *node = parse_expression_prefix(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
22218 switch (PM_NODE_TYPE(node)) {
22219 case PM_MISSING_NODE:
22223 case PM_PRE_EXECUTION_NODE:
22224 case PM_POST_EXECUTION_NODE:
22225 case PM_ALIAS_GLOBAL_VARIABLE_NODE:
22226 case PM_ALIAS_METHOD_NODE:
22227 case PM_MULTI_WRITE_NODE:
22228 case PM_UNDEF_NODE:
22231 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
22241 if ((pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_COMPOSITION) && pm_call_node_command_p((
pm_call_node_t *) node)) {
22245 case PM_SYMBOL_NODE:
22249 if (pm_symbol_node_label_p(node)) {
22260 pm_token_type_t current_token_type;
22263 current_token_type = parser->
current.type,
22264 current_binding_powers = pm_binding_powers[current_token_type],
22265 binding_power <= current_binding_powers.
left &&
22266 current_binding_powers.
binary
22268 node = parse_expression_infix(parser, node, binding_power, current_binding_powers.
right, accepts_command_call, (uint16_t) (depth + 1));
22276 switch (PM_NODE_TYPE(node)) {
22277 case PM_MULTI_WRITE_NODE:
22280 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
22284 case PM_CLASS_VARIABLE_WRITE_NODE:
22285 case PM_CONSTANT_PATH_WRITE_NODE:
22286 case PM_CONSTANT_WRITE_NODE:
22287 case PM_GLOBAL_VARIABLE_WRITE_NODE:
22288 case PM_INSTANCE_VARIABLE_WRITE_NODE:
22289 case PM_LOCAL_VARIABLE_WRITE_NODE:
22292 if (PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
22300 if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
22310 if (current_binding_powers.
nonassoc) {
22313 if (match1(parser, current_token_type)) {
22325 if (PM_NODE_TYPE_P(node, PM_RANGE_NODE) && ((
pm_range_node_t *) node)->right == NULL) {
22326 if (match4(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_DOT, PM_TOKEN_AMPERSAND_DOT)) {
22331 if (PM_BINDING_POWER_TERM <= pm_binding_powers[parser->
current.type].left) {
22334 }
else if (current_binding_powers.
left <= pm_binding_powers[parser->
current.type].left) {
22339 if (accepts_command_call) {
22348 switch (node->
type) {
22349 case PM_CALL_NODE: {
22363 cast->
block == NULL &&
22373 cast->
block != NULL && PM_NODE_TYPE_P(cast->
block, PM_BLOCK_NODE)
22376 accepts_command_call =
false;
22381 case PM_CONSTANT_PATH_NODE:
22384 accepts_command_call =
false;
22399 if (PM_PARSER_COMMAND_LINE_OPTION_P(parser)) {
22400 if (statements == NULL) {
22401 statements = pm_statements_node_create(parser);
22405 pm_arguments_node_arguments_append(
22407 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2))
22410 pm_statements_node_body_append(parser, statements, (
pm_node_t *) pm_call_node_fcall_synthesized_create(
22413 pm_parser_constant_id_constant(parser,
"print", 5)
22417 if (PM_PARSER_COMMAND_LINE_OPTION_N(parser)) {
22418 if (PM_PARSER_COMMAND_LINE_OPTION_A(parser)) {
22419 if (statements == NULL) {
22420 statements = pm_statements_node_create(parser);
22424 pm_arguments_node_arguments_append(
22426 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$;", 2))
22429 pm_global_variable_read_node_t *receiver = pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2));
22430 pm_call_node_t *call = pm_call_node_call_synthesized_create(parser, (
pm_node_t *) receiver,
"split", arguments);
22434 pm_parser_constant_id_constant(parser,
"$F", 2),
22438 pm_statements_node_body_prepend(statements, (
pm_node_t *) write);
22442 pm_arguments_node_arguments_append(
22444 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$/", 2))
22447 if (PM_PARSER_COMMAND_LINE_OPTION_L(parser)) {
22449 pm_keyword_hash_node_elements_append(keywords, (
pm_node_t *) pm_assoc_node_create(
22451 (
pm_node_t *) pm_symbol_node_synthesized_create(parser,
"chomp"),
22453 (
pm_node_t *) pm_true_node_synthesized_create(parser)
22456 pm_arguments_node_arguments_append(arguments, (
pm_node_t *) keywords);
22457 pm_node_flag_set((
pm_node_t *) arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS);
22461 pm_statements_node_body_append(parser, wrapped_statements, (
pm_node_t *) pm_while_node_synthesized_create(
22463 (
pm_node_t *) pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser,
"gets", 4)),
22467 statements = wrapped_statements;
22482 pm_parser_scope_push(parser,
true);
22486 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
22488 parser_lex(parser);
22495 assert(statements->
body.
size > 0);
22496 pm_void_statement_check(parser, statements->
body.
nodes[statements->
body.
size - 1]);
22501 pm_parser_scope_pop(parser);
22506 statements = wrap_statements(parser, statements);
22508 flush_block_exits(parser, previous_block_exits);
22509 pm_node_list_free(¤t_block_exits);
22515 if (statements == NULL) {
22516 statements = pm_statements_node_create(parser);
22517 pm_statements_node_location_set(statements, parser->
start, parser->
start);
22520 return (
pm_node_t *) pm_program_node_create(parser, &locals, statements);
22537pm_strnstr(
const char *big,
const char *little,
size_t big_length) {
22538 size_t little_length = strlen(little);
22540 for (
const char *big_end = big + big_length; big < big_end; big++) {
22541 if (*big == *little && memcmp(big, little, little_length) == 0)
return big;
22548#define pm_parser_warn_shebang_carriage_return(parser, start, length) ((void) 0)
22556pm_parser_warn_shebang_carriage_return(
pm_parser_t *parser,
const uint8_t *start,
size_t length) {
22557 if (length > 2 && start[length - 2] ==
'\r' && start[length - 1] ==
'\n') {
22558 pm_parser_warn(parser, start, start + length, PM_WARN_SHEBANG_CARRIAGE_RETURN);
22569 const char *switches = pm_strnstr(engine,
" -", length);
22570 if (switches == NULL)
return;
22575 (
const uint8_t *) (switches + 1),
22576 length - ((
size_t) (switches - engine)) - 1,
22580 size_t encoding_length;
22583 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22595 assert(source != NULL);
22599 .lex_state = PM_LEX_STATE_BEG,
22600 .enclosure_nesting = 0,
22601 .lambda_enclosure_nesting = -1,
22602 .brace_nesting = 0,
22603 .do_loop_stack = 0,
22604 .accepts_block_stack = 0,
22607 .stack = {{ .mode = PM_LEX_DEFAULT }},
22611 .end = source + size,
22612 .previous = { .type = PM_TOKEN_EOF, .start = source, .end = source },
22613 .current = { .type = PM_TOKEN_EOF, .start = source, .end = source },
22614 .next_start = NULL,
22615 .heredoc_end = NULL,
22616 .data_loc = { .start = NULL, .end = NULL },
22617 .comment_list = { 0 },
22618 .magic_comment_list = { 0 },
22619 .warning_list = { 0 },
22620 .error_list = { 0 },
22621 .current_scope = NULL,
22622 .current_context = NULL,
22624 .encoding_changed_callback = NULL,
22625 .encoding_comment_start = source,
22626 .lex_callback = NULL,
22628 .constant_pool = { 0 },
22629 .newline_list = { 0 },
22633 .explicit_encoding = NULL,
22635 .parsing_eval =
false,
22636 .partial_script =
false,
22637 .command_start =
true,
22638 .recovering =
false,
22639 .encoding_locked =
false,
22640 .encoding_changed =
false,
22641 .pattern_matching_newlines =
false,
22642 .in_keyword_arg =
false,
22643 .current_block_exits = NULL,
22644 .semantic_token_seen =
false,
22646 .current_regular_expression_ascii_only =
false,
22647 .warn_mismatched_indentation =
true
22664 uint32_t constant_size = ((uint32_t) size) / 95;
22665 pm_constant_pool_init(&parser->
constant_pool, constant_size < 4 ? 4 : constant_size);
22670 size_t newline_size = size / 22;
22671 pm_newline_list_init(&parser->
newline_list, source, newline_size < 4 ? 4 : newline_size);
22674 if (options != NULL) {
22683 if (encoding_length > 0) {
22685 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22707 for (
size_t scope_index = 0; scope_index < options->
scopes_count; scope_index++) {
22709 pm_parser_scope_push(parser, scope_index == 0);
22715 for (
size_t local_index = 0; local_index < scope->
locals_count; local_index++) {
22721 void *allocated =
xmalloc(length);
22722 if (allocated == NULL)
continue;
22724 memcpy(allocated, source, length);
22725 pm_parser_local_add_owned(parser, (uint8_t *) allocated, length);
22736 pm_accepts_block_stack_push(parser,
true);
22739 if (size >= 3 && source[0] == 0xef && source[1] == 0xbb && source[2] == 0xbf) {
22752 bool search_shebang = PM_PARSER_COMMAND_LINE_OPTION_X(parser);
22769 const uint8_t *newline = next_newline(parser->
start, parser->
end - parser->
start);
22770 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - parser->
start);
22772 if (length > 2 && parser->
current.end[0] ==
'#' && parser->
current.end[1] ==
'!') {
22773 const char *engine;
22775 if ((engine = pm_strnstr((
const char *) parser->
start,
"ruby", length)) != NULL) {
22776 if (newline != NULL) {
22780 pm_parser_warn_shebang_carriage_return(parser, parser->
start, length + 1);
22785 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) parser->
start)));
22788 search_shebang =
false;
22790 search_shebang =
true;
22796 if (search_shebang) {
22799 bool found_shebang =
false;
22803 const uint8_t *cursor = parser->
start;
22807 const uint8_t *newline = next_newline(cursor, parser->
end - cursor);
22809 while (newline != NULL) {
22810 pm_newline_list_append(&parser->
newline_list, newline);
22812 cursor = newline + 1;
22813 newline = next_newline(cursor, parser->
end - cursor);
22815 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - cursor);
22816 if (length > 2 && cursor[0] ==
'#' && cursor[1] ==
'!') {
22817 const char *engine;
22818 if ((engine = pm_strnstr((
const char *) cursor,
"ruby", length)) != NULL) {
22819 found_shebang =
true;
22821 if (newline != NULL) {
22822 pm_parser_warn_shebang_carriage_return(parser, cursor, length + 1);
22827 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) cursor)));
22835 if (found_shebang) {
22837 parser->
current = (
pm_token_t) { .type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
22839 pm_parser_err(parser, parser->
start, parser->
start, PM_ERR_SCRIPT_NOT_FOUND);
22866 for (node = list->
head; node != NULL; node = next) {
22878pm_magic_comment_list_free(
pm_list_t *list) {
22881 for (node = list->
head; node != NULL; node = next) {
22895 pm_diagnostic_list_free(&parser->
error_list);
22907 pm_parser_scope_pop(parser);
22911 lex_mode_pop(parser);
22920 return parse_program(parser);
22930#define LINE_SIZE 4096
22931 char line[LINE_SIZE];
22933 while (memset(line,
'\n', LINE_SIZE), stream_fgets(line, LINE_SIZE, stream) != NULL) {
22934 size_t length = LINE_SIZE;
22935 while (length > 0 && line[length - 1] ==
'\n') length--;
22937 if (length == LINE_SIZE) {
22942 pm_buffer_append_string(buffer, line, length);
22948 pm_buffer_append_string(buffer, line, length);
22956 if (strncmp(line,
"__END__", 7) == 0)
return false;
22959 if (strncmp(line,
"__END__\n", 8) == 0)
return false;
22962 if (strncmp(line,
"__END__\r\n", 9) == 0)
return false;
22968 if (stream_feof(stream)) {
22987pm_parse_stream_unterminated_heredoc_p(
pm_parser_t *parser) {
22990 for (; diagnostic != NULL; diagnostic = (
pm_diagnostic_t *) diagnostic->node.next) {
22991 if (diagnostic->diag_id == PM_ERR_HEREDOC_TERM) {
23009 bool eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof);
23015 pm_node_destroy(parser, node);
23016 eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof);
23030pm_parse_success_p(
const uint8_t *source,
size_t size,
const char *data) {
23032 pm_options_read(&options, data);
23038 pm_node_destroy(&parser, node);
23047#undef PM_CASE_KEYWORD
23048#undef PM_CASE_OPERATOR
23049#undef PM_CASE_WRITABLE
23050#undef PM_STRING_EMPTY
23051#undef PM_LOCATION_NODE_BASE_VALUE
23052#undef PM_LOCATION_NODE_VALUE
23053#undef PM_LOCATION_NULL_VALUE
23054#undef PM_LOCATION_TOKEN_VALUE
23059#ifndef PRISM_EXCLUDE_SERIALIZATION
23063 pm_buffer_append_string(buffer,
"PRISM", 5);
23067 pm_buffer_append_byte(buffer, PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS ? 1 : 0);
23075 pm_serialize_header(buffer);
23077 pm_buffer_append_byte(buffer,
'\0');
23085pm_serialize_parse(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
23087 pm_options_read(&options, data);
23094 pm_serialize_header(buffer);
23096 pm_buffer_append_byte(buffer,
'\0');
23098 pm_node_destroy(&parser, node);
23111 pm_options_read(&options, data);
23115 pm_serialize_header(buffer);
23117 pm_buffer_append_byte(buffer,
'\0');
23119 pm_node_destroy(&parser, node);
23129pm_serialize_parse_comments(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
23131 pm_options_read(&options, data);
23137 pm_serialize_header(buffer);
23139 pm_buffer_append_varsint(buffer, parser.
start_line);
23142 pm_node_destroy(&parser, node);
23156 PM_SLICE_TYPE_ERROR = -1,
23159 PM_SLICE_TYPE_NONE,
23162 PM_SLICE_TYPE_LOCAL,
23165 PM_SLICE_TYPE_CONSTANT,
23168 PM_SLICE_TYPE_METHOD_NAME
23175pm_slice_type(
const uint8_t *source,
size_t length,
const char *encoding_name) {
23177 const pm_encoding_t *encoding = pm_encoding_find((
const uint8_t *) encoding_name, (
const uint8_t *) (encoding_name + strlen(encoding_name)));
23178 if (encoding == NULL)
return PM_SLICE_TYPE_ERROR;
23181 if (length == 0)
return PM_SLICE_TYPE_NONE;
23184 if ((width = encoding->
alpha_char(source, (ptrdiff_t) length)) != 0) {
23186 }
else if (*source ==
'_') {
23189 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, (ptrdiff_t) length)) > 0)) {
23193 return PM_SLICE_TYPE_NONE;
23197 const uint8_t *end = source + length;
23198 pm_slice_type_t result = encoding->
isupper_char(source, end - source) ? PM_SLICE_TYPE_CONSTANT : PM_SLICE_TYPE_LOCAL;
23204 while (source < end) {
23205 if ((width = encoding->
alnum_char(source, end - source)) != 0) {
23208 }
else if (*source ==
'_') {
23211 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, end - source)) > 0)) {
23221 if (*source ==
'!' || *source ==
'?' || *source ==
'=') {
23223 result = PM_SLICE_TYPE_METHOD_NAME;
23227 return source == end ? result : PM_SLICE_TYPE_NONE;
23234pm_string_query_local(
const uint8_t *source,
size_t length,
const char *encoding_name) {
23235 switch (pm_slice_type(source, length, encoding_name)) {
23236 case PM_SLICE_TYPE_ERROR:
23238 case PM_SLICE_TYPE_NONE:
23239 case PM_SLICE_TYPE_CONSTANT:
23240 case PM_SLICE_TYPE_METHOD_NAME:
23242 case PM_SLICE_TYPE_LOCAL:
23246 assert(
false &&
"unreachable");
23254pm_string_query_constant(
const uint8_t *source,
size_t length,
const char *encoding_name) {
23255 switch (pm_slice_type(source, length, encoding_name)) {
23256 case PM_SLICE_TYPE_ERROR:
23258 case PM_SLICE_TYPE_NONE:
23259 case PM_SLICE_TYPE_LOCAL:
23260 case PM_SLICE_TYPE_METHOD_NAME:
23262 case PM_SLICE_TYPE_CONSTANT:
23266 assert(
false &&
"unreachable");
23274pm_string_query_method_name(
const uint8_t *source,
size_t length,
const char *encoding_name) {
23275#define B(p) ((p) ? PM_STRING_QUERY_TRUE : PM_STRING_QUERY_FALSE)
23276#define C1(c) (*source == c)
23277#define C2(s) (memcmp(source, s, 2) == 0)
23278#define C3(s) (memcmp(source, s, 3) == 0)
23280 switch (pm_slice_type(source, length, encoding_name)) {
23281 case PM_SLICE_TYPE_ERROR:
23283 case PM_SLICE_TYPE_NONE:
23285 case PM_SLICE_TYPE_LOCAL:
23287 return B((length != 2) || (source[0] !=
'_') || (source[1] ==
'0') || !pm_char_is_decimal_digit(source[1]));
23288 case PM_SLICE_TYPE_CONSTANT:
23290 case PM_SLICE_TYPE_METHOD_NAME:
23297 return B(C1(
'&') || C1(
'`') || C1(
'!') || C1(
'^') || C1(
'>') || C1(
'<') || C1(
'-') || C1(
'%') || C1(
'|') || C1(
'+') || C1(
'/') || C1(
'*') || C1(
'~'));
23299 return B(C2(
"!=") || C2(
"!~") || C2(
"[]") || C2(
"==") || C2(
"=~") || C2(
">=") || C2(
">>") || C2(
"<=") || C2(
"<<") || C2(
"**"));
23301 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_3_5
The vendored version of prism in CRuby 3.5.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_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 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.
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::@95 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 ...
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...
union pm_lex_mode::@96 as
The data associated with this type of lex mode.
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_node_flags_t flags
This represents any flags on 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...
struct pm_parser::@101 lex_modes
A stack of lex modes.
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 ...
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::@102 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.