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 = (1 << 2);
2627static const pm_node_flags_t PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY = ((PM_CALL_NODE_FLAGS_LAST - 1) << 1);
2628static const pm_node_flags_t PM_CALL_NODE_FLAGS_COMPARISON = ((PM_CALL_NODE_FLAGS_LAST - 1) << 2);
2629static const pm_node_flags_t PM_CALL_NODE_FLAGS_INDEX = ((PM_CALL_NODE_FLAGS_LAST - 1) << 3);
2636static pm_call_node_t *
2637pm_call_node_create(pm_parser_t *parser, pm_node_flags_t flags) {
2638 pm_call_node_t *node = PM_NODE_ALLOC(parser, pm_call_node_t);
2640 *node = (pm_call_node_t) {
2642 .type = PM_CALL_NODE,
2644 .node_id = PM_NODE_IDENTIFY(parser),
2645 .location = PM_LOCATION_NULL_VALUE(parser),
2648 .call_operator_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2649 .message_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2650 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2652 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2664static inline pm_node_flags_t
2665pm_call_node_ignore_visibility_flag(const pm_node_t *receiver) {
2666 return PM_NODE_TYPE_P(receiver, PM_SELF_NODE) ? PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY : 0;
2673static pm_call_node_t *
2674pm_call_node_aref_create(pm_parser_t *parser, pm_node_t *receiver, pm_arguments_t *arguments) {
2675 pm_assert_value_expression(parser, receiver);
2677 pm_node_flags_t flags = pm_call_node_ignore_visibility_flag(receiver);
2678 if (arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_ARGUMENT_NODE)) {
2679 flags |= PM_CALL_NODE_FLAGS_INDEX;
2682 pm_call_node_t *node = pm_call_node_create(parser, flags);
2684 node->base.location.start = receiver->location.start;
2685 node->base.location.end = pm_arguments_end(arguments);
2687 node->receiver = receiver;
2688 node->message_loc.start = arguments->opening_loc.start;
2689 node->message_loc.end = arguments->closing_loc.end;
2691 node->opening_loc = arguments->opening_loc;
2692 node->arguments = arguments->arguments;
2693 node->closing_loc = arguments->closing_loc;
2694 node->block = arguments->block;
2696 node->name = pm_parser_constant_id_constant(parser, "[]", 2);
2703static pm_call_node_t *
2704pm_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) {
2705 pm_assert_value_expression(parser, receiver);
2706 pm_assert_value_expression(parser, argument);
2708 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver) | flags);
2710 node->base.location.start = MIN(receiver->location.start, argument->location.start);
2711 node->base.location.end = MAX(receiver->location.end, argument->location.end);
2713 node->receiver = receiver;
2714 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2716 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
2717 pm_arguments_node_arguments_append(arguments, argument);
2718 node->arguments = arguments;
2720 node->name = pm_parser_constant_id_token(parser, operator);
2727static pm_call_node_t *
2728pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_token_t *message, pm_arguments_t *arguments) {
2729 pm_assert_value_expression(parser, receiver);
2731 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2733 node->base.location.start = receiver->location.start;
2734 const uint8_t *end = pm_arguments_end(arguments);
2738 node->base.location.end = end;
2740 node->receiver = receiver;
2741 node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2742 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2743 node->opening_loc = arguments->opening_loc;
2744 node->arguments = arguments->arguments;
2745 node->closing_loc = arguments->closing_loc;
2746 node->block = arguments->block;
2748 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2749 pm_node_flag_set((pm_node_t *)node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2752 node->name = pm_parser_constant_id_token(parser, message);
2759static pm_call_node_t *
2760pm_call_node_call_synthesized_create(pm_parser_t *parser, pm_node_t *receiver, const char *message, pm_arguments_node_t *arguments) {
2761 pm_call_node_t *node = pm_call_node_create(parser, 0);
2762 node->base.location.start = parser->start;
2763 node->base.location.end = parser->end;
2765 node->receiver = receiver;
2766 node->call_operator_loc = (pm_location_t) { .start = NULL, .end = NULL };
2767 node->message_loc = (pm_location_t) { .start = NULL, .end = NULL };
2768 node->arguments = arguments;
2770 node->name = pm_parser_constant_id_constant(parser, message, strlen(message));
2778static pm_call_node_t *
2779pm_call_node_fcall_create(pm_parser_t *parser, pm_token_t *message, pm_arguments_t *arguments) {
2780 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2782 node->base.location.start = message->start;
2783 node->base.location.end = pm_arguments_end(arguments);
2785 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2786 node->opening_loc = arguments->opening_loc;
2787 node->arguments = arguments->arguments;
2788 node->closing_loc = arguments->closing_loc;
2789 node->block = arguments->block;
2791 node->name = pm_parser_constant_id_token(parser, message);
2799static pm_call_node_t *
2800pm_call_node_fcall_synthesized_create(pm_parser_t *parser, pm_arguments_node_t *arguments, pm_constant_id_t name) {
2801 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2803 node->base.location = PM_LOCATION_NULL_VALUE(parser);
2804 node->arguments = arguments;
2813static pm_call_node_t *
2814pm_call_node_not_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *message, pm_arguments_t *arguments) {
2815 pm_assert_value_expression(parser, receiver);
2816 if (receiver != NULL) pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
2818 pm_call_node_t *node = pm_call_node_create(parser, receiver == NULL ? 0 : pm_call_node_ignore_visibility_flag(receiver));
2820 node->base.location.start = message->start;
2821 if (arguments->closing_loc.start != NULL) {
2822 node->base.location.end = arguments->closing_loc.end;
2824 assert(receiver != NULL);
2825 node->base.location.end = receiver->location.end;
2828 node->receiver = receiver;
2829 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2830 node->opening_loc = arguments->opening_loc;
2831 node->arguments = arguments->arguments;
2832 node->closing_loc = arguments->closing_loc;
2834 node->name = pm_parser_constant_id_constant(parser, "!", 1);
2841static pm_call_node_t *
2842pm_call_node_shorthand_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_arguments_t *arguments) {
2843 pm_assert_value_expression(parser, receiver);
2845 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2847 node->base.location.start = receiver->location.start;
2848 node->base.location.end = pm_arguments_end(arguments);
2850 node->receiver = receiver;
2851 node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2852 node->opening_loc = arguments->opening_loc;
2853 node->arguments = arguments->arguments;
2854 node->closing_loc = arguments->closing_loc;
2855 node->block = arguments->block;
2857 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2858 pm_node_flag_set((pm_node_t *)node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2861 node->name = pm_parser_constant_id_constant(parser, "call", 4);
2868static pm_call_node_t *
2869pm_call_node_unary_create(pm_parser_t *parser, pm_token_t *operator, pm_node_t *receiver, const char *name) {
2870 pm_assert_value_expression(parser, receiver);
2872 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2874 node->base.location.start = operator->start;
2875 node->base.location.end = receiver->location.end;
2877 node->receiver = receiver;
2878 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2880 node->name = pm_parser_constant_id_constant(parser, name, strlen(name));
2888static pm_call_node_t *
2889pm_call_node_variable_call_create(pm_parser_t *parser, pm_token_t *message) {
2890 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2892 node->base.location = PM_LOCATION_TOKEN_VALUE(message);
2893 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2895 node->name = pm_parser_constant_id_token(parser, message);
2904pm_call_node_writable_p(const pm_parser_t *parser, const pm_call_node_t *node) {
2906 (node->message_loc.start != NULL) &&
2907 (node->message_loc.end[-1] != '!') &&
2908 (node->message_loc.end[-1] != '?') &&
2909 char_is_identifier_start(parser, node->message_loc.start, parser->end - node->message_loc.start) &&
2910 (node->opening_loc.start == NULL) &&
2911 (node->arguments == NULL) &&
2912 (node->block == NULL)
2920pm_call_write_read_name_init(pm_parser_t *parser, pm_constant_id_t *read_name, pm_constant_id_t *write_name) {
2921 pm_constant_t *write_constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *write_name);
2923 if (write_constant->length > 0) {
2924 size_t length = write_constant->length - 1;
2926 void *memory = xmalloc(length);
2927 memcpy(memory, write_constant->start, length);
2929 *read_name = pm_constant_pool_insert_owned(&parser->constant_pool, (uint8_t *) memory, length);
2931 // We can get here if the message was missing because of a syntax error.
2932 *read_name = pm_parser_constant_id_constant(parser, "", 0);
2939static pm_call_and_write_node_t *
2940pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2941 assert(target->block == NULL);
2942 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
2943 pm_call_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_and_write_node_t);
2945 *node = (pm_call_and_write_node_t) {
2947 .type = PM_CALL_AND_WRITE_NODE,
2948 .flags = target->base.flags,
2949 .node_id = PM_NODE_IDENTIFY(parser),
2951 .start = target->base.location.start,
2952 .end = value->location.end
2955 .receiver = target->receiver,
2956 .call_operator_loc = target->call_operator_loc,
2957 .message_loc = target->message_loc,
2959 .write_name = target->name,
2960 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2964 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
2966 // Here we're going to free the target, since it is no longer necessary.
2967 // However, we don't want to call `pm_node_destroy` because we want to keep
2968 // around all of its children since we just reused them.
2979pm_index_arguments_check(pm_parser_t *parser, const pm_arguments_node_t *arguments, const pm_node_t *block) {
2980 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) {
2981 if (arguments != NULL && PM_NODE_FLAG_P(arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) {
2983 PM_NODE_LIST_FOREACH(&arguments->arguments, index, node) {
2984 if (PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE)) {
2985 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_INDEX_KEYWORDS);
2991 if (block != NULL) {
2992 pm_parser_err_node(parser, block, PM_ERR_UNEXPECTED_INDEX_BLOCK);
3000static pm_index_and_write_node_t *
3001pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3002 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3003 pm_index_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_and_write_node_t);
3005 pm_index_arguments_check(parser, target->arguments, target->block);
3007 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3008 *node = (pm_index_and_write_node_t) {
3010 .type = PM_INDEX_AND_WRITE_NODE,
3011 .flags = target->base.flags,
3012 .node_id = PM_NODE_IDENTIFY(parser),
3014 .start = target->base.location.start,
3015 .end = value->location.end
3018 .receiver = target->receiver,
3019 .call_operator_loc = target->call_operator_loc,
3020 .opening_loc = target->opening_loc,
3021 .arguments = target->arguments,
3022 .closing_loc = target->closing_loc,
3023 .block = (pm_block_argument_node_t *) target->block,
3024 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3028 // Here we're going to free the target, since it is no longer necessary.
3029 // However, we don't want to call `pm_node_destroy` because we want to keep
3030 // around all of its children since we just reused them.
3039static pm_call_operator_write_node_t *
3040pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3041 assert(target->block == NULL);
3042 pm_call_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_operator_write_node_t);
3044 *node = (pm_call_operator_write_node_t) {
3046 .type = PM_CALL_OPERATOR_WRITE_NODE,
3047 .flags = target->base.flags,
3048 .node_id = PM_NODE_IDENTIFY(parser),
3050 .start = target->base.location.start,
3051 .end = value->location.end
3054 .receiver = target->receiver,
3055 .call_operator_loc = target->call_operator_loc,
3056 .message_loc = target->message_loc,
3058 .write_name = target->name,
3059 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
3060 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3064 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3066 // Here we're going to free the target, since it is no longer necessary.
3067 // However, we don't want to call `pm_node_destroy` because we want to keep
3068 // around all of its children since we just reused them.
3077static pm_index_operator_write_node_t *
3078pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3079 pm_index_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_operator_write_node_t);
3081 pm_index_arguments_check(parser, target->arguments, target->block);
3083 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3084 *node = (pm_index_operator_write_node_t) {
3086 .type = PM_INDEX_OPERATOR_WRITE_NODE,
3087 .flags = target->base.flags,
3088 .node_id = PM_NODE_IDENTIFY(parser),
3090 .start = target->base.location.start,
3091 .end = value->location.end
3094 .receiver = target->receiver,
3095 .call_operator_loc = target->call_operator_loc,
3096 .opening_loc = target->opening_loc,
3097 .arguments = target->arguments,
3098 .closing_loc = target->closing_loc,
3099 .block = (pm_block_argument_node_t *) target->block,
3100 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
3101 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3105 // Here we're going to free the target, since it is no longer necessary.
3106 // However, we don't want to call `pm_node_destroy` because we want to keep
3107 // around all of its children since we just reused them.
3116static pm_call_or_write_node_t *
3117pm_call_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3118 assert(target->block == NULL);
3119 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3120 pm_call_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_or_write_node_t);
3122 *node = (pm_call_or_write_node_t) {
3124 .type = PM_CALL_OR_WRITE_NODE,
3125 .flags = target->base.flags,
3126 .node_id = PM_NODE_IDENTIFY(parser),
3128 .start = target->base.location.start,
3129 .end = value->location.end
3132 .receiver = target->receiver,
3133 .call_operator_loc = target->call_operator_loc,
3134 .message_loc = target->message_loc,
3136 .write_name = target->name,
3137 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3141 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3143 // Here we're going to free the target, since it is no longer necessary.
3144 // However, we don't want to call `pm_node_destroy` because we want to keep
3145 // around all of its children since we just reused them.
3154static pm_index_or_write_node_t *
3155pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3156 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3157 pm_index_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_or_write_node_t);
3159 pm_index_arguments_check(parser, target->arguments, target->block);
3161 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3162 *node = (pm_index_or_write_node_t) {
3164 .type = PM_INDEX_OR_WRITE_NODE,
3165 .flags = target->base.flags,
3166 .node_id = PM_NODE_IDENTIFY(parser),
3168 .start = target->base.location.start,
3169 .end = value->location.end
3172 .receiver = target->receiver,
3173 .call_operator_loc = target->call_operator_loc,
3174 .opening_loc = target->opening_loc,
3175 .arguments = target->arguments,
3176 .closing_loc = target->closing_loc,
3177 .block = (pm_block_argument_node_t *) target->block,
3178 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3182 // Here we're going to free the target, since it is no longer necessary.
3183 // However, we don't want to call `pm_node_destroy` because we want to keep
3184 // around all of its children since we just reused them.
3194static pm_call_target_node_t *
3195pm_call_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3196 pm_call_target_node_t *node = PM_NODE_ALLOC(parser, pm_call_target_node_t);
3198 *node = (pm_call_target_node_t) {
3200 .type = PM_CALL_TARGET_NODE,
3201 .flags = target->base.flags,
3202 .node_id = PM_NODE_IDENTIFY(parser),
3203 .location = target->base.location
3205 .receiver = target->receiver,
3206 .call_operator_loc = target->call_operator_loc,
3207 .name = target->name,
3208 .message_loc = target->message_loc
3211 // Here we're going to free the target, since it is no longer necessary.
3212 // However, we don't want to call `pm_node_destroy` because we want to keep
3213 // around all of its children since we just reused them.
3223static pm_index_target_node_t *
3224pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3225 pm_index_target_node_t *node = PM_NODE_ALLOC(parser, pm_index_target_node_t);
3226 pm_node_flags_t flags = target->base.flags;
3228 pm_index_arguments_check(parser, target->arguments, target->block);
3230 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3231 *node = (pm_index_target_node_t) {
3233 .type = PM_INDEX_TARGET_NODE,
3234 .flags = flags | PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE,
3235 .node_id = PM_NODE_IDENTIFY(parser),
3236 .location = target->base.location
3238 .receiver = target->receiver,
3239 .opening_loc = target->opening_loc,
3240 .arguments = target->arguments,
3241 .closing_loc = target->closing_loc,
3242 .block = (pm_block_argument_node_t *) target->block,
3245 // Here we're going to free the target, since it is no longer necessary.
3246 // However, we don't want to call `pm_node_destroy` because we want to keep
3247 // around all of its children since we just reused them.
3256static pm_capture_pattern_node_t *
3257pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_local_variable_target_node_t *target, const pm_token_t *operator) {
3258 pm_capture_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_capture_pattern_node_t);
3260 *node = (pm_capture_pattern_node_t) {
3262 .type = PM_CAPTURE_PATTERN_NODE,
3263 .node_id = PM_NODE_IDENTIFY(parser),
3265 .start = value->location.start,
3266 .end = target->base.location.end
3271 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
3280static pm_case_node_t *
3281pm_case_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3282 pm_case_node_t *node = PM_NODE_ALLOC(parser, pm_case_node_t);
3284 *node = (pm_case_node_t) {
3286 .type = PM_CASE_NODE,
3287 .node_id = PM_NODE_IDENTIFY(parser),
3289 .start = case_keyword->start,
3290 .end = end_keyword->end
3293 .predicate = predicate,
3294 .else_clause = NULL,
3295 .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
3296 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3307pm_case_node_condition_append(pm_case_node_t *node, pm_node_t *condition) {
3308 assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
3310 pm_node_list_append(&node->conditions, condition);
3311 node->base.location.end = condition->location.end;
3318pm_case_node_else_clause_set(pm_case_node_t *node, pm_else_node_t *else_clause) {
3319 node->else_clause = else_clause;
3320 node->base.location.end = else_clause->base.location.end;
3327pm_case_node_end_keyword_loc_set(pm_case_node_t *node, const pm_token_t *end_keyword) {
3328 node->base.location.end = end_keyword->end;
3329 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
3335static pm_case_match_node_t *
3336pm_case_match_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3337 pm_case_match_node_t *node = PM_NODE_ALLOC(parser, pm_case_match_node_t);
3339 *node = (pm_case_match_node_t) {
3341 .type = PM_CASE_MATCH_NODE,
3342 .node_id = PM_NODE_IDENTIFY(parser),
3344 .start = case_keyword->start,
3345 .end = end_keyword->end
3348 .predicate = predicate,
3349 .else_clause = NULL,
3350 .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
3351 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3362pm_case_match_node_condition_append(pm_case_match_node_t *node, pm_node_t *condition) {
3363 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
3365 pm_node_list_append(&node->conditions, condition);
3366 node->base.location.end = condition->location.end;
3373pm_case_match_node_else_clause_set(pm_case_match_node_t *node, pm_else_node_t *else_clause) {
3374 node->else_clause = else_clause;
3375 node->base.location.end = else_clause->base.location.end;
3382pm_case_match_node_end_keyword_loc_set(pm_case_match_node_t *node, const pm_token_t *end_keyword) {
3383 node->base.location.end = end_keyword->end;
3384 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
3390static pm_class_node_t *
3391pm_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) {
3392 pm_class_node_t *node = PM_NODE_ALLOC(parser, pm_class_node_t);
3394 *node = (pm_class_node_t) {
3396 .type = PM_CLASS_NODE,
3397 .node_id = PM_NODE_IDENTIFY(parser),
3398 .location = { .start = class_keyword->start, .end = end_keyword->end },
3401 .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
3402 .constant_path = constant_path,
3403 .inheritance_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(inheritance_operator),
3404 .superclass = superclass,
3406 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3407 .name = pm_parser_constant_id_token(parser, name)
3416static pm_class_variable_and_write_node_t *
3417pm_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) {
3418 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3419 pm_class_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_and_write_node_t);
3421 *node = (pm_class_variable_and_write_node_t) {
3423 .type = PM_CLASS_VARIABLE_AND_WRITE_NODE,
3424 .node_id = PM_NODE_IDENTIFY(parser),
3426 .start = target->base.location.start,
3427 .end = value->location.end
3430 .name = target->name,
3431 .name_loc = target->base.location,
3432 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3442static pm_class_variable_operator_write_node_t *
3443pm_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) {
3444 pm_class_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_operator_write_node_t);
3446 *node = (pm_class_variable_operator_write_node_t) {
3448 .type = PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE,
3449 .node_id = PM_NODE_IDENTIFY(parser),
3451 .start = target->base.location.start,
3452 .end = value->location.end
3455 .name = target->name,
3456 .name_loc = target->base.location,
3457 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3459 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3468static pm_class_variable_or_write_node_t *
3469pm_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) {
3470 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3471 pm_class_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_or_write_node_t);
3473 *node = (pm_class_variable_or_write_node_t) {
3475 .type = PM_CLASS_VARIABLE_OR_WRITE_NODE,
3476 .node_id = PM_NODE_IDENTIFY(parser),
3478 .start = target->base.location.start,
3479 .end = value->location.end
3482 .name = target->name,
3483 .name_loc = target->base.location,
3484 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3494static pm_class_variable_read_node_t *
3495pm_class_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
3496 assert(token->type == PM_TOKEN_CLASS_VARIABLE);
3497 pm_class_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_read_node_t);
3499 *node = (pm_class_variable_read_node_t) {
3501 .type = PM_CLASS_VARIABLE_READ_NODE,
3502 .node_id = PM_NODE_IDENTIFY(parser),
3503 .location = PM_LOCATION_TOKEN_VALUE(token)
3505 .name = pm_parser_constant_id_token(parser, token)
3517static inline pm_node_flags_t
3518pm_implicit_array_write_flags(const pm_node_t *node, pm_node_flags_t flags) {
3519 if (PM_NODE_TYPE_P(node, PM_ARRAY_NODE) && ((const pm_array_node_t *) node)->opening_loc.start == NULL) {
3528static pm_class_variable_write_node_t *
3529pm_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) {
3530 pm_class_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_write_node_t);
3532 *node = (pm_class_variable_write_node_t) {
3534 .type = PM_CLASS_VARIABLE_WRITE_NODE,
3535 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3536 .node_id = PM_NODE_IDENTIFY(parser),
3538 .start = read_node->base.location.start,
3539 .end = value->location.end
3542 .name = read_node->name,
3543 .name_loc = PM_LOCATION_NODE_VALUE((pm_node_t *) read_node),
3544 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3554static pm_constant_path_and_write_node_t *
3555pm_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) {
3556 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3557 pm_constant_path_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_and_write_node_t);
3559 *node = (pm_constant_path_and_write_node_t) {
3561 .type = PM_CONSTANT_PATH_AND_WRITE_NODE,
3562 .node_id = PM_NODE_IDENTIFY(parser),
3564 .start = target->base.location.start,
3565 .end = value->location.end
3569 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3579static pm_constant_path_operator_write_node_t *
3580pm_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) {
3581 pm_constant_path_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_operator_write_node_t);
3583 *node = (pm_constant_path_operator_write_node_t) {
3585 .type = PM_CONSTANT_PATH_OPERATOR_WRITE_NODE,
3586 .node_id = PM_NODE_IDENTIFY(parser),
3588 .start = target->base.location.start,
3589 .end = value->location.end
3593 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3595 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3604static pm_constant_path_or_write_node_t *
3605pm_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) {
3606 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3607 pm_constant_path_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_or_write_node_t);
3609 *node = (pm_constant_path_or_write_node_t) {
3611 .type = PM_CONSTANT_PATH_OR_WRITE_NODE,
3612 .node_id = PM_NODE_IDENTIFY(parser),
3614 .start = target->base.location.start,
3615 .end = value->location.end
3619 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3629static pm_constant_path_node_t *
3630pm_constant_path_node_create(pm_parser_t *parser, pm_node_t *parent, const pm_token_t *delimiter, const pm_token_t *name_token) {
3631 pm_assert_value_expression(parser, parent);
3632 pm_constant_path_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_node_t);
3634 pm_constant_id_t name = PM_CONSTANT_ID_UNSET;
3635 if (name_token->type == PM_TOKEN_CONSTANT) {
3636 name = pm_parser_constant_id_token(parser, name_token);
3639 *node = (pm_constant_path_node_t) {
3641 .type = PM_CONSTANT_PATH_NODE,
3642 .node_id = PM_NODE_IDENTIFY(parser),
3644 .start = parent == NULL ? delimiter->start : parent->location.start,
3645 .end = name_token->end
3650 .delimiter_loc = PM_LOCATION_TOKEN_VALUE(delimiter),
3651 .name_loc = PM_LOCATION_TOKEN_VALUE(name_token)
3660static pm_constant_path_write_node_t *
3661pm_constant_path_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3662 pm_constant_path_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_write_node_t);
3664 *node = (pm_constant_path_write_node_t) {
3666 .type = PM_CONSTANT_PATH_WRITE_NODE,
3667 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3668 .node_id = PM_NODE_IDENTIFY(parser),
3670 .start = target->base.location.start,
3671 .end = value->location.end
3675 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3685static pm_constant_and_write_node_t *
3686pm_constant_and_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3687 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3688 pm_constant_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_and_write_node_t);
3690 *node = (pm_constant_and_write_node_t) {
3692 .type = PM_CONSTANT_AND_WRITE_NODE,
3693 .node_id = PM_NODE_IDENTIFY(parser),
3695 .start = target->base.location.start,
3696 .end = value->location.end
3699 .name = target->name,
3700 .name_loc = target->base.location,
3701 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3711static pm_constant_operator_write_node_t *
3712pm_constant_operator_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3713 pm_constant_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_operator_write_node_t);
3715 *node = (pm_constant_operator_write_node_t) {
3717 .type = PM_CONSTANT_OPERATOR_WRITE_NODE,
3718 .node_id = PM_NODE_IDENTIFY(parser),
3720 .start = target->base.location.start,
3721 .end = value->location.end
3724 .name = target->name,
3725 .name_loc = target->base.location,
3726 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3728 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3737static pm_constant_or_write_node_t *
3738pm_constant_or_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3739 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3740 pm_constant_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_or_write_node_t);
3742 *node = (pm_constant_or_write_node_t) {
3744 .type = PM_CONSTANT_OR_WRITE_NODE,
3745 .node_id = PM_NODE_IDENTIFY(parser),
3747 .start = target->base.location.start,
3748 .end = value->location.end
3751 .name = target->name,
3752 .name_loc = target->base.location,
3753 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3763static pm_constant_read_node_t *
3764pm_constant_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
3765 assert(name->type == PM_TOKEN_CONSTANT || name->type == PM_TOKEN_MISSING);
3766 pm_constant_read_node_t *node = PM_NODE_ALLOC(parser, pm_constant_read_node_t);
3768 *node = (pm_constant_read_node_t) {
3770 .type = PM_CONSTANT_READ_NODE,
3771 .node_id = PM_NODE_IDENTIFY(parser),
3772 .location = PM_LOCATION_TOKEN_VALUE(name)
3774 .name = pm_parser_constant_id_token(parser, name)
3783static pm_constant_write_node_t *
3784pm_constant_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3785 pm_constant_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_write_node_t);
3787 *node = (pm_constant_write_node_t) {
3789 .type = PM_CONSTANT_WRITE_NODE,
3790 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3791 .node_id = PM_NODE_IDENTIFY(parser),
3793 .start = target->base.location.start,
3794 .end = value->location.end
3797 .name = target->name,
3798 .name_loc = target->base.location,
3799 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3810pm_def_node_receiver_check(pm_parser_t *parser, const pm_node_t *node) {
3811 switch (PM_NODE_TYPE(node)) {
3812 case PM_BEGIN_NODE: {
3813 const pm_begin_node_t *cast = (pm_begin_node_t *) node;
3814 if (cast->statements != NULL) pm_def_node_receiver_check(parser, (pm_node_t *) cast->statements);
3817 case PM_PARENTHESES_NODE: {
3818 const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node;
3819 if (cast->body != NULL) pm_def_node_receiver_check(parser, cast->body);
3822 case PM_STATEMENTS_NODE: {
3823 const pm_statements_node_t *cast = (const pm_statements_node_t *) node;
3824 pm_def_node_receiver_check(parser, cast->body.nodes[cast->body.size - 1]);
3829 case PM_IMAGINARY_NODE:
3830 case PM_INTEGER_NODE:
3831 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
3832 case PM_INTERPOLATED_STRING_NODE:
3833 case PM_INTERPOLATED_SYMBOL_NODE:
3834 case PM_INTERPOLATED_X_STRING_NODE:
3835 case PM_RATIONAL_NODE:
3836 case PM_REGULAR_EXPRESSION_NODE:
3837 case PM_SOURCE_ENCODING_NODE:
3838 case PM_SOURCE_FILE_NODE:
3839 case PM_SOURCE_LINE_NODE:
3840 case PM_STRING_NODE:
3841 case PM_SYMBOL_NODE:
3842 case PM_X_STRING_NODE:
3843 pm_parser_err_node(parser, node, PM_ERR_SINGLETON_FOR_LITERALS);
3853static pm_def_node_t *
3855 pm_parser_t *parser,
3856 pm_constant_id_t name,
3857 const pm_token_t *name_loc,
3858 pm_node_t *receiver,
3859 pm_parameters_node_t *parameters,
3861 pm_constant_id_list_t *locals,
3862 const pm_token_t *def_keyword,
3863 const pm_token_t *operator,
3864 const pm_token_t *lparen,
3865 const pm_token_t *rparen,
3866 const pm_token_t *equal,
3867 const pm_token_t *end_keyword
3869 pm_def_node_t *node = PM_NODE_ALLOC(parser, pm_def_node_t);
3872 if (end_keyword->type == PM_TOKEN_NOT_PROVIDED) {
3873 end = body->location.end;
3875 end = end_keyword->end;
3878 if (receiver != NULL) {
3879 pm_def_node_receiver_check(parser, receiver);
3882 *node = (pm_def_node_t) {
3884 .type = PM_DEF_NODE,
3885 .node_id = PM_NODE_IDENTIFY(parser),
3886 .location = { .start = def_keyword->start, .end = end },
3889 .name_loc = PM_LOCATION_TOKEN_VALUE(name_loc),
3890 .receiver = receiver,
3891 .parameters = parameters,
3894 .def_keyword_loc = PM_LOCATION_TOKEN_VALUE(def_keyword),
3895 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3896 .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
3897 .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
3898 .equal_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(equal),
3899 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
3908static pm_defined_node_t *
3909pm_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) {
3910 pm_defined_node_t *node = PM_NODE_ALLOC(parser, pm_defined_node_t);
3912 *node = (pm_defined_node_t) {
3914 .type = PM_DEFINED_NODE,
3915 .node_id = PM_NODE_IDENTIFY(parser),
3917 .start = keyword_loc->start,
3918 .end = (rparen->type == PM_TOKEN_NOT_PROVIDED ? value->location.end : rparen->end)
3921 .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
3923 .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
3924 .keyword_loc = *keyword_loc
3933static pm_else_node_t *
3934pm_else_node_create(pm_parser_t *parser, const pm_token_t *else_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
3935 pm_else_node_t *node = PM_NODE_ALLOC(parser, pm_else_node_t);
3936 const uint8_t *end = NULL;
3937 if ((end_keyword->type == PM_TOKEN_NOT_PROVIDED) && (statements != NULL)) {
3938 end = statements->base.location.end;
3940 end = end_keyword->end;
3943 *node = (pm_else_node_t) {
3945 .type = PM_ELSE_NODE,
3946 .node_id = PM_NODE_IDENTIFY(parser),
3948 .start = else_keyword->start,
3952 .else_keyword_loc = PM_LOCATION_TOKEN_VALUE(else_keyword),
3953 .statements = statements,
3954 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
3963static pm_embedded_statements_node_t *
3964pm_embedded_statements_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
3965 pm_embedded_statements_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_statements_node_t);
3967 *node = (pm_embedded_statements_node_t) {
3969 .type = PM_EMBEDDED_STATEMENTS_NODE,
3970 .node_id = PM_NODE_IDENTIFY(parser),
3972 .start = opening->start,
3976 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
3977 .statements = statements,
3978 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
3987static pm_embedded_variable_node_t *
3988pm_embedded_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
3989 pm_embedded_variable_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_variable_node_t);
3991 *node = (pm_embedded_variable_node_t) {
3993 .type = PM_EMBEDDED_VARIABLE_NODE,
3994 .node_id = PM_NODE_IDENTIFY(parser),
3996 .start = operator->start,
3997 .end = variable->location.end
4000 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4001 .variable = variable
4010static pm_ensure_node_t *
4011pm_ensure_node_create(pm_parser_t *parser, const pm_token_t *ensure_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
4012 pm_ensure_node_t *node = PM_NODE_ALLOC(parser, pm_ensure_node_t);
4014 *node = (pm_ensure_node_t) {
4016 .type = PM_ENSURE_NODE,
4017 .node_id = PM_NODE_IDENTIFY(parser),
4019 .start = ensure_keyword->start,
4020 .end = end_keyword->end
4023 .ensure_keyword_loc = PM_LOCATION_TOKEN_VALUE(ensure_keyword),
4024 .statements = statements,
4025 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
4034static pm_false_node_t *
4035pm_false_node_create(pm_parser_t *parser, const pm_token_t *token) {
4036 assert(token->type == PM_TOKEN_KEYWORD_FALSE);
4037 pm_false_node_t *node = PM_NODE_ALLOC(parser, pm_false_node_t);
4039 *node = (pm_false_node_t) {{
4040 .type = PM_FALSE_NODE,
4041 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4042 .node_id = PM_NODE_IDENTIFY(parser),
4043 .location = PM_LOCATION_TOKEN_VALUE(token)
4053static pm_find_pattern_node_t *
4054pm_find_pattern_node_create(pm_parser_t *parser, pm_node_list_t *nodes) {
4055 pm_find_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_find_pattern_node_t);
4057 pm_node_t *left = nodes->nodes[0];
4058 assert(PM_NODE_TYPE_P(left, PM_SPLAT_NODE));
4059 pm_splat_node_t *left_splat_node = (pm_splat_node_t *) left;
4063 if (nodes->size == 1) {
4064 right = (pm_node_t *) pm_missing_node_create(parser, left->location.end, left->location.end);
4066 right = nodes->nodes[nodes->size - 1];
4067 assert(PM_NODE_TYPE_P(right, PM_SPLAT_NODE));
4070#if PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS
4071 // FindPatternNode#right is typed as SplatNode in this case, so replace the potential MissingNode with a SplatNode.
4072 // The resulting AST will anyway be ignored, but this file still needs to compile.
4073 pm_splat_node_t *right_splat_node = PM_NODE_TYPE_P(right, PM_SPLAT_NODE) ? (pm_splat_node_t *) right : left_splat_node;
4075 pm_node_t *right_splat_node = right;
4077 *node = (pm_find_pattern_node_t) {
4079 .type = PM_FIND_PATTERN_NODE,
4080 .node_id = PM_NODE_IDENTIFY(parser),
4082 .start = left->location.start,
4083 .end = right->location.end,
4087 .left = left_splat_node,
4088 .right = right_splat_node,
4090 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4091 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4094 // For now we're going to just copy over each pointer manually. This could be
4095 // much more efficient, as we could instead resize the node list to only point
4097 for (size_t index = 1; index < nodes->size - 1; index++) {
4098 pm_node_list_append(&node->requireds, nodes->nodes[index]);
4109pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
4110 ptrdiff_t diff = token->end - token->start;
4111 if (diff <= 0) return 0.0;
4113 // First, get a buffer of the content.
4114 size_t length = (size_t) diff;
4115 char *buffer = xmalloc(sizeof(char) * (length + 1));
4116 memcpy((void *) buffer, token->start, length);
4118 // Next, determine if we need to replace the decimal point because of
4119 // locale-specific options, and then normalize them if we have to.
4120 char decimal_point = *localeconv()->decimal_point;
4121 if (decimal_point != '.') {
4122 for (size_t index = 0; index < length; index++) {
4123 if (buffer[index] == '.') buffer[index] = decimal_point;
4127 // Next, handle underscores by removing them from the buffer.
4128 for (size_t index = 0; index < length; index++) {
4129 if (buffer[index] == '_') {
4130 memmove((void *) (buffer + index), (void *) (buffer + index + 1), length - index);
4135 // Null-terminate the buffer so that strtod cannot read off the end.
4136 buffer[length] = '\0';
4138 // Now, call strtod to parse the value. Note that CRuby has their own
4139 // version of strtod which avoids locales. We're okay using the locale-aware
4140 // version because we've already validated through the parser that the token
4141 // is in a valid format.
4144 double value = strtod(buffer, &eptr);
4146 // This should never happen, because we've already checked that the token
4147 // is in a valid format. However it's good to be safe.
4148 if ((eptr != buffer + length) || (errno != 0 && errno != ERANGE)) {
4149 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, (*token), PM_ERR_FLOAT_PARSE);
4150 xfree((void *) buffer);
4154 // If errno is set, then it should only be ERANGE. At this point we need to
4155 // check if it's infinity (it should be).
4156 if (errno == ERANGE && PRISM_ISINF(value)) {
4158 const char *ellipsis;
4164 warn_width = (int) length;
4168 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);
4169 value = (value < 0.0) ? -HUGE_VAL : HUGE_VAL;
4172 // Finally we can free the buffer and return the value.
4173 xfree((void *) buffer);
4180static pm_float_node_t *
4181pm_float_node_create(pm_parser_t *parser, const pm_token_t *token) {
4182 assert(token->type == PM_TOKEN_FLOAT);
4183 pm_float_node_t *node = PM_NODE_ALLOC(parser, pm_float_node_t);
4185 *node = (pm_float_node_t) {
4187 .type = PM_FLOAT_NODE,
4188 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4189 .node_id = PM_NODE_IDENTIFY(parser),
4190 .location = PM_LOCATION_TOKEN_VALUE(token)
4192 .value = pm_double_parse(parser, token)
4201static pm_imaginary_node_t *
4202pm_float_node_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4203 assert(token->type == PM_TOKEN_FLOAT_IMAGINARY);
4205 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4206 *node = (pm_imaginary_node_t) {
4208 .type = PM_IMAGINARY_NODE,
4209 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4210 .node_id = PM_NODE_IDENTIFY(parser),
4211 .location = PM_LOCATION_TOKEN_VALUE(token)
4213 .numeric = (pm_node_t *) pm_float_node_create(parser, &((pm_token_t) {
4214 .type = PM_TOKEN_FLOAT,
4215 .start = token->start,
4216 .end = token->end - 1
4226static pm_rational_node_t *
4227pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
4228 assert(token->type == PM_TOKEN_FLOAT_RATIONAL);
4230 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
4231 *node = (pm_rational_node_t) {
4233 .type = PM_RATIONAL_NODE,
4234 .flags = PM_INTEGER_BASE_FLAGS_DECIMAL | PM_NODE_FLAG_STATIC_LITERAL,
4235 .node_id = PM_NODE_IDENTIFY(parser),
4236 .location = PM_LOCATION_TOKEN_VALUE(token)
4239 .denominator = { 0 }
4242 const uint8_t *start = token->start;
4243 const uint8_t *end = token->end - 1; // r
4245 while (start < end && *start == '0') start++; // 0.1 -> .1
4246 while (end > start && end[-1] == '0') end--; // 1.0 -> 1.
4248 size_t length = (size_t) (end - start);
4250 node->denominator.value = 1;
4254 const uint8_t *point = memchr(start, '.', length);
4255 assert(point && "should have a decimal point");
4257 uint8_t *digits = xmalloc(length);
4258 if (digits == NULL) {
4259 fputs("[pm_float_node_rational_create] Failed to allocate memory", stderr);
4263 memcpy(digits, start, (unsigned long) (point - start));
4264 memcpy(digits + (point - start), point + 1, (unsigned long) (end - point - 1));
4265 pm_integer_parse(&node->numerator, PM_INTEGER_BASE_DEFAULT, digits, digits + length - 1);
4268 if (end - point > 1) memset(digits + 1, '0', (size_t) (end - point - 1));
4269 pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + (end - point));
4272 pm_integers_reduce(&node->numerator, &node->denominator);
4280static pm_imaginary_node_t *
4281pm_float_node_rational_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4282 assert(token->type == PM_TOKEN_FLOAT_RATIONAL_IMAGINARY);
4284 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4285 *node = (pm_imaginary_node_t) {
4287 .type = PM_IMAGINARY_NODE,
4288 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4289 .node_id = PM_NODE_IDENTIFY(parser),
4290 .location = PM_LOCATION_TOKEN_VALUE(token)
4292 .numeric = (pm_node_t *) pm_float_node_rational_create(parser, &((pm_token_t) {
4293 .type = PM_TOKEN_FLOAT_RATIONAL,
4294 .start = token->start,
4295 .end = token->end - 1
4305static pm_for_node_t *
4307 pm_parser_t *parser,
4309 pm_node_t *collection,
4310 pm_statements_node_t *statements,
4311 const pm_token_t *for_keyword,
4312 const pm_token_t *in_keyword,
4313 const pm_token_t *do_keyword,
4314 const pm_token_t *end_keyword
4316 pm_for_node_t *node = PM_NODE_ALLOC(parser, pm_for_node_t);
4318 *node = (pm_for_node_t) {
4320 .type = PM_FOR_NODE,
4321 .node_id = PM_NODE_IDENTIFY(parser),
4323 .start = for_keyword->start,
4324 .end = end_keyword->end
4328 .collection = collection,
4329 .statements = statements,
4330 .for_keyword_loc = PM_LOCATION_TOKEN_VALUE(for_keyword),
4331 .in_keyword_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
4332 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
4333 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
4342static pm_forwarding_arguments_node_t *
4343pm_forwarding_arguments_node_create(pm_parser_t *parser, const pm_token_t *token) {
4344 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4345 pm_forwarding_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_arguments_node_t);
4347 *node = (pm_forwarding_arguments_node_t) {{
4348 .type = PM_FORWARDING_ARGUMENTS_NODE,
4349 .node_id = PM_NODE_IDENTIFY(parser),
4350 .location = PM_LOCATION_TOKEN_VALUE(token)
4359static pm_forwarding_parameter_node_t *
4360pm_forwarding_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
4361 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4362 pm_forwarding_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_parameter_node_t);
4364 *node = (pm_forwarding_parameter_node_t) {{
4365 .type = PM_FORWARDING_PARAMETER_NODE,
4366 .node_id = PM_NODE_IDENTIFY(parser),
4367 .location = PM_LOCATION_TOKEN_VALUE(token)
4376static pm_forwarding_super_node_t *
4377pm_forwarding_super_node_create(pm_parser_t *parser, const pm_token_t *token, pm_arguments_t *arguments) {
4378 assert(arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_NODE));
4379 assert(token->type == PM_TOKEN_KEYWORD_SUPER);
4380 pm_forwarding_super_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_super_node_t);
4382 pm_block_node_t *block = NULL;
4383 if (arguments->block != NULL) {
4384 block = (pm_block_node_t *) arguments->block;
4387 *node = (pm_forwarding_super_node_t) {
4389 .type = PM_FORWARDING_SUPER_NODE,
4390 .node_id = PM_NODE_IDENTIFY(parser),
4392 .start = token->start,
4393 .end = block != NULL ? block->base.location.end : token->end
4406static pm_hash_pattern_node_t *
4407pm_hash_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4408 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4410 *node = (pm_hash_pattern_node_t) {
4412 .type = PM_HASH_PATTERN_NODE,
4413 .node_id = PM_NODE_IDENTIFY(parser),
4415 .start = opening->start,
4420 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4421 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
4432static pm_hash_pattern_node_t *
4433pm_hash_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *elements, pm_node_t *rest) {
4434 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4436 const uint8_t *start;
4439 if (elements->size > 0) {
4441 start = elements->nodes[0]->location.start;
4442 end = rest->location.end;
4444 start = elements->nodes[0]->location.start;
4445 end = elements->nodes[elements->size - 1]->location.end;
4448 assert(rest != NULL);
4449 start = rest->location.start;
4450 end = rest->location.end;
4453 *node = (pm_hash_pattern_node_t) {
4455 .type = PM_HASH_PATTERN_NODE,
4456 .node_id = PM_NODE_IDENTIFY(parser),
4465 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4466 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4470 PM_NODE_LIST_FOREACH(elements, index, element) {
4471 pm_node_list_append(&node->elements, element);
4480static pm_constant_id_t
4481pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
4482 switch (PM_NODE_TYPE(target)) {
4483 case PM_GLOBAL_VARIABLE_READ_NODE:
4484 return ((pm_global_variable_read_node_t *) target)->name;
4485 case PM_BACK_REFERENCE_READ_NODE:
4486 return ((pm_back_reference_read_node_t *) target)->name;
4487 case PM_NUMBERED_REFERENCE_READ_NODE:
4488 // This will only ever happen in the event of a syntax error, but we
4489 // still need to provide something for the node.
4490 return pm_parser_constant_id_location(parser, target->location.start, target->location.end);
4492 assert(false && "unreachable");
4493 return (pm_constant_id_t) -1;
4500static pm_global_variable_and_write_node_t *
4501pm_global_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4502 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4503 pm_global_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_and_write_node_t);
4505 *node = (pm_global_variable_and_write_node_t) {
4507 .type = PM_GLOBAL_VARIABLE_AND_WRITE_NODE,
4508 .node_id = PM_NODE_IDENTIFY(parser),
4510 .start = target->location.start,
4511 .end = value->location.end
4514 .name = pm_global_variable_write_name(parser, target),
4515 .name_loc = target->location,
4516 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4526static pm_global_variable_operator_write_node_t *
4527pm_global_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4528 pm_global_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_operator_write_node_t);
4530 *node = (pm_global_variable_operator_write_node_t) {
4532 .type = PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE,
4533 .node_id = PM_NODE_IDENTIFY(parser),
4535 .start = target->location.start,
4536 .end = value->location.end
4539 .name = pm_global_variable_write_name(parser, target),
4540 .name_loc = target->location,
4541 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4543 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
4552static pm_global_variable_or_write_node_t *
4553pm_global_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4554 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4555 pm_global_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_or_write_node_t);
4557 *node = (pm_global_variable_or_write_node_t) {
4559 .type = PM_GLOBAL_VARIABLE_OR_WRITE_NODE,
4560 .node_id = PM_NODE_IDENTIFY(parser),
4562 .start = target->location.start,
4563 .end = value->location.end
4566 .name = pm_global_variable_write_name(parser, target),
4567 .name_loc = target->location,
4568 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4578static pm_global_variable_read_node_t *
4579pm_global_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
4580 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4582 *node = (pm_global_variable_read_node_t) {
4584 .type = PM_GLOBAL_VARIABLE_READ_NODE,
4585 .node_id = PM_NODE_IDENTIFY(parser),
4586 .location = PM_LOCATION_TOKEN_VALUE(name),
4588 .name = pm_parser_constant_id_token(parser, name)
4597static pm_global_variable_read_node_t *
4598pm_global_variable_read_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name) {
4599 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4601 *node = (pm_global_variable_read_node_t) {
4603 .type = PM_GLOBAL_VARIABLE_READ_NODE,
4604 .node_id = PM_NODE_IDENTIFY(parser),
4605 .location = PM_LOCATION_NULL_VALUE(parser)
4616static pm_global_variable_write_node_t *
4617pm_global_variable_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4618 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4620 *node = (pm_global_variable_write_node_t) {
4622 .type = PM_GLOBAL_VARIABLE_WRITE_NODE,
4623 .node_id = PM_NODE_IDENTIFY(parser),
4624 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
4626 .start = target->location.start,
4627 .end = value->location.end
4630 .name = pm_global_variable_write_name(parser, target),
4631 .name_loc = PM_LOCATION_NODE_VALUE(target),
4632 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
4642static pm_global_variable_write_node_t *
4643pm_global_variable_write_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name, pm_node_t *value) {
4644 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4646 *node = (pm_global_variable_write_node_t) {
4648 .type = PM_GLOBAL_VARIABLE_WRITE_NODE,
4649 .node_id = PM_NODE_IDENTIFY(parser),
4650 .location = PM_LOCATION_NULL_VALUE(parser)
4653 .name_loc = PM_LOCATION_NULL_VALUE(parser),
4654 .operator_loc = PM_LOCATION_NULL_VALUE(parser),
4664static pm_hash_node_t *
4665pm_hash_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4666 assert(opening != NULL);
4667 pm_hash_node_t *node = PM_NODE_ALLOC(parser, pm_hash_node_t);
4669 *node = (pm_hash_node_t) {
4671 .type = PM_HASH_NODE,
4672 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4673 .node_id = PM_NODE_IDENTIFY(parser),
4674 .location = PM_LOCATION_TOKEN_VALUE(opening)
4676 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4677 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
4688pm_hash_node_elements_append(pm_hash_node_t *hash, pm_node_t *element) {
4689 pm_node_list_append(&hash->elements, element);
4691 bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE);
4692 if (static_literal) {
4693 pm_assoc_node_t *assoc = (pm_assoc_node_t *) element;
4694 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);
4695 static_literal = static_literal && PM_NODE_FLAG_P(assoc->key, PM_NODE_FLAG_STATIC_LITERAL);
4696 static_literal = static_literal && PM_NODE_FLAG_P(assoc, PM_NODE_FLAG_STATIC_LITERAL);
4699 if (!static_literal) {
4700 pm_node_flag_unset((pm_node_t *)hash, PM_NODE_FLAG_STATIC_LITERAL);
4705pm_hash_node_closing_loc_set(pm_hash_node_t *hash, pm_token_t *token) {
4706 hash->base.location.end = token->end;
4707 hash->closing_loc = PM_LOCATION_TOKEN_VALUE(token);
4713static pm_if_node_t *
4714pm_if_node_create(pm_parser_t *parser,
4715 const pm_token_t *if_keyword,
4716 pm_node_t *predicate,
4717 const pm_token_t *then_keyword,
4718 pm_statements_node_t *statements,
4719 pm_node_t *subsequent,
4720 const pm_token_t *end_keyword
4722 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4723 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4726 if (end_keyword->type != PM_TOKEN_NOT_PROVIDED) {
4727 end = end_keyword->end;
4728 } else if (subsequent != NULL) {
4729 end = subsequent->location.end;
4730 } else if (pm_statements_node_body_length(statements) != 0) {
4731 end = statements->base.location.end;
4733 end = predicate->location.end;
4736 *node = (pm_if_node_t) {
4739 .flags = PM_NODE_FLAG_NEWLINE,
4740 .node_id = PM_NODE_IDENTIFY(parser),
4742 .start = if_keyword->start,
4746 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4747 .predicate = predicate,
4748 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
4749 .statements = statements,
4750 .subsequent = subsequent,
4751 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
4760static pm_if_node_t *
4761pm_if_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *if_keyword, pm_node_t *predicate) {
4762 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4763 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4765 pm_statements_node_t *statements = pm_statements_node_create(parser);
4766 pm_statements_node_body_append(parser, statements, statement, true);
4768 *node = (pm_if_node_t) {
4771 .flags = PM_NODE_FLAG_NEWLINE,
4772 .node_id = PM_NODE_IDENTIFY(parser),
4774 .start = statement->location.start,
4775 .end = predicate->location.end
4778 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4779 .predicate = predicate,
4780 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4781 .statements = statements,
4783 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4792static pm_if_node_t *
4793pm_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) {
4794 pm_assert_value_expression(parser, predicate);
4795 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4797 pm_statements_node_t *if_statements = pm_statements_node_create(parser);
4798 pm_statements_node_body_append(parser, if_statements, true_expression, true);
4800 pm_statements_node_t *else_statements = pm_statements_node_create(parser);
4801 pm_statements_node_body_append(parser, else_statements, false_expression, true);
4803 pm_token_t end_keyword = not_provided(parser);
4804 pm_else_node_t *else_node = pm_else_node_create(parser, colon, else_statements, &end_keyword);
4806 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4808 *node = (pm_if_node_t) {
4811 .flags = PM_NODE_FLAG_NEWLINE,
4812 .node_id = PM_NODE_IDENTIFY(parser),
4814 .start = predicate->location.start,
4815 .end = false_expression->location.end,
4818 .if_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4819 .predicate = predicate,
4820 .then_keyword_loc = PM_LOCATION_TOKEN_VALUE(qmark),
4821 .statements = if_statements,
4822 .subsequent = (pm_node_t *) else_node,
4823 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4831pm_if_node_end_keyword_loc_set(pm_if_node_t *node, const pm_token_t *keyword) {
4832 node->base.location.end = keyword->end;
4833 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4837pm_else_node_end_keyword_loc_set(pm_else_node_t *node, const pm_token_t *keyword) {
4838 node->base.location.end = keyword->end;
4839 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4845static pm_implicit_node_t *
4846pm_implicit_node_create(pm_parser_t *parser, pm_node_t *value) {
4847 pm_implicit_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_node_t);
4849 *node = (pm_implicit_node_t) {
4851 .type = PM_IMPLICIT_NODE,
4852 .node_id = PM_NODE_IDENTIFY(parser),
4853 .location = value->location
4864static pm_implicit_rest_node_t *
4865pm_implicit_rest_node_create(pm_parser_t *parser, const pm_token_t *token) {
4866 assert(token->type == PM_TOKEN_COMMA);
4868 pm_implicit_rest_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_rest_node_t);
4870 *node = (pm_implicit_rest_node_t) {
4872 .type = PM_IMPLICIT_REST_NODE,
4873 .node_id = PM_NODE_IDENTIFY(parser),
4874 .location = PM_LOCATION_TOKEN_VALUE(token)
4884static pm_integer_node_t *
4885pm_integer_node_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4886 assert(token->type == PM_TOKEN_INTEGER);
4887 pm_integer_node_t *node = PM_NODE_ALLOC(parser, pm_integer_node_t);
4889 *node = (pm_integer_node_t) {
4891 .type = PM_INTEGER_NODE,
4892 .flags = base | PM_NODE_FLAG_STATIC_LITERAL,
4893 .node_id = PM_NODE_IDENTIFY(parser),
4894 .location = PM_LOCATION_TOKEN_VALUE(token)
4899 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4901 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4902 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4903 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4904 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4905 default: assert(false && "unreachable"); break;
4908 pm_integer_parse(&node->value, integer_base, token->start, token->end);
4916static pm_imaginary_node_t *
4917pm_integer_node_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4918 assert(token->type == PM_TOKEN_INTEGER_IMAGINARY);
4920 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4921 *node = (pm_imaginary_node_t) {
4923 .type = PM_IMAGINARY_NODE,
4924 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4925 .node_id = PM_NODE_IDENTIFY(parser),
4926 .location = PM_LOCATION_TOKEN_VALUE(token)
4928 .numeric = (pm_node_t *) pm_integer_node_create(parser, base, &((pm_token_t) {
4929 .type = PM_TOKEN_INTEGER,
4930 .start = token->start,
4931 .end = token->end - 1
4942static pm_rational_node_t *
4943pm_integer_node_rational_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4944 assert(token->type == PM_TOKEN_INTEGER_RATIONAL);
4946 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
4947 *node = (pm_rational_node_t) {
4949 .type = PM_RATIONAL_NODE,
4950 .flags = base | PM_NODE_FLAG_STATIC_LITERAL,
4951 .node_id = PM_NODE_IDENTIFY(parser),
4952 .location = PM_LOCATION_TOKEN_VALUE(token)
4955 .denominator = { .value = 1, 0 }
4958 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4960 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4961 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4962 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4963 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4964 default: assert(false && "unreachable"); break;
4967 pm_integer_parse(&node->numerator, integer_base, token->start, token->end - 1);
4976static pm_imaginary_node_t *
4977pm_integer_node_rational_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4978 assert(token->type == PM_TOKEN_INTEGER_RATIONAL_IMAGINARY);
4980 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4981 *node = (pm_imaginary_node_t) {
4983 .type = PM_IMAGINARY_NODE,
4984 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4985 .node_id = PM_NODE_IDENTIFY(parser),
4986 .location = PM_LOCATION_TOKEN_VALUE(token)
4988 .numeric = (pm_node_t *) pm_integer_node_rational_create(parser, base, &((pm_token_t) {
4989 .type = PM_TOKEN_INTEGER_RATIONAL,
4990 .start = token->start,
4991 .end = token->end - 1
5001static pm_in_node_t *
5002pm_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) {
5003 pm_in_node_t *node = PM_NODE_ALLOC(parser, pm_in_node_t);
5006 if (statements != NULL) {
5007 end = statements->base.location.end;
5008 } else if (then_keyword->type != PM_TOKEN_NOT_PROVIDED) {
5009 end = then_keyword->end;
5011 end = pattern->location.end;
5014 *node = (pm_in_node_t) {
5017 .node_id = PM_NODE_IDENTIFY(parser),
5019 .start = in_keyword->start,
5024 .statements = statements,
5025 .in_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
5026 .then_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword)
5035static pm_instance_variable_and_write_node_t *
5036pm_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) {
5037 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5038 pm_instance_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_and_write_node_t);
5040 *node = (pm_instance_variable_and_write_node_t) {
5042 .type = PM_INSTANCE_VARIABLE_AND_WRITE_NODE,
5043 .node_id = PM_NODE_IDENTIFY(parser),
5045 .start = target->base.location.start,
5046 .end = value->location.end
5049 .name = target->name,
5050 .name_loc = target->base.location,
5051 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5061static pm_instance_variable_operator_write_node_t *
5062pm_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) {
5063 pm_instance_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_operator_write_node_t);
5065 *node = (pm_instance_variable_operator_write_node_t) {
5067 .type = PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE,
5068 .node_id = PM_NODE_IDENTIFY(parser),
5070 .start = target->base.location.start,
5071 .end = value->location.end
5074 .name = target->name,
5075 .name_loc = target->base.location,
5076 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5078 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
5087static pm_instance_variable_or_write_node_t *
5088pm_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) {
5089 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5090 pm_instance_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_or_write_node_t);
5092 *node = (pm_instance_variable_or_write_node_t) {
5094 .type = PM_INSTANCE_VARIABLE_OR_WRITE_NODE,
5095 .node_id = PM_NODE_IDENTIFY(parser),
5097 .start = target->base.location.start,
5098 .end = value->location.end
5101 .name = target->name,
5102 .name_loc = target->base.location,
5103 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5113static pm_instance_variable_read_node_t *
5114pm_instance_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
5115 assert(token->type == PM_TOKEN_INSTANCE_VARIABLE);
5116 pm_instance_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_read_node_t);
5118 *node = (pm_instance_variable_read_node_t) {
5120 .type = PM_INSTANCE_VARIABLE_READ_NODE,
5121 .node_id = PM_NODE_IDENTIFY(parser),
5122 .location = PM_LOCATION_TOKEN_VALUE(token)
5124 .name = pm_parser_constant_id_token(parser, token)
5134static pm_instance_variable_write_node_t *
5135pm_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) {
5136 pm_instance_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_write_node_t);
5137 *node = (pm_instance_variable_write_node_t) {
5139 .type = PM_INSTANCE_VARIABLE_WRITE_NODE,
5140 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5141 .node_id = PM_NODE_IDENTIFY(parser),
5143 .start = read_node->base.location.start,
5144 .end = value->location.end
5147 .name = read_node->name,
5148 .name_loc = PM_LOCATION_NODE_BASE_VALUE(read_node),
5149 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
5162pm_interpolated_node_append(pm_node_t *node, pm_node_list_t *parts, pm_node_t *part) {
5163 switch (PM_NODE_TYPE(part)) {
5164 case PM_STRING_NODE:
5165 pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5167 case PM_EMBEDDED_STATEMENTS_NODE: {
5168 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5169 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5171 if (embedded == NULL) {
5172 // If there are no statements or more than one statement, then
5173 // we lose the static literal flag.
5174 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5175 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5176 // If the embedded statement is a string, then we can keep the
5177 // static literal flag and mark the string as frozen.
5178 pm_node_flag_set(embedded, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5179 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5180 // If the embedded statement is an interpolated string and it's
5181 // a static literal, then we can keep the static literal flag.
5183 // Otherwise we lose the static literal flag.
5184 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5189 case PM_EMBEDDED_VARIABLE_NODE:
5190 pm_node_flag_unset((pm_node_t *) node, PM_NODE_FLAG_STATIC_LITERAL);
5193 assert(false && "unexpected node type");
5197 pm_node_list_append(parts, part);
5203static pm_interpolated_regular_expression_node_t *
5204pm_interpolated_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening) {
5205 pm_interpolated_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_regular_expression_node_t);
5207 *node = (pm_interpolated_regular_expression_node_t) {
5209 .type = PM_INTERPOLATED_REGULAR_EXPRESSION_NODE,
5210 .flags = PM_NODE_FLAG_STATIC_LITERAL,
5211 .node_id = PM_NODE_IDENTIFY(parser),
5213 .start = opening->start,
5217 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5218 .closing_loc = PM_LOCATION_TOKEN_VALUE(opening),
5226pm_interpolated_regular_expression_node_append(pm_interpolated_regular_expression_node_t *node, pm_node_t *part) {
5227 if (node->base.location.start > part->location.start) {
5228 node->base.location.start = part->location.start;
5230 if (node->base.location.end < part->location.end) {
5231 node->base.location.end = part->location.end;
5234 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5238pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_interpolated_regular_expression_node_t *node, const pm_token_t *closing) {
5239 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
5240 node->base.location.end = closing->end;
5241 pm_node_flag_set((pm_node_t *) node, pm_regular_expression_flags_create(parser, closing));
5268pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_node_t *part) {
5269#define CLEAR_FLAGS(node) \
5270 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))
5272#define MUTABLE_FLAGS(node) \
5273 node->base.flags = (pm_node_flags_t) ((node->base.flags | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE) & ~PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN);
5275 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
5276 node->base.location.start = part->location.start;
5279 node->base.location.end = MAX(node->base.location.end, part->location.end);
5281 switch (PM_NODE_TYPE(part)) {
5282 case PM_STRING_NODE:
5283 // If inner string is not frozen, it stops being a static literal. We should *not* clear other flags,
5284 // because concatenating two frozen strings (`'foo' 'bar'`) is still frozen. This holds true for
5285 // as long as this interpolation only consists of other string literals.
5286 if (!PM_NODE_FLAG_P(part, PM_STRING_FLAGS_FROZEN)) {
5287 pm_node_flag_unset((pm_node_t *) node, PM_NODE_FLAG_STATIC_LITERAL);
5289 part->flags = (pm_node_flags_t) ((part->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5291 case PM_INTERPOLATED_STRING_NODE:
5292 if (PM_NODE_FLAG_P(part, PM_NODE_FLAG_STATIC_LITERAL)) {
5293 // If the string that we're concatenating is a static literal,
5294 // then we can keep the static literal flag for this string.
5296 // Otherwise, we lose the static literal flag here and we should
5297 // also clear the mutability flags.
5301 case PM_EMBEDDED_STATEMENTS_NODE: {
5302 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5303 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5305 if (embedded == NULL) {
5306 // If we're embedding multiple statements or no statements, then
5307 // the string is not longer a static literal.
5309 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5310 // If the embedded statement is a string, then we can make that
5311 // string as frozen and static literal, and not touch the static
5312 // literal status of this string.
5313 embedded->flags = (pm_node_flags_t) ((embedded->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5315 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5316 MUTABLE_FLAGS(node);
5318 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5319 // If the embedded statement is an interpolated string, but that
5320 // string is marked as static literal, then we can keep our
5321 // static literal status for this string.
5322 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5323 MUTABLE_FLAGS(node);
5326 // In all other cases, we lose the static literal flag here and
5333 case PM_EMBEDDED_VARIABLE_NODE:
5334 // Embedded variables clear static literal, which means we also
5335 // should clear the mutability flags.
5338 case PM_X_STRING_NODE:
5339 case PM_INTERPOLATED_X_STRING_NODE:
5340 // If this is an x string, then this is a syntax error. But we want
5341 // to handle it here so that we don't fail the assertion.
5345 assert(false && "unexpected node type");
5349 pm_node_list_append(&node->parts, part);
5358static pm_interpolated_string_node_t *
5359pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5360 pm_interpolated_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_string_node_t);
5361 pm_node_flags_t flags = PM_NODE_FLAG_STATIC_LITERAL;
5363 switch (parser->frozen_string_literal) {
5364 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
5365 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE;
5367 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
5368 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN;
5372 *node = (pm_interpolated_string_node_t) {
5374 .type = PM_INTERPOLATED_STRING_NODE,
5376 .node_id = PM_NODE_IDENTIFY(parser),
5378 .start = opening->start,
5379 .end = closing->end,
5382 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5383 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5387 if (parts != NULL) {
5389 PM_NODE_LIST_FOREACH(parts, index, part) {
5390 pm_interpolated_string_node_append(node, part);
5401pm_interpolated_string_node_closing_set(pm_interpolated_string_node_t *node, const pm_token_t *closing) {
5402 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5403 node->base.location.end = closing->end;
5407pm_interpolated_symbol_node_append(pm_interpolated_symbol_node_t *node, pm_node_t *part) {
5408 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
5409 node->base.location.start = part->location.start;
5412 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5413 node->base.location.end = MAX(node->base.location.end, part->location.end);
5417pm_interpolated_symbol_node_closing_loc_set(pm_interpolated_symbol_node_t *node, const pm_token_t *closing) {
5418 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5419 node->base.location.end = closing->end;
5425static pm_interpolated_symbol_node_t *
5426pm_interpolated_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5427 pm_interpolated_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_symbol_node_t);
5429 *node = (pm_interpolated_symbol_node_t) {
5431 .type = PM_INTERPOLATED_SYMBOL_NODE,
5432 .flags = PM_NODE_FLAG_STATIC_LITERAL,
5433 .node_id = PM_NODE_IDENTIFY(parser),
5435 .start = opening->start,
5436 .end = closing->end,
5439 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5440 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5444 if (parts != NULL) {
5446 PM_NODE_LIST_FOREACH(parts, index, part) {
5447 pm_interpolated_symbol_node_append(node, part);
5457static pm_interpolated_x_string_node_t *
5458pm_interpolated_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5459 pm_interpolated_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_x_string_node_t);
5461 *node = (pm_interpolated_x_string_node_t) {
5463 .type = PM_INTERPOLATED_X_STRING_NODE,
5464 .node_id = PM_NODE_IDENTIFY(parser),
5466 .start = opening->start,
5470 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5471 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5479pm_interpolated_xstring_node_append(pm_interpolated_x_string_node_t *node, pm_node_t *part) {
5480 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5481 node->base.location.end = part->location.end;
5485pm_interpolated_xstring_node_closing_set(pm_interpolated_x_string_node_t *node, const pm_token_t *closing) {
5486 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5487 node->base.location.end = closing->end;
5493static pm_it_local_variable_read_node_t *
5494pm_it_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5495 pm_it_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_it_local_variable_read_node_t);
5497 *node = (pm_it_local_variable_read_node_t) {
5499 .type = PM_IT_LOCAL_VARIABLE_READ_NODE,
5500 .node_id = PM_NODE_IDENTIFY(parser),
5501 .location = PM_LOCATION_TOKEN_VALUE(name)
5511static pm_it_parameters_node_t *
5512pm_it_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5513 pm_it_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_it_parameters_node_t);
5515 *node = (pm_it_parameters_node_t) {
5517 .type = PM_IT_PARAMETERS_NODE,
5518 .node_id = PM_NODE_IDENTIFY(parser),
5520 .start = opening->start,
5532static pm_keyword_hash_node_t *
5533pm_keyword_hash_node_create(pm_parser_t *parser) {
5534 pm_keyword_hash_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_hash_node_t);
5536 *node = (pm_keyword_hash_node_t) {
5538 .type = PM_KEYWORD_HASH_NODE,
5539 .flags = PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS,
5540 .node_id = PM_NODE_IDENTIFY(parser),
5541 .location = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
5553pm_keyword_hash_node_elements_append(pm_keyword_hash_node_t *hash, pm_node_t *element) {
5554 // If the element being added is not an AssocNode or does not have a symbol
5555 // key, then we want to turn the SYMBOL_KEYS flag off.
5556 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE) || !PM_NODE_TYPE_P(((pm_assoc_node_t *) element)->key, PM_SYMBOL_NODE)) {
5557 pm_node_flag_unset((pm_node_t *)hash, PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS);
5560 pm_node_list_append(&hash->elements, element);
5561 if (hash->base.location.start == NULL) {
5562 hash->base.location.start = element->location.start;
5564 hash->base.location.end = element->location.end;
5570static pm_required_keyword_parameter_node_t *
5571pm_required_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name) {
5572 pm_required_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_keyword_parameter_node_t);
5574 *node = (pm_required_keyword_parameter_node_t) {
5576 .type = PM_REQUIRED_KEYWORD_PARAMETER_NODE,
5577 .node_id = PM_NODE_IDENTIFY(parser),
5579 .start = name->start,
5583 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5584 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5593static pm_optional_keyword_parameter_node_t *
5594pm_optional_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, pm_node_t *value) {
5595 pm_optional_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_keyword_parameter_node_t);
5597 *node = (pm_optional_keyword_parameter_node_t) {
5599 .type = PM_OPTIONAL_KEYWORD_PARAMETER_NODE,
5600 .node_id = PM_NODE_IDENTIFY(parser),
5602 .start = name->start,
5603 .end = value->location.end
5606 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5607 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5617static pm_keyword_rest_parameter_node_t *
5618pm_keyword_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
5619 pm_keyword_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_rest_parameter_node_t);
5621 *node = (pm_keyword_rest_parameter_node_t) {
5623 .type = PM_KEYWORD_REST_PARAMETER_NODE,
5624 .node_id = PM_NODE_IDENTIFY(parser),
5626 .start = operator->start,
5627 .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
5630 .name = pm_parser_optional_constant_id_token(parser, name),
5631 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
5632 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5641static pm_lambda_node_t *
5642pm_lambda_node_create(
5643 pm_parser_t *parser,
5644 pm_constant_id_list_t *locals,
5645 const pm_token_t *operator,
5646 const pm_token_t *opening,
5647 const pm_token_t *closing,
5648 pm_node_t *parameters,
5651 pm_lambda_node_t *node = PM_NODE_ALLOC(parser, pm_lambda_node_t);
5653 *node = (pm_lambda_node_t) {
5655 .type = PM_LAMBDA_NODE,
5656 .node_id = PM_NODE_IDENTIFY(parser),
5658 .start = operator->start,
5663 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5664 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5665 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
5666 .parameters = parameters,
5676static pm_local_variable_and_write_node_t *
5677pm_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) {
5678 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));
5679 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5680 pm_local_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_and_write_node_t);
5682 *node = (pm_local_variable_and_write_node_t) {
5684 .type = PM_LOCAL_VARIABLE_AND_WRITE_NODE,
5685 .node_id = PM_NODE_IDENTIFY(parser),
5687 .start = target->location.start,
5688 .end = value->location.end
5691 .name_loc = target->location,
5692 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5704static pm_local_variable_operator_write_node_t *
5705pm_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) {
5706 pm_local_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_operator_write_node_t);
5708 *node = (pm_local_variable_operator_write_node_t) {
5710 .type = PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE,
5711 .node_id = PM_NODE_IDENTIFY(parser),
5713 .start = target->location.start,
5714 .end = value->location.end
5717 .name_loc = target->location,
5718 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5721 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
5731static pm_local_variable_or_write_node_t *
5732pm_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) {
5733 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));
5734 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5735 pm_local_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_or_write_node_t);
5737 *node = (pm_local_variable_or_write_node_t) {
5739 .type = PM_LOCAL_VARIABLE_OR_WRITE_NODE,
5740 .node_id = PM_NODE_IDENTIFY(parser),
5742 .start = target->location.start,
5743 .end = value->location.end
5746 .name_loc = target->location,
5747 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5759static pm_local_variable_read_node_t *
5760pm_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) {
5761 if (!missing) pm_locals_read(&pm_parser_scope_find(parser, depth)->locals, name_id);
5763 pm_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_read_node_t);
5765 *node = (pm_local_variable_read_node_t) {
5767 .type = PM_LOCAL_VARIABLE_READ_NODE,
5768 .node_id = PM_NODE_IDENTIFY(parser),
5769 .location = PM_LOCATION_TOKEN_VALUE(name)
5781static pm_local_variable_read_node_t *
5782pm_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5783 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5784 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, false);
5791static pm_local_variable_read_node_t *
5792pm_local_variable_read_node_missing_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5793 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5794 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, true);
5800static pm_local_variable_write_node_t *
5801pm_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) {
5802 pm_local_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_write_node_t);
5804 *node = (pm_local_variable_write_node_t) {
5806 .type = PM_LOCAL_VARIABLE_WRITE_NODE,
5807 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5808 .node_id = PM_NODE_IDENTIFY(parser),
5810 .start = name_loc->start,
5811 .end = value->location.end
5817 .name_loc = *name_loc,
5818 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator)
5828pm_token_is_it(const uint8_t *start, const uint8_t *end) {
5829 return (end - start == 2) && (start[0] == 'i') && (start[1] == 't');
5837pm_token_is_numbered_parameter(const uint8_t *start, const uint8_t *end) {
5838 return (end - start == 2) && (start[0] == '_') && (start[1] != '0') && (pm_char_is_decimal_digit(start[1]));
5846pm_refute_numbered_parameter(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
5847 if (pm_token_is_numbered_parameter(start, end)) {
5848 PM_PARSER_ERR_FORMAT(parser, start, end, PM_ERR_PARAMETER_NUMBERED_RESERVED, start);
5856static pm_local_variable_target_node_t *
5857pm_local_variable_target_node_create(pm_parser_t *parser, const pm_location_t *location, pm_constant_id_t name, uint32_t depth) {
5858 pm_refute_numbered_parameter(parser, location->start, location->end);
5859 pm_local_variable_target_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_target_node_t);
5861 *node = (pm_local_variable_target_node_t) {
5863 .type = PM_LOCAL_VARIABLE_TARGET_NODE,
5864 .node_id = PM_NODE_IDENTIFY(parser),
5865 .location = *location
5877static pm_match_predicate_node_t *
5878pm_match_predicate_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5879 pm_assert_value_expression(parser, value);
5881 pm_match_predicate_node_t *node = PM_NODE_ALLOC(parser, pm_match_predicate_node_t);
5883 *node = (pm_match_predicate_node_t) {
5885 .type = PM_MATCH_PREDICATE_NODE,
5886 .node_id = PM_NODE_IDENTIFY(parser),
5888 .start = value->location.start,
5889 .end = pattern->location.end
5894 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5903static pm_match_required_node_t *
5904pm_match_required_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5905 pm_assert_value_expression(parser, value);
5907 pm_match_required_node_t *node = PM_NODE_ALLOC(parser, pm_match_required_node_t);
5909 *node = (pm_match_required_node_t) {
5911 .type = PM_MATCH_REQUIRED_NODE,
5912 .node_id = PM_NODE_IDENTIFY(parser),
5914 .start = value->location.start,
5915 .end = pattern->location.end
5920 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5929static pm_match_write_node_t *
5930pm_match_write_node_create(pm_parser_t *parser, pm_call_node_t *call) {
5931 pm_match_write_node_t *node = PM_NODE_ALLOC(parser, pm_match_write_node_t);
5933 *node = (pm_match_write_node_t) {
5935 .type = PM_MATCH_WRITE_NODE,
5936 .node_id = PM_NODE_IDENTIFY(parser),
5937 .location = call->base.location
5949static pm_module_node_t *
5950pm_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) {
5951 pm_module_node_t *node = PM_NODE_ALLOC(parser, pm_module_node_t);
5953 *node = (pm_module_node_t) {
5955 .type = PM_MODULE_NODE,
5956 .node_id = PM_NODE_IDENTIFY(parser),
5958 .start = module_keyword->start,
5959 .end = end_keyword->end
5962 .locals = (locals == NULL ? ((pm_constant_id_list_t) { .ids = NULL, .size = 0, .capacity = 0 }) : *locals),
5963 .module_keyword_loc = PM_LOCATION_TOKEN_VALUE(module_keyword),
5964 .constant_path = constant_path,
5966 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
5967 .name = pm_parser_constant_id_token(parser, name)
5976static pm_multi_target_node_t *
5977pm_multi_target_node_create(pm_parser_t *parser) {
5978 pm_multi_target_node_t *node = PM_NODE_ALLOC(parser, pm_multi_target_node_t);
5980 *node = (pm_multi_target_node_t) {
5982 .type = PM_MULTI_TARGET_NODE,
5983 .node_id = PM_NODE_IDENTIFY(parser),
5984 .location = { .start = NULL, .end = NULL }
5989 .lparen_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
5990 .rparen_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
6000pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t *node, pm_node_t *target) {
6001 if (PM_NODE_TYPE_P(target, PM_SPLAT_NODE)) {
6002 if (node->rest == NULL) {
6003 node->rest = target;
6005 pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
6006 pm_node_list_append(&node->rights, target);
6008 } else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
6009 if (node->rest == NULL) {
6010 node->rest = target;
6012 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
6013 pm_node_list_append(&node->rights, target);
6015 } else if (node->rest == NULL) {
6016 pm_node_list_append(&node->lefts, target);
6018 pm_node_list_append(&node->rights, target);
6021 if (node->base.location.start == NULL || (node->base.location.start > target->location.start)) {
6022 node->base.location.start = target->location.start;
6025 if (node->base.location.end == NULL || (node->base.location.end < target->location.end)) {
6026 node->base.location.end = target->location.end;
6034pm_multi_target_node_opening_set(pm_multi_target_node_t *node, const pm_token_t *lparen) {
6035 node->base.location.start = lparen->start;
6036 node->lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen);
6043pm_multi_target_node_closing_set(pm_multi_target_node_t *node, const pm_token_t *rparen) {
6044 node->base.location.end = rparen->end;
6045 node->rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen);
6051static pm_multi_write_node_t *
6052pm_multi_write_node_create(pm_parser_t *parser, pm_multi_target_node_t *target, const pm_token_t *operator, pm_node_t *value) {
6053 pm_multi_write_node_t *node = PM_NODE_ALLOC(parser, pm_multi_write_node_t);
6055 *node = (pm_multi_write_node_t) {
6057 .type = PM_MULTI_WRITE_NODE,
6058 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
6059 .node_id = PM_NODE_IDENTIFY(parser),
6061 .start = target->base.location.start,
6062 .end = value->location.end
6065 .lefts = target->lefts,
6066 .rest = target->rest,
6067 .rights = target->rights,
6068 .lparen_loc = target->lparen_loc,
6069 .rparen_loc = target->rparen_loc,
6070 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6074 // Explicitly do not call pm_node_destroy here because we want to keep
6075 // around all of the information within the MultiWriteNode node.
6084static pm_next_node_t *
6085pm_next_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6086 assert(keyword->type == PM_TOKEN_KEYWORD_NEXT);
6087 pm_next_node_t *node = PM_NODE_ALLOC(parser, pm_next_node_t);
6089 *node = (pm_next_node_t) {
6091 .type = PM_NEXT_NODE,
6092 .node_id = PM_NODE_IDENTIFY(parser),
6094 .start = keyword->start,
6095 .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
6098 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6099 .arguments = arguments
6108static pm_nil_node_t *
6109pm_nil_node_create(pm_parser_t *parser, const pm_token_t *token) {
6110 assert(token->type == PM_TOKEN_KEYWORD_NIL);
6111 pm_nil_node_t *node = PM_NODE_ALLOC(parser, pm_nil_node_t);
6113 *node = (pm_nil_node_t) {{
6114 .type = PM_NIL_NODE,
6115 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6116 .node_id = PM_NODE_IDENTIFY(parser),
6117 .location = PM_LOCATION_TOKEN_VALUE(token)
6126static pm_no_keywords_parameter_node_t *
6127pm_no_keywords_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
6128 assert(operator->type == PM_TOKEN_USTAR_STAR || operator->type == PM_TOKEN_STAR_STAR);
6129 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
6130 pm_no_keywords_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_no_keywords_parameter_node_t);
6132 *node = (pm_no_keywords_parameter_node_t) {
6134 .type = PM_NO_KEYWORDS_PARAMETER_NODE,
6135 .node_id = PM_NODE_IDENTIFY(parser),
6137 .start = operator->start,
6141 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6142 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
6151static pm_numbered_parameters_node_t *
6152pm_numbered_parameters_node_create(pm_parser_t *parser, const pm_location_t *location, uint8_t maximum) {
6153 pm_numbered_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_parameters_node_t);
6155 *node = (pm_numbered_parameters_node_t) {
6157 .type = PM_NUMBERED_PARAMETERS_NODE,
6158 .node_id = PM_NODE_IDENTIFY(parser),
6159 .location = *location
6171#define NTH_REF_MAX ((uint32_t) (INT_MAX >> 1))
6180pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *token) {
6181 const uint8_t *start = token->start + 1;
6182 const uint8_t *end = token->end;
6184 ptrdiff_t diff = end - start;
6186#if PTRDIFF_MAX > SIZE_MAX
6187 assert(diff < (ptrdiff_t) SIZE_MAX);
6189 size_t length = (size_t) diff;
6191 char *digits = xcalloc(length + 1, sizeof(char));
6192 memcpy(digits, start, length);
6193 digits[length] = '\0';
6197 unsigned long value = strtoul(digits, &endptr, 10);
6199 if ((digits == endptr) || (*endptr != '\0')) {
6200 pm_parser_err(parser, start, end, PM_ERR_INVALID_NUMBER_DECIMAL);
6206 if ((errno == ERANGE) || (value > NTH_REF_MAX)) {
6207 PM_PARSER_WARN_FORMAT(parser, start, end, PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start);
6211 return (uint32_t) value;
6219static pm_numbered_reference_read_node_t *
6220pm_numbered_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
6221 assert(name->type == PM_TOKEN_NUMBERED_REFERENCE);
6222 pm_numbered_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_reference_read_node_t);
6224 *node = (pm_numbered_reference_read_node_t) {
6226 .type = PM_NUMBERED_REFERENCE_READ_NODE,
6227 .node_id = PM_NODE_IDENTIFY(parser),
6228 .location = PM_LOCATION_TOKEN_VALUE(name),
6230 .number = pm_numbered_reference_read_node_number(parser, name)
6239static pm_optional_parameter_node_t *
6240pm_optional_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator, pm_node_t *value) {
6241 pm_optional_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_parameter_node_t);
6243 *node = (pm_optional_parameter_node_t) {
6245 .type = PM_OPTIONAL_PARAMETER_NODE,
6246 .node_id = PM_NODE_IDENTIFY(parser),
6248 .start = name->start,
6249 .end = value->location.end
6252 .name = pm_parser_constant_id_token(parser, name),
6253 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
6254 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6264static pm_or_node_t *
6265pm_or_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
6266 pm_assert_value_expression(parser, left);
6268 pm_or_node_t *node = PM_NODE_ALLOC(parser, pm_or_node_t);
6270 *node = (pm_or_node_t) {
6273 .node_id = PM_NODE_IDENTIFY(parser),
6275 .start = left->location.start,
6276 .end = right->location.end
6281 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6290static pm_parameters_node_t *
6291pm_parameters_node_create(pm_parser_t *parser) {
6292 pm_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_parameters_node_t);
6294 *node = (pm_parameters_node_t) {
6296 .type = PM_PARAMETERS_NODE,
6297 .node_id = PM_NODE_IDENTIFY(parser),
6298 .location = PM_LOCATION_TOKEN_VALUE(&parser->current)
6301 .keyword_rest = NULL,
6316pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param) {
6317 if (params->base.location.start == NULL) {
6318 params->base.location.start = param->location.start;
6320 params->base.location.start = params->base.location.start < param->location.start ? params->base.location.start : param->location.start;
6323 if (params->base.location.end == NULL) {
6324 params->base.location.end = param->location.end;
6326 params->base.location.end = params->base.location.end > param->location.end ? params->base.location.end : param->location.end;
6334pm_parameters_node_requireds_append(pm_parameters_node_t *params, pm_node_t *param) {
6335 pm_parameters_node_location_set(params, param);
6336 pm_node_list_append(¶ms->requireds, param);
6343pm_parameters_node_optionals_append(pm_parameters_node_t *params, pm_optional_parameter_node_t *param) {
6344 pm_parameters_node_location_set(params, (pm_node_t *) param);
6345 pm_node_list_append(¶ms->optionals, (pm_node_t *) param);
6352pm_parameters_node_posts_append(pm_parameters_node_t *params, pm_node_t *param) {
6353 pm_parameters_node_location_set(params, param);
6354 pm_node_list_append(¶ms->posts, param);
6361pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6362 pm_parameters_node_location_set(params, param);
6363 params->rest = param;
6370pm_parameters_node_keywords_append(pm_parameters_node_t *params, pm_node_t *param) {
6371 pm_parameters_node_location_set(params, param);
6372 pm_node_list_append(¶ms->keywords, param);
6379pm_parameters_node_keyword_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6380 assert(params->keyword_rest == NULL);
6381 pm_parameters_node_location_set(params, param);
6382 params->keyword_rest = param;
6389pm_parameters_node_block_set(pm_parameters_node_t *params, pm_block_parameter_node_t *param) {
6390 assert(params->block == NULL);
6391 pm_parameters_node_location_set(params, (pm_node_t *) param);
6392 params->block = param;
6398static pm_program_node_t *
6399pm_program_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, pm_statements_node_t *statements) {
6400 pm_program_node_t *node = PM_NODE_ALLOC(parser, pm_program_node_t);
6402 *node = (pm_program_node_t) {
6404 .type = PM_PROGRAM_NODE,
6405 .node_id = PM_NODE_IDENTIFY(parser),
6407 .start = statements == NULL ? parser->start : statements->base.location.start,
6408 .end = statements == NULL ? parser->end : statements->base.location.end
6412 .statements = statements
6421static pm_parentheses_node_t *
6422pm_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) {
6423 pm_parentheses_node_t *node = PM_NODE_ALLOC(parser, pm_parentheses_node_t);
6425 *node = (pm_parentheses_node_t) {
6427 .type = PM_PARENTHESES_NODE,
6429 .node_id = PM_NODE_IDENTIFY(parser),
6431 .start = opening->start,
6436 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6437 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6446static pm_pinned_expression_node_t *
6447pm_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) {
6448 pm_pinned_expression_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_expression_node_t);
6450 *node = (pm_pinned_expression_node_t) {
6452 .type = PM_PINNED_EXPRESSION_NODE,
6453 .node_id = PM_NODE_IDENTIFY(parser),
6455 .start = operator->start,
6459 .expression = expression,
6460 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6461 .lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen),
6462 .rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen)
6471static pm_pinned_variable_node_t *
6472pm_pinned_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
6473 pm_pinned_variable_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_variable_node_t);
6475 *node = (pm_pinned_variable_node_t) {
6477 .type = PM_PINNED_VARIABLE_NODE,
6478 .node_id = PM_NODE_IDENTIFY(parser),
6480 .start = operator->start,
6481 .end = variable->location.end
6484 .variable = variable,
6485 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6494static pm_post_execution_node_t *
6495pm_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) {
6496 pm_post_execution_node_t *node = PM_NODE_ALLOC(parser, pm_post_execution_node_t);
6498 *node = (pm_post_execution_node_t) {
6500 .type = PM_POST_EXECUTION_NODE,
6501 .node_id = PM_NODE_IDENTIFY(parser),
6503 .start = keyword->start,
6507 .statements = statements,
6508 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6509 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6510 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6519static pm_pre_execution_node_t *
6520pm_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) {
6521 pm_pre_execution_node_t *node = PM_NODE_ALLOC(parser, pm_pre_execution_node_t);
6523 *node = (pm_pre_execution_node_t) {
6525 .type = PM_PRE_EXECUTION_NODE,
6526 .node_id = PM_NODE_IDENTIFY(parser),
6528 .start = keyword->start,
6532 .statements = statements,
6533 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6534 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6535 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6544static pm_range_node_t *
6545pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
6546 pm_assert_value_expression(parser, left);
6547 pm_assert_value_expression(parser, right);
6549 pm_range_node_t *node = PM_NODE_ALLOC(parser, pm_range_node_t);
6550 pm_node_flags_t flags = 0;
6552 // Indicate that this node is an exclusive range if the operator is `...`.
6553 if (operator->type == PM_TOKEN_DOT_DOT_DOT || operator->type == PM_TOKEN_UDOT_DOT_DOT) {
6554 flags |= PM_RANGE_FLAGS_EXCLUDE_END;
6557 // Indicate that this node is a static literal (i.e., can be compiled with
6558 // a putobject in CRuby) if the left and right are implicit nil, explicit
6559 // nil, or integers.
6561 (left == NULL || PM_NODE_TYPE_P(left, PM_NIL_NODE) || PM_NODE_TYPE_P(left, PM_INTEGER_NODE)) &&
6562 (right == NULL || PM_NODE_TYPE_P(right, PM_NIL_NODE) || PM_NODE_TYPE_P(right, PM_INTEGER_NODE))
6564 flags |= PM_NODE_FLAG_STATIC_LITERAL;
6567 *node = (pm_range_node_t) {
6569 .type = PM_RANGE_NODE,
6571 .node_id = PM_NODE_IDENTIFY(parser),
6573 .start = (left == NULL ? operator->start : left->location.start),
6574 .end = (right == NULL ? operator->end : right->location.end)
6579 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6588static pm_redo_node_t *
6589pm_redo_node_create(pm_parser_t *parser, const pm_token_t *token) {
6590 assert(token->type == PM_TOKEN_KEYWORD_REDO);
6591 pm_redo_node_t *node = PM_NODE_ALLOC(parser, pm_redo_node_t);
6593 *node = (pm_redo_node_t) {{
6594 .type = PM_REDO_NODE,
6595 .node_id = PM_NODE_IDENTIFY(parser),
6596 .location = PM_LOCATION_TOKEN_VALUE(token)
6606static pm_regular_expression_node_t *
6607pm_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) {
6608 pm_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_regular_expression_node_t);
6610 *node = (pm_regular_expression_node_t) {
6612 .type = PM_REGULAR_EXPRESSION_NODE,
6613 .flags = pm_regular_expression_flags_create(parser, closing) | PM_NODE_FLAG_STATIC_LITERAL,
6614 .node_id = PM_NODE_IDENTIFY(parser),
6616 .start = MIN(opening->start, closing->start),
6617 .end = MAX(opening->end, closing->end)
6620 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6621 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
6622 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
6623 .unescaped = *unescaped
6632static inline pm_regular_expression_node_t *
6633pm_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6634 return pm_regular_expression_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6640static pm_required_parameter_node_t *
6641pm_required_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
6642 pm_required_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_parameter_node_t);
6644 *node = (pm_required_parameter_node_t) {
6646 .type = PM_REQUIRED_PARAMETER_NODE,
6647 .node_id = PM_NODE_IDENTIFY(parser),
6648 .location = PM_LOCATION_TOKEN_VALUE(token)
6650 .name = pm_parser_constant_id_token(parser, token)
6659static pm_rescue_modifier_node_t *
6660pm_rescue_modifier_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *keyword, pm_node_t *rescue_expression) {
6661 pm_rescue_modifier_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_modifier_node_t);
6663 *node = (pm_rescue_modifier_node_t) {
6665 .type = PM_RESCUE_MODIFIER_NODE,
6666 .node_id = PM_NODE_IDENTIFY(parser),
6668 .start = expression->location.start,
6669 .end = rescue_expression->location.end
6672 .expression = expression,
6673 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6674 .rescue_expression = rescue_expression
6683static pm_rescue_node_t *
6684pm_rescue_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
6685 pm_rescue_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_node_t);
6687 *node = (pm_rescue_node_t) {
6689 .type = PM_RESCUE_NODE,
6690 .node_id = PM_NODE_IDENTIFY(parser),
6691 .location = PM_LOCATION_TOKEN_VALUE(keyword)
6693 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6694 .operator_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
6695 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
6706pm_rescue_node_operator_set(pm_rescue_node_t *node, const pm_token_t *operator) {
6707 node->operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
6714pm_rescue_node_reference_set(pm_rescue_node_t *node, pm_node_t *reference) {
6715 node->reference = reference;
6716 node->base.location.end = reference->location.end;
6723pm_rescue_node_statements_set(pm_rescue_node_t *node, pm_statements_node_t *statements) {
6724 node->statements = statements;
6725 if (pm_statements_node_body_length(statements) > 0) {
6726 node->base.location.end = statements->base.location.end;
6734pm_rescue_node_subsequent_set(pm_rescue_node_t *node, pm_rescue_node_t *subsequent) {
6735 node->subsequent = subsequent;
6736 node->base.location.end = subsequent->base.location.end;
6743pm_rescue_node_exceptions_append(pm_rescue_node_t *node, pm_node_t *exception) {
6744 pm_node_list_append(&node->exceptions, exception);
6745 node->base.location.end = exception->location.end;
6751static pm_rest_parameter_node_t *
6752pm_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
6753 pm_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_rest_parameter_node_t);
6755 *node = (pm_rest_parameter_node_t) {
6757 .type = PM_REST_PARAMETER_NODE,
6758 .node_id = PM_NODE_IDENTIFY(parser),
6760 .start = operator->start,
6761 .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
6764 .name = pm_parser_optional_constant_id_token(parser, name),
6765 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
6766 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6775static pm_retry_node_t *
6776pm_retry_node_create(pm_parser_t *parser, const pm_token_t *token) {
6777 assert(token->type == PM_TOKEN_KEYWORD_RETRY);
6778 pm_retry_node_t *node = PM_NODE_ALLOC(parser, pm_retry_node_t);
6780 *node = (pm_retry_node_t) {{
6781 .type = PM_RETRY_NODE,
6782 .node_id = PM_NODE_IDENTIFY(parser),
6783 .location = PM_LOCATION_TOKEN_VALUE(token)
6792static pm_return_node_t *
6793pm_return_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6794 pm_return_node_t *node = PM_NODE_ALLOC(parser, pm_return_node_t);
6796 *node = (pm_return_node_t) {
6798 .type = PM_RETURN_NODE,
6799 .node_id = PM_NODE_IDENTIFY(parser),
6801 .start = keyword->start,
6802 .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
6805 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6806 .arguments = arguments
6815static pm_self_node_t *
6816pm_self_node_create(pm_parser_t *parser, const pm_token_t *token) {
6817 assert(token->type == PM_TOKEN_KEYWORD_SELF);
6818 pm_self_node_t *node = PM_NODE_ALLOC(parser, pm_self_node_t);
6820 *node = (pm_self_node_t) {{
6821 .type = PM_SELF_NODE,
6822 .node_id = PM_NODE_IDENTIFY(parser),
6823 .location = PM_LOCATION_TOKEN_VALUE(token)
6832static pm_shareable_constant_node_t *
6833pm_shareable_constant_node_create(pm_parser_t *parser, pm_node_t *write, pm_shareable_constant_value_t value) {
6834 pm_shareable_constant_node_t *node = PM_NODE_ALLOC(parser, pm_shareable_constant_node_t);
6836 *node = (pm_shareable_constant_node_t) {
6838 .type = PM_SHAREABLE_CONSTANT_NODE,
6839 .flags = (pm_node_flags_t) value,
6840 .node_id = PM_NODE_IDENTIFY(parser),
6841 .location = PM_LOCATION_NODE_VALUE(write)
6852static pm_singleton_class_node_t *
6853pm_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) {
6854 pm_singleton_class_node_t *node = PM_NODE_ALLOC(parser, pm_singleton_class_node_t);
6856 *node = (pm_singleton_class_node_t) {
6858 .type = PM_SINGLETON_CLASS_NODE,
6859 .node_id = PM_NODE_IDENTIFY(parser),
6861 .start = class_keyword->start,
6862 .end = end_keyword->end
6866 .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
6867 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6868 .expression = expression,
6870 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
6879static pm_source_encoding_node_t *
6880pm_source_encoding_node_create(pm_parser_t *parser, const pm_token_t *token) {
6881 assert(token->type == PM_TOKEN_KEYWORD___ENCODING__);
6882 pm_source_encoding_node_t *node = PM_NODE_ALLOC(parser, pm_source_encoding_node_t);
6884 *node = (pm_source_encoding_node_t) {{
6885 .type = PM_SOURCE_ENCODING_NODE,
6886 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6887 .node_id = PM_NODE_IDENTIFY(parser),
6888 .location = PM_LOCATION_TOKEN_VALUE(token)
6897static pm_source_file_node_t*
6898pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword) {
6899 pm_source_file_node_t *node = PM_NODE_ALLOC(parser, pm_source_file_node_t);
6900 assert(file_keyword->type == PM_TOKEN_KEYWORD___FILE__);
6902 pm_node_flags_t flags = 0;
6904 switch (parser->frozen_string_literal) {
6905 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6906 flags |= PM_STRING_FLAGS_MUTABLE;
6908 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6909 flags |= PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6913 *node = (pm_source_file_node_t) {
6915 .type = PM_SOURCE_FILE_NODE,
6917 .node_id = PM_NODE_IDENTIFY(parser),
6918 .location = PM_LOCATION_TOKEN_VALUE(file_keyword),
6920 .filepath = parser->filepath
6929static pm_source_line_node_t *
6930pm_source_line_node_create(pm_parser_t *parser, const pm_token_t *token) {
6931 assert(token->type == PM_TOKEN_KEYWORD___LINE__);
6932 pm_source_line_node_t *node = PM_NODE_ALLOC(parser, pm_source_line_node_t);
6934 *node = (pm_source_line_node_t) {{
6935 .type = PM_SOURCE_LINE_NODE,
6936 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6937 .node_id = PM_NODE_IDENTIFY(parser),
6938 .location = PM_LOCATION_TOKEN_VALUE(token)
6947static pm_splat_node_t *
6948pm_splat_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
6949 pm_splat_node_t *node = PM_NODE_ALLOC(parser, pm_splat_node_t);
6951 *node = (pm_splat_node_t) {
6953 .type = PM_SPLAT_NODE,
6954 .node_id = PM_NODE_IDENTIFY(parser),
6956 .start = operator->start,
6957 .end = (expression == NULL ? operator->end : expression->location.end)
6960 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6961 .expression = expression
6970static pm_statements_node_t *
6971pm_statements_node_create(pm_parser_t *parser) {
6972 pm_statements_node_t *node = PM_NODE_ALLOC(parser, pm_statements_node_t);
6974 *node = (pm_statements_node_t) {
6976 .type = PM_STATEMENTS_NODE,
6977 .node_id = PM_NODE_IDENTIFY(parser),
6978 .location = PM_LOCATION_NULL_VALUE(parser)
6990pm_statements_node_body_length(pm_statements_node_t *node) {
6991 return node && node->body.size;
6998pm_statements_node_location_set(pm_statements_node_t *node, const uint8_t *start, const uint8_t *end) {
6999 node->base.location = (pm_location_t) { .start = start, .end = end };
7007pm_statements_node_body_update(pm_statements_node_t *node, pm_node_t *statement) {
7008 if (pm_statements_node_body_length(node) == 0 || statement->location.start < node->base.location.start) {
7009 node->base.location.start = statement->location.start;
7012 if (statement->location.end > node->base.location.end) {
7013 node->base.location.end = statement->location.end;
7021pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline) {
7022 pm_statements_node_body_update(node, statement);
7024 if (node->body.size > 0) {
7025 const pm_node_t *previous = node->body.nodes[node->body.size - 1];
7027 switch (PM_NODE_TYPE(previous)) {
7032 case PM_RETURN_NODE:
7033 pm_parser_warn_node(parser, statement, PM_WARN_UNREACHABLE_STATEMENT);
7040 pm_node_list_append(&node->body, statement);
7041 if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
7048pm_statements_node_body_prepend(pm_statements_node_t *node, pm_node_t *statement) {
7049 pm_statements_node_body_update(node, statement);
7050 pm_node_list_prepend(&node->body, statement);
7051 pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
7057static inline pm_string_node_t *
7058pm_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) {
7059 pm_string_node_t *node = PM_NODE_ALLOC(parser, pm_string_node_t);
7060 pm_node_flags_t flags = 0;
7062 switch (parser->frozen_string_literal) {
7063 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
7064 flags = PM_STRING_FLAGS_MUTABLE;
7066 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
7067 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
7071 *node = (pm_string_node_t) {
7073 .type = PM_STRING_NODE,
7075 .node_id = PM_NODE_IDENTIFY(parser),
7077 .start = (opening->type == PM_TOKEN_NOT_PROVIDED ? content->start : opening->start),
7078 .end = (closing->type == PM_TOKEN_NOT_PROVIDED ? content->end : closing->end)
7081 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7082 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
7083 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7084 .unescaped = *string
7093static pm_string_node_t *
7094pm_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7095 return pm_string_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7102static pm_string_node_t *
7103pm_string_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7104 pm_string_node_t *node = pm_string_node_create_unescaped(parser, opening, content, closing, &parser->current_string);
7105 parser->current_string = PM_STRING_EMPTY;
7112static pm_super_node_t *
7113pm_super_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_t *arguments) {
7114 assert(keyword->type == PM_TOKEN_KEYWORD_SUPER);
7115 pm_super_node_t *node = PM_NODE_ALLOC(parser, pm_super_node_t);
7117 const uint8_t *end = pm_arguments_end(arguments);
7119 assert(false && "unreachable");
7122 *node = (pm_super_node_t) {
7124 .type = PM_SUPER_NODE,
7125 .node_id = PM_NODE_IDENTIFY(parser),
7127 .start = keyword->start,
7131 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7132 .lparen_loc = arguments->opening_loc,
7133 .arguments = arguments->arguments,
7134 .rparen_loc = arguments->closing_loc,
7135 .block = arguments->block
7146pm_ascii_only_p(const pm_string_t *contents) {
7147 const size_t length = pm_string_length(contents);
7148 const uint8_t *source = pm_string_source(contents);
7150 for (size_t index = 0; index < length; index++) {
7151 if (source[index] & 0x80) return false;
7161parse_symbol_encoding_validate_utf8(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
7162 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
7163 size_t width = pm_encoding_utf_8_char_width(cursor, end - cursor);
7166 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
7179parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
7180 const pm_encoding_t *encoding = parser->encoding;
7182 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
7183 size_t width = encoding->char_width(cursor, end - cursor);
7186 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
7203static inline pm_node_flags_t
7204parse_symbol_encoding(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents, bool validate) {
7205 if (parser->explicit_encoding != NULL) {
7206 // A Symbol may optionally have its encoding explicitly set. This will
7207 // happen if an escape sequence results in a non-ASCII code point.
7208 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7209 if (validate) parse_symbol_encoding_validate_utf8(parser, location, contents);
7210 return PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING;
7211 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7212 return PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING;
7213 } else if (validate) {
7214 parse_symbol_encoding_validate_other(parser, location, contents);
7216 } else if (pm_ascii_only_p(contents)) {
7217 // Ruby stipulates that all source files must use an ASCII-compatible
7218 // encoding. Thus, all symbols appearing in source are eligible for
7219 // "downgrading" to US-ASCII.
7220 return PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING;
7221 } else if (validate) {
7222 parse_symbol_encoding_validate_other(parser, location, contents);
7228static pm_node_flags_t
7229parse_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) {
7230 assert ((modifier == 'n' && modifier_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) ||
7231 (modifier == 'u' && modifier_encoding == PM_ENCODING_UTF_8_ENTRY) ||
7232 (modifier == 'e' && modifier_encoding == PM_ENCODING_EUC_JP_ENTRY) ||
7233 (modifier == 's' && modifier_encoding == PM_ENCODING_WINDOWS_31J_ENTRY));
7235 // There's special validation logic used if a string does not contain any character escape sequences.
7236 if (parser->explicit_encoding == NULL) {
7237 // If an ASCII-only string without character escapes is used with an encoding modifier, then resulting Regexp
7238 // has the modifier encoding, unless the ASCII-8BIT modifier is used, in which case the Regexp "downgrades" to
7239 // the US-ASCII encoding.
7241 return modifier == 'n' ? PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING : flags;
7244 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7246 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
7248 } else if (parser->encoding != modifier_encoding) {
7249 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_ENCODING_OPTION_MISMATCH, modifier, parser->encoding->name);
7251 if (modifier == 'n' && !ascii_only) {
7252 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));
7259 // 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.
7260 bool mixed_encoding = false;
7262 if (mixed_encoding) {
7263 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 != 'n' && parser->explicit_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) {
7265 // 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.
7266 bool valid_string_in_modifier_encoding = true;
7268 if (!valid_string_in_modifier_encoding) {
7269 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
7271 } else if (modifier != 'u' && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7272 // 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.
7273 if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
7274 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));
7278 // We've determined the encoding would naturally be EUC-JP and there is no need to force the encoding to anything else.
7288static pm_node_flags_t
7289parse_and_validate_regular_expression_encoding(pm_parser_t *parser, const pm_string_t *source, bool ascii_only, pm_node_flags_t flags) {
7290 // 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.
7291 bool valid_unicode_range = true;
7292 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY && !valid_unicode_range) {
7293 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));
7297 // US-ASCII strings do not admit multi-byte character literals. However, character escape sequences corresponding
7298 // to multi-byte characters are allowed.
7299 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY && parser->explicit_encoding == NULL && !ascii_only) {
7300 // CRuby will continue processing even though a SyntaxError has already been detected. It may result in the
7301 // following error message appearing twice. We do the same for compatibility.
7302 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
7313 if (flags & PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT) {
7314 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'n', PM_ENCODING_ASCII_8BIT_ENTRY);
7317 if (flags & PM_REGULAR_EXPRESSION_FLAGS_UTF_8) {
7318 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'u', PM_ENCODING_UTF_8_ENTRY);
7321 if (flags & PM_REGULAR_EXPRESSION_FLAGS_EUC_JP) {
7322 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'e', PM_ENCODING_EUC_JP_ENTRY);
7325 if (flags & PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J) {
7326 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 's', PM_ENCODING_WINDOWS_31J_ENTRY);
7329 // At this point no encoding modifiers will be present on the regular expression as they would have already
7330 // been processed. Ruby stipulates that all source files must use an ASCII-compatible encoding. Thus, all
7331 // regular expressions without an encoding modifier appearing in source are eligible for "downgrading" to US-ASCII.
7333 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING;
7336 // A Regexp may optionally have its encoding explicitly set via a character escape sequence in the source string
7337 // or by specifying a modifier.
7339 // NB: an explicitly set encoding is ignored by Ruby if the Regexp consists of only US ASCII code points.
7340 if (parser->explicit_encoding != NULL) {
7341 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7342 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING;
7343 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7344 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING;
7355static pm_symbol_node_t *
7356pm_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) {
7357 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7359 *node = (pm_symbol_node_t) {
7361 .type = PM_SYMBOL_NODE,
7362 .flags = PM_NODE_FLAG_STATIC_LITERAL | flags,
7363 .node_id = PM_NODE_IDENTIFY(parser),
7365 .start = (opening->type == PM_TOKEN_NOT_PROVIDED ? value->start : opening->start),
7366 .end = (closing->type == PM_TOKEN_NOT_PROVIDED ? value->end : closing->end)
7369 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7370 .value_loc = PM_LOCATION_TOKEN_VALUE(value),
7371 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7372 .unescaped = *unescaped
7381static inline pm_symbol_node_t *
7382pm_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
7383 return pm_symbol_node_create_unescaped(parser, opening, value, closing, &PM_STRING_EMPTY, 0);
7389static pm_symbol_node_t *
7390pm_symbol_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
7391 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));
7392 parser->current_string = PM_STRING_EMPTY;
7399static pm_symbol_node_t *
7400pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
7401 pm_symbol_node_t *node;
7403 switch (token->type) {
7404 case PM_TOKEN_LABEL: {
7405 pm_token_t opening = not_provided(parser);
7406 pm_token_t closing = { .type = PM_TOKEN_LABEL_END, .start = token->end - 1, .end = token->end };
7408 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end - 1 };
7409 node = pm_symbol_node_create(parser, &opening, &label, &closing);
7411 assert((label.end - label.start) >= 0);
7412 pm_string_shared_init(&node->unescaped, label.start, label.end);
7413 pm_node_flag_set((pm_node_t *) node, parse_symbol_encoding(parser, &label, &node->unescaped, false));
7417 case PM_TOKEN_MISSING: {
7418 pm_token_t opening = not_provided(parser);
7419 pm_token_t closing = not_provided(parser);
7421 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end };
7422 node = pm_symbol_node_create(parser, &opening, &label, &closing);
7426 assert(false && "unreachable");
7437static pm_symbol_node_t *
7438pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
7439 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7441 *node = (pm_symbol_node_t) {
7443 .type = PM_SYMBOL_NODE,
7444 .flags = PM_NODE_FLAG_STATIC_LITERAL | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING,
7445 .node_id = PM_NODE_IDENTIFY(parser),
7446 .location = PM_LOCATION_NULL_VALUE(parser)
7448 .value_loc = PM_LOCATION_NULL_VALUE(parser),
7452 pm_string_constant_init(&node->unescaped, content, strlen(content));
7460pm_symbol_node_label_p(pm_node_t *node) {
7461 const uint8_t *end = NULL;
7463 switch (PM_NODE_TYPE(node)) {
7464 case PM_SYMBOL_NODE:
7465 end = ((pm_symbol_node_t *) node)->closing_loc.end;
7467 case PM_INTERPOLATED_SYMBOL_NODE:
7468 end = ((pm_interpolated_symbol_node_t *) node)->closing_loc.end;
7474 return (end != NULL) && (end[-1] == ':');
7480static pm_symbol_node_t *
7481pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const pm_token_t *opening, const pm_token_t *closing) {
7482 pm_symbol_node_t *new_node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7484 *new_node = (pm_symbol_node_t) {
7486 .type = PM_SYMBOL_NODE,
7487 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7488 .node_id = PM_NODE_IDENTIFY(parser),
7490 .start = opening->start,
7494 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7495 .value_loc = node->content_loc,
7496 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7497 .unescaped = node->unescaped
7500 pm_token_t content = { .type = PM_TOKEN_IDENTIFIER, .start = node->content_loc.start, .end = node->content_loc.end };
7501 pm_node_flag_set((pm_node_t *) new_node, parse_symbol_encoding(parser, &content, &node->unescaped, true));
7503 // We are explicitly _not_ using pm_node_destroy here because we don't want
7504 // to trash the unescaped string. We could instead copy the string if we
7505 // know that it is owned, but we're taking the fast path for now.
7514static pm_string_node_t *
7515pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
7516 pm_string_node_t *new_node = PM_NODE_ALLOC(parser, pm_string_node_t);
7517 pm_node_flags_t flags = 0;
7519 switch (parser->frozen_string_literal) {
7520 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
7521 flags = PM_STRING_FLAGS_MUTABLE;
7523 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
7524 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
7528 *new_node = (pm_string_node_t) {
7530 .type = PM_STRING_NODE,
7532 .node_id = PM_NODE_IDENTIFY(parser),
7533 .location = node->base.location
7535 .opening_loc = node->opening_loc,
7536 .content_loc = node->value_loc,
7537 .closing_loc = node->closing_loc,
7538 .unescaped = node->unescaped
7541 // We are explicitly _not_ using pm_node_destroy here because we don't want
7542 // to trash the unescaped string. We could instead copy the string if we
7543 // know that it is owned, but we're taking the fast path for now.
7552static pm_true_node_t *
7553pm_true_node_create(pm_parser_t *parser, const pm_token_t *token) {
7554 assert(token->type == PM_TOKEN_KEYWORD_TRUE);
7555 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
7557 *node = (pm_true_node_t) {{
7558 .type = PM_TRUE_NODE,
7559 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7560 .node_id = PM_NODE_IDENTIFY(parser),
7561 .location = PM_LOCATION_TOKEN_VALUE(token)
7570static pm_true_node_t *
7571pm_true_node_synthesized_create(pm_parser_t *parser) {
7572 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
7574 *node = (pm_true_node_t) {{
7575 .type = PM_TRUE_NODE,
7576 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7577 .node_id = PM_NODE_IDENTIFY(parser),
7578 .location = { .start = parser->start, .end = parser->end }
7587static pm_undef_node_t *
7588pm_undef_node_create(pm_parser_t *parser, const pm_token_t *token) {
7589 assert(token->type == PM_TOKEN_KEYWORD_UNDEF);
7590 pm_undef_node_t *node = PM_NODE_ALLOC(parser, pm_undef_node_t);
7592 *node = (pm_undef_node_t) {
7594 .type = PM_UNDEF_NODE,
7595 .node_id = PM_NODE_IDENTIFY(parser),
7596 .location = PM_LOCATION_TOKEN_VALUE(token),
7598 .keyword_loc = PM_LOCATION_TOKEN_VALUE(token),
7609pm_undef_node_append(pm_undef_node_t *node, pm_node_t *name) {
7610 node->base.location.end = name->location.end;
7611 pm_node_list_append(&node->names, name);
7617static pm_unless_node_t *
7618pm_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) {
7619 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7620 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
7623 if (statements != NULL) {
7624 end = statements->base.location.end;
7626 end = predicate->location.end;
7629 *node = (pm_unless_node_t) {
7631 .type = PM_UNLESS_NODE,
7632 .flags = PM_NODE_FLAG_NEWLINE,
7633 .node_id = PM_NODE_IDENTIFY(parser),
7635 .start = keyword->start,
7639 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7640 .predicate = predicate,
7641 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
7642 .statements = statements,
7643 .else_clause = NULL,
7644 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
7653static pm_unless_node_t *
7654pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *unless_keyword, pm_node_t *predicate) {
7655 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7656 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
7658 pm_statements_node_t *statements = pm_statements_node_create(parser);
7659 pm_statements_node_body_append(parser, statements, statement, true);
7661 *node = (pm_unless_node_t) {
7663 .type = PM_UNLESS_NODE,
7664 .flags = PM_NODE_FLAG_NEWLINE,
7665 .node_id = PM_NODE_IDENTIFY(parser),
7667 .start = statement->location.start,
7668 .end = predicate->location.end
7671 .keyword_loc = PM_LOCATION_TOKEN_VALUE(unless_keyword),
7672 .predicate = predicate,
7673 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7674 .statements = statements,
7675 .else_clause = NULL,
7676 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
7683pm_unless_node_end_keyword_loc_set(pm_unless_node_t *node, const pm_token_t *end_keyword) {
7684 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
7685 node->base.location.end = end_keyword->end;
7694pm_loop_modifier_block_exits(pm_parser_t *parser, pm_statements_node_t *statements) {
7695 assert(parser->current_block_exits != NULL);
7697 // All of the block exits that we want to remove should be within the
7698 // statements, and since we are modifying the statements, we shouldn't have
7699 // to check the end location.
7700 const uint8_t *start = statements->base.location.start;
7702 for (size_t index = parser->current_block_exits->size; index > 0; index--) {
7703 pm_node_t *block_exit = parser->current_block_exits->nodes[index - 1];
7704 if (block_exit->location.start < start) break;
7706 // Implicitly remove from the list by lowering the size.
7707 parser->current_block_exits->size--;
7714static pm_until_node_t *
7715pm_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) {
7716 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
7717 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7719 *node = (pm_until_node_t) {
7721 .type = PM_UNTIL_NODE,
7723 .node_id = PM_NODE_IDENTIFY(parser),
7725 .start = keyword->start,
7726 .end = closing->end,
7729 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7730 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
7731 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7732 .predicate = predicate,
7733 .statements = statements
7742static pm_until_node_t *
7743pm_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) {
7744 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
7745 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7746 pm_loop_modifier_block_exits(parser, statements);
7748 *node = (pm_until_node_t) {
7750 .type = PM_UNTIL_NODE,
7752 .node_id = PM_NODE_IDENTIFY(parser),
7754 .start = statements->base.location.start,
7755 .end = predicate->location.end,
7758 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7759 .do_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7760 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7761 .predicate = predicate,
7762 .statements = statements
7771static pm_when_node_t *
7772pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
7773 pm_when_node_t *node = PM_NODE_ALLOC(parser, pm_when_node_t);
7775 *node = (pm_when_node_t) {
7777 .type = PM_WHEN_NODE,
7778 .node_id = PM_NODE_IDENTIFY(parser),
7780 .start = keyword->start,
7784 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7786 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7797pm_when_node_conditions_append(pm_when_node_t *node, pm_node_t *condition) {
7798 node->base.location.end = condition->location.end;
7799 pm_node_list_append(&node->conditions, condition);
7806pm_when_node_then_keyword_loc_set(pm_when_node_t *node, const pm_token_t *then_keyword) {
7807 node->base.location.end = then_keyword->end;
7808 node->then_keyword_loc = PM_LOCATION_TOKEN_VALUE(then_keyword);
7815pm_when_node_statements_set(pm_when_node_t *node, pm_statements_node_t *statements) {
7816 if (statements->base.location.end > node->base.location.end) {
7817 node->base.location.end = statements->base.location.end;
7820 node->statements = statements;
7826static pm_while_node_t *
7827pm_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) {
7828 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7829 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7831 *node = (pm_while_node_t) {
7833 .type = PM_WHILE_NODE,
7835 .node_id = PM_NODE_IDENTIFY(parser),
7837 .start = keyword->start,
7841 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7842 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
7843 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7844 .predicate = predicate,
7845 .statements = statements
7854static pm_while_node_t *
7855pm_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) {
7856 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7857 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7858 pm_loop_modifier_block_exits(parser, statements);
7860 *node = (pm_while_node_t) {
7862 .type = PM_WHILE_NODE,
7864 .node_id = PM_NODE_IDENTIFY(parser),
7866 .start = statements->base.location.start,
7867 .end = predicate->location.end
7870 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7871 .do_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7872 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7873 .predicate = predicate,
7874 .statements = statements
7883static pm_while_node_t *
7884pm_while_node_synthesized_create(pm_parser_t *parser, pm_node_t *predicate, pm_statements_node_t *statements) {
7885 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7887 *node = (pm_while_node_t) {
7889 .type = PM_WHILE_NODE,
7890 .node_id = PM_NODE_IDENTIFY(parser),
7891 .location = PM_LOCATION_NULL_VALUE(parser)
7893 .keyword_loc = PM_LOCATION_NULL_VALUE(parser),
7894 .do_keyword_loc = PM_LOCATION_NULL_VALUE(parser),
7895 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
7896 .predicate = predicate,
7897 .statements = statements
7907static pm_x_string_node_t *
7908pm_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) {
7909 pm_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_x_string_node_t);
7911 *node = (pm_x_string_node_t) {
7913 .type = PM_X_STRING_NODE,
7914 .flags = PM_STRING_FLAGS_FROZEN,
7915 .node_id = PM_NODE_IDENTIFY(parser),
7917 .start = opening->start,
7921 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
7922 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
7923 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
7924 .unescaped = *unescaped
7933static inline pm_x_string_node_t *
7934pm_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7935 return pm_xstring_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7941static pm_yield_node_t *
7942pm_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) {
7943 pm_yield_node_t *node = PM_NODE_ALLOC(parser, pm_yield_node_t);
7946 if (rparen_loc->start != NULL) {
7947 end = rparen_loc->end;
7948 } else if (arguments != NULL) {
7949 end = arguments->base.location.end;
7950 } else if (lparen_loc->start != NULL) {
7951 end = lparen_loc->end;
7956 *node = (pm_yield_node_t) {
7958 .type = PM_YIELD_NODE,
7959 .node_id = PM_NODE_IDENTIFY(parser),
7961 .start = keyword->start,
7965 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7966 .lparen_loc = *lparen_loc,
7967 .arguments = arguments,
7968 .rparen_loc = *rparen_loc
7975#undef PM_NODE_IDENTIFY
7982pm_parser_local_depth_constant_id(pm_parser_t *parser, pm_constant_id_t constant_id) {
7983 pm_scope_t *scope = parser->current_scope;
7986 while (scope != NULL) {
7987 if (pm_locals_find(&scope->locals, constant_id) != UINT32_MAX) return depth;
7988 if (scope->closed) break;
7990 scope = scope->previous;
8003pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
8004 return pm_parser_local_depth_constant_id(parser, pm_parser_constant_id_token(parser, token));
8011pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id, const uint8_t *start, const uint8_t *end, uint32_t reads) {
8012 pm_locals_write(&parser->current_scope->locals, constant_id, start, end, reads);
8018static pm_constant_id_t
8019pm_parser_local_add_location(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, uint32_t reads) {
8020 pm_constant_id_t constant_id = pm_parser_constant_id_location(parser, start, end);
8021 if (constant_id != 0) pm_parser_local_add(parser, constant_id, start, end, reads);
8028static inline pm_constant_id_t
8029pm_parser_local_add_token(pm_parser_t *parser, pm_token_t *token, uint32_t reads) {
8030 return pm_parser_local_add_location(parser, token->start, token->end, reads);
8036static pm_constant_id_t
8037pm_parser_local_add_owned(pm_parser_t *parser, uint8_t *start, size_t length) {
8038 pm_constant_id_t constant_id = pm_parser_constant_id_owned(parser, start, length);
8039 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
8046static pm_constant_id_t
8047pm_parser_local_add_constant(pm_parser_t *parser, const char *start, size_t length) {
8048 pm_constant_id_t constant_id = pm_parser_constant_id_constant(parser, start, length);
8049 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
8061pm_parser_parameter_name_check(pm_parser_t *parser, const pm_token_t *name) {
8062 // We want to check whether the parameter name is a numbered parameter or
8064 pm_refute_numbered_parameter(parser, name->start, name->end);
8066 // Otherwise we'll fetch the constant id for the parameter name and check
8067 // whether it's already in the current scope.
8068 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, name);
8070 if (pm_locals_find(&parser->current_scope->locals, constant_id) != UINT32_MAX) {
8071 // Add an error if the parameter doesn't start with _ and has been seen before
8072 if ((name->start < name->end) && (*name->start != '_')) {
8073 pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NAME_DUPLICATED);
8084pm_parser_scope_pop(pm_parser_t *parser) {
8085 pm_scope_t *scope = parser->current_scope;
8086 parser->current_scope = scope->previous;
8087 pm_locals_free(&scope->locals);
8088 pm_node_list_free(&scope->implicit_parameters);
8092/******************************************************************************/
8094/******************************************************************************/
8100pm_state_stack_push(pm_state_stack_t *stack, bool value) {
8101 *stack = (*stack << 1) | (value & 1);
8108pm_state_stack_pop(pm_state_stack_t *stack) {
8116pm_state_stack_p(const pm_state_stack_t *stack) {
8121pm_accepts_block_stack_push(pm_parser_t *parser, bool value) {
8122 // Use the negation of the value to prevent stack overflow.
8123 pm_state_stack_push(&parser->accepts_block_stack, !value);
8127pm_accepts_block_stack_pop(pm_parser_t *parser) {
8128 pm_state_stack_pop(&parser->accepts_block_stack);
8132pm_accepts_block_stack_p(pm_parser_t *parser) {
8133 return !pm_state_stack_p(&parser->accepts_block_stack);
8137pm_do_loop_stack_push(pm_parser_t *parser, bool value) {
8138 pm_state_stack_push(&parser->do_loop_stack, value);
8142pm_do_loop_stack_pop(pm_parser_t *parser) {
8143 pm_state_stack_pop(&parser->do_loop_stack);
8147pm_do_loop_stack_p(pm_parser_t *parser) {
8148 return pm_state_stack_p(&parser->do_loop_stack);
8151/******************************************************************************/
8152/* Lexer check helpers */
8153/******************************************************************************/
8159static inline uint8_t
8160peek_at(const pm_parser_t *parser, const uint8_t *cursor) {
8161 if (cursor < parser->end) {
8173static inline uint8_t
8174peek_offset(pm_parser_t *parser, ptrdiff_t offset) {
8175 return peek_at(parser, parser->current.end + offset);
8182static inline uint8_t
8183peek(const pm_parser_t *parser) {
8184 return peek_at(parser, parser->current.end);
8192match(pm_parser_t *parser, uint8_t value) {
8193 if (peek(parser) == value) {
8194 parser->current.end++;
8205match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
8206 if (peek_at(parser, cursor) == '\n') {
8209 if (peek_at(parser, cursor) == '\r' && peek_at(parser, cursor + 1) == '\n') {
8221match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
8222 return match_eol_at(parser, parser->current.end + offset);
8231match_eol(pm_parser_t *parser) {
8232 return match_eol_at(parser, parser->current.end);
8238static inline const uint8_t *
8239next_newline(const uint8_t *cursor, ptrdiff_t length) {
8240 assert(length >= 0);
8242 // Note that it's okay for us to use memchr here to look for \n because none
8243 // of the encodings that we support have \n as a component of a multi-byte
8245 return memchr(cursor, '\n', (size_t) length);
8252ambiguous_operator_p(const pm_parser_t *parser, bool space_seen) {
8253 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));
8261parser_lex_magic_comment_encoding_value(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
8262 const pm_encoding_t *encoding = pm_encoding_find(start, end);
8264 if (encoding != NULL) {
8265 if (parser->encoding != encoding) {
8266 parser->encoding = encoding;
8267 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
8270 parser->encoding_changed = (encoding != PM_ENCODING_UTF_8_ENTRY);
8282parser_lex_magic_comment_encoding(pm_parser_t *parser) {
8283 const uint8_t *cursor = parser->current.start + 1;
8284 const uint8_t *end = parser->current.end;
8286 bool separator = false;
8288 if (end - cursor <= 6) return;
8289 switch (cursor[6]) {
8290 case 'C': case 'c': cursor += 6; continue;
8291 case 'O': case 'o': cursor += 5; continue;
8292 case 'D': case 'd': cursor += 4; continue;
8293 case 'I': case 'i': cursor += 3; continue;
8294 case 'N': case 'n': cursor += 2; continue;
8295 case 'G': case 'g': cursor += 1; continue;
8302 if (pm_char_is_whitespace(*cursor)) break;
8305 if (pm_strncasecmp(cursor - 6, (const uint8_t *) "coding", 6) == 0) break;
8311 if (++cursor >= end) return;
8312 } while (pm_char_is_whitespace(*cursor));
8314 if (separator) break;
8315 if (*cursor != '=' && *cursor != ':') return;
8321 const uint8_t *value_start = cursor;
8322 while ((*cursor == '-' || *cursor == '_' || parser->encoding->alnum_char(cursor, 1)) && ++cursor < end);
8324 if (!parser_lex_magic_comment_encoding_value(parser, value_start, cursor)) {
8325 // If we were unable to parse the encoding value, then we've got an
8326 // issue because we didn't understand the encoding that the user was
8327 // trying to use. In this case we'll keep using the default encoding but
8328 // add an error to the parser to indicate an unsuccessful parse.
8329 pm_parser_err(parser, value_start, cursor, PM_ERR_INVALID_ENCODING_MAGIC_COMMENT);
8334 PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE,
8335 PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE,
8336 PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID
8337} pm_magic_comment_boolean_value_t;
8343static pm_magic_comment_boolean_value_t
8344parser_lex_magic_comment_boolean_value(const uint8_t *value_start, uint32_t value_length) {
8345 if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "true", 4) == 0) {
8346 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE;
8347 } else if (value_length == 5 && pm_strncasecmp(value_start, (const uint8_t *) "false", 5) == 0) {
8348 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE;
8350 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID;
8355pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
8356 return b == '\'' || b == '"' || b == ':' || b == ';';
8364static inline const uint8_t *
8365parser_lex_magic_comment_emacs_marker(
pm_parser_t *parser,
const uint8_t *cursor,
const uint8_t *end) {
8366 while ((cursor + 3 <= end) && (cursor = pm_memchr(cursor,
'-', (
size_t) (end - cursor), parser->
encoding_changed, parser->
encoding)) != NULL) {
8367 if (cursor + 3 <= end && cursor[1] ==
'*' && cursor[2] ==
'-') {
8386parser_lex_magic_comment(
pm_parser_t *parser,
bool semantic_token_seen) {
8389 const uint8_t *start = parser->
current.start + 1;
8390 const uint8_t *end = parser->
current.end;
8391 if (end - start <= 7)
return false;
8393 const uint8_t *cursor;
8394 bool indicator =
false;
8396 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
8399 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
8410 while (cursor < end) {
8411 while (cursor < end && (pm_char_is_magic_comment_key_delimiter(*cursor) || pm_char_is_whitespace(*cursor))) cursor++;
8413 const uint8_t *key_start = cursor;
8414 while (cursor < end && (!pm_char_is_magic_comment_key_delimiter(*cursor) && !pm_char_is_whitespace(*cursor))) cursor++;
8416 const uint8_t *key_end = cursor;
8417 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
8418 if (cursor == end)
break;
8420 if (*cursor ==
':') {
8423 if (!indicator)
return false;
8427 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
8428 if (cursor == end)
break;
8430 const uint8_t *value_start;
8431 const uint8_t *value_end;
8433 if (*cursor ==
'"') {
8434 value_start = ++cursor;
8435 for (; cursor < end && *cursor !=
'"'; cursor++) {
8436 if (*cursor ==
'\\' && (cursor + 1 < end)) cursor++;
8439 if (*cursor ==
'"') cursor++;
8441 value_start = cursor;
8442 while (cursor < end && *cursor !=
'"' && *cursor !=
';' && !pm_char_is_whitespace(*cursor)) cursor++;
8447 while (cursor < end && (*cursor ==
';' || pm_char_is_whitespace(*cursor))) cursor++;
8449 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
8450 if (cursor != end)
return false;
8456 const size_t key_length = (size_t) (key_end - key_start);
8460 pm_string_shared_init(&key, key_start, key_end);
8462 uint8_t *buffer =
xmalloc(key_length);
8463 if (buffer == NULL)
break;
8465 memcpy(buffer, key_start, key_length);
8466 buffer[dash - key_start] =
'_';
8468 while ((dash = pm_memchr(dash + 1,
'-', (
size_t) (key_end - dash - 1), parser->
encoding_changed, parser->
encoding)) != NULL) {
8469 buffer[dash - key_start] =
'_';
8472 pm_string_owned_init(&key, buffer, key_length);
8478 uint32_t value_length = (uint32_t) (value_end - value_start);
8484 (key_length == 8 && pm_strncasecmp(key_source, (
const uint8_t *)
"encoding", 8) == 0) ||
8485 (key_length == 6 && pm_strncasecmp(key_source, (
const uint8_t *)
"coding", 6) == 0)
8487 result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
8491 if (key_length == 11) {
8492 if (pm_strncasecmp(key_source, (
const uint8_t *)
"warn_indent", 11) == 0) {
8493 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
8494 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
8495 PM_PARSER_WARN_TOKEN_FORMAT(
8498 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8500 (
const char *) key_source,
8502 (
const char *) value_start
8505 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
8508 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
8513 }
else if (key_length == 21) {
8514 if (pm_strncasecmp(key_source, (
const uint8_t *)
"frozen_string_literal", 21) == 0) {
8517 if (semantic_token_seen) {
8518 pm_parser_warn_token(parser, &parser->
current, PM_WARN_IGNORED_FROZEN_STRING_LITERAL);
8520 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
8521 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
8522 PM_PARSER_WARN_TOKEN_FORMAT(
8525 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8527 (
const char *) key_source,
8529 (
const char *) value_start
8532 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
8535 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
8541 }
else if (key_length == 24) {
8542 if (pm_strncasecmp(key_source, (
const uint8_t *)
"shareable_constant_value", 24) == 0) {
8543 const uint8_t *cursor = parser->
current.start;
8544 while ((cursor > parser->
start) && ((cursor[-1] ==
' ') || (cursor[-1] ==
'\t'))) cursor--;
8546 if (!((cursor == parser->
start) || (cursor[-1] ==
'\n'))) {
8547 pm_parser_warn_token(parser, &parser->
current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
8548 }
else if (value_length == 4 && pm_strncasecmp(value_start, (
const uint8_t *)
"none", 4) == 0) {
8549 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
8550 }
else if (value_length == 7 && pm_strncasecmp(value_start, (
const uint8_t *)
"literal", 7) == 0) {
8551 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
8552 }
else if (value_length == 23 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_everything", 23) == 0) {
8553 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING);
8554 }
else if (value_length == 17 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_copy", 17) == 0) {
8555 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY);
8557 PM_PARSER_WARN_TOKEN_FORMAT(
8560 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8562 (
const char *) key_source,
8564 (
const char *) value_start
8592static const uint32_t context_terminators[] = {
8594 [
PM_CONTEXT_BEGIN] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8597 [
PM_CONTEXT_BEGIN_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8599 [
PM_CONTEXT_BLOCK_KEYWORDS] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
8602 [
PM_CONTEXT_BLOCK_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8603 [
PM_CONTEXT_CASE_WHEN] = (1 << PM_TOKEN_KEYWORD_WHEN) | (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_ELSE),
8604 [
PM_CONTEXT_CASE_IN] = (1 << PM_TOKEN_KEYWORD_IN) | (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_ELSE),
8605 [
PM_CONTEXT_CLASS] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
8608 [
PM_CONTEXT_CLASS_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8609 [
PM_CONTEXT_DEF] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
8612 [
PM_CONTEXT_DEF_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8617 [
PM_CONTEXT_ELSIF] = (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_ELSIF) | (1 << PM_TOKEN_KEYWORD_END),
8621 [
PM_CONTEXT_IF] = (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_ELSIF) | (1 << PM_TOKEN_KEYWORD_END),
8623 [
PM_CONTEXT_LAMBDA_DO_END] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
8626 [
PM_CONTEXT_LAMBDA_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8629 [
PM_CONTEXT_MODULE] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
8632 [
PM_CONTEXT_MODULE_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8636 [
PM_CONTEXT_PREDICATE] = (1 << PM_TOKEN_KEYWORD_THEN) | (1 << PM_TOKEN_NEWLINE) | (1 << PM_TOKEN_SEMICOLON),
8639 [
PM_CONTEXT_SCLASS] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
8642 [
PM_CONTEXT_SCLASS_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8644 [
PM_CONTEXT_UNLESS] = (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8651 return token->type < 32 && (context_terminators[context] & (1 << token->type));
8662 while (context_node != NULL) {
8663 if (context_terminator(context_node->
context, token))
return context_node->
context;
8664 context_node = context_node->
prev;
8673 if (context_node == NULL)
return false;
8698 while (context_node != NULL) {
8699 if (context_node->
context == context)
return true;
8700 context_node = context_node->
prev;
8710 while (context_node != NULL) {
8711 switch (context_node->
context) {
8732 context_node = context_node->
prev;
8747 assert(
false &&
"unreachable");
8804 assert(
false &&
"unreachable");
8813pm_strspn_number_validate(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const uint8_t *invalid) {
8814 if (invalid != NULL) {
8815 pm_diagnostic_id_t diag_id = (invalid == (
string + length - 1)) ? PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING : PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER;
8816 pm_parser_err(parser, invalid, invalid + 1, diag_id);
8821pm_strspn_binary_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8822 const uint8_t *invalid = NULL;
8823 size_t length = pm_strspn_binary_number(
string, parser->
end -
string, &invalid);
8824 pm_strspn_number_validate(parser,
string, length, invalid);
8829pm_strspn_octal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8830 const uint8_t *invalid = NULL;
8831 size_t length = pm_strspn_octal_number(
string, parser->
end -
string, &invalid);
8832 pm_strspn_number_validate(parser,
string, length, invalid);
8837pm_strspn_decimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8838 const uint8_t *invalid = NULL;
8839 size_t length = pm_strspn_decimal_number(
string, parser->
end -
string, &invalid);
8840 pm_strspn_number_validate(parser,
string, length, invalid);
8845pm_strspn_hexadecimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8846 const uint8_t *invalid = NULL;
8847 size_t length = pm_strspn_hexadecimal_number(
string, parser->
end -
string, &invalid);
8848 pm_strspn_number_validate(parser,
string, length, invalid);
8852static pm_token_type_t
8853lex_optional_float_suffix(
pm_parser_t *parser,
bool* seen_e) {
8854 pm_token_type_t
type = PM_TOKEN_INTEGER;
8858 if (peek(parser) ==
'.') {
8859 if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8861 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8862 type = PM_TOKEN_FLOAT;
8872 if ((peek(parser) ==
'e') || (peek(parser) ==
'E')) {
8873 if ((peek_offset(parser, 1) ==
'+') || (peek_offset(parser, 1) ==
'-')) {
8876 if (pm_char_is_decimal_digit(peek(parser))) {
8878 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8880 pm_parser_err_current(parser, PM_ERR_INVALID_FLOAT_EXPONENT);
8882 }
else if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8884 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8890 type = PM_TOKEN_FLOAT;
8896static pm_token_type_t
8897lex_numeric_prefix(
pm_parser_t *parser,
bool* seen_e) {
8898 pm_token_type_t
type = PM_TOKEN_INTEGER;
8901 if (peek_offset(parser, -1) ==
'0') {
8902 switch (*parser->
current.end) {
8907 if (pm_char_is_decimal_digit(peek(parser))) {
8908 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8911 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_DECIMAL);
8920 if (pm_char_is_binary_digit(peek(parser))) {
8921 parser->
current.end += pm_strspn_binary_number_validate(parser, parser->
current.end);
8924 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
8934 if (pm_char_is_octal_digit(peek(parser))) {
8935 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8938 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
8954 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8962 if (pm_char_is_hexadecimal_digit(peek(parser))) {
8963 parser->
current.end += pm_strspn_hexadecimal_number_validate(parser, parser->
current.end);
8966 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
8969 parser->
integer_base = PM_INTEGER_BASE_FLAGS_HEXADECIMAL;
8974 type = lex_optional_float_suffix(parser, seen_e);
8981 type = lex_optional_float_suffix(parser, seen_e);
8988 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8991 type = lex_optional_float_suffix(parser, seen_e);
8997 if (peek_offset(parser, 0) ==
'.' && pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8998 const uint8_t *fraction_start = parser->
current.end;
8999 const uint8_t *fraction_end = parser->
current.end + 2;
9000 fraction_end += pm_strspn_decimal_digit(fraction_end, parser->
end - fraction_end);
9001 pm_parser_err(parser, fraction_start, fraction_end, PM_ERR_INVALID_NUMBER_FRACTION);
9007static pm_token_type_t
9009 pm_token_type_t
type = PM_TOKEN_INTEGER;
9013 bool seen_e =
false;
9014 type = lex_numeric_prefix(parser, &seen_e);
9016 const uint8_t *end = parser->
current.end;
9017 pm_token_type_t suffix_type =
type;
9019 if (
type == PM_TOKEN_INTEGER) {
9020 if (match(parser,
'r')) {
9021 suffix_type = PM_TOKEN_INTEGER_RATIONAL;
9023 if (match(parser,
'i')) {
9024 suffix_type = PM_TOKEN_INTEGER_RATIONAL_IMAGINARY;
9026 }
else if (match(parser,
'i')) {
9027 suffix_type = PM_TOKEN_INTEGER_IMAGINARY;
9030 if (!seen_e && match(parser,
'r')) {
9031 suffix_type = PM_TOKEN_FLOAT_RATIONAL;
9033 if (match(parser,
'i')) {
9034 suffix_type = PM_TOKEN_FLOAT_RATIONAL_IMAGINARY;
9036 }
else if (match(parser,
'i')) {
9037 suffix_type = PM_TOKEN_FLOAT_IMAGINARY;
9041 const uint8_t b = peek(parser);
9042 if (b !=
'\0' && (b >= 0x80 || ((b >=
'a' && b <=
'z') || (b >=
'A' && b <=
'Z')) || b ==
'_')) {
9052static pm_token_type_t
9055 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
9056 return PM_TOKEN_GLOBAL_VARIABLE;
9061 bool allow_multiple =
true;
9063 switch (*parser->
current.end) {
9081 return PM_TOKEN_GLOBAL_VARIABLE;
9088 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_BACK_REFERENCE;
9094 if ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0) {
9097 }
while ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0);
9101 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
current, diag_id);
9104 return PM_TOKEN_GLOBAL_VARIABLE;
9117 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_NUMBERED_REFERENCE;
9121 allow_multiple =
false;
9126 if ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0) {
9129 }
while (allow_multiple && (width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0);
9130 }
else if (pm_char_is_whitespace(peek(parser))) {
9133 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
9139 PM_PARSER_ERR_FORMAT(parser, parser->
current.start, end, diag_id, (
int) (end - parser->
current.start), (
const char *) parser->
current.start);
9142 return PM_TOKEN_GLOBAL_VARIABLE;
9159static inline pm_token_type_t
9160lex_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) {
9161 if (memcmp(current_start, value, vlen) == 0) {
9164 if (parser->
lex_state & PM_LEX_STATE_FNAME) {
9165 lex_state_set(parser, PM_LEX_STATE_ENDFN);
9167 lex_state_set(parser, state);
9168 if (state == PM_LEX_STATE_BEG) {
9172 if ((modifier_type != PM_TOKEN_EOF) && !(last_state & (PM_LEX_STATE_BEG | PM_LEX_STATE_LABELED | PM_LEX_STATE_CLASS))) {
9173 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
9174 return modifier_type;
9181 return PM_TOKEN_EOF;
9184static pm_token_type_t
9185lex_identifier(
pm_parser_t *parser,
bool previous_command_start) {
9188 const uint8_t *end = parser->
end;
9189 const uint8_t *current_start = parser->
current.start;
9190 const uint8_t *current_end = parser->
current.end;
9193 if (encoding_changed) {
9194 while ((width = char_is_identifier(parser, current_end, end - current_end)) > 0) {
9195 current_end += width;
9198 while ((width = char_is_identifier_utf8(current_end, end - current_end)) > 0) {
9199 current_end += width;
9202 parser->
current.end = current_end;
9206 width = (size_t) (current_end - current_start);
9208 if (current_end < end) {
9209 if (((current_end + 1 >= end) || (current_end[1] !=
'=')) && (match(parser,
'!') || match(parser,
'?'))) {
9215 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
9216 (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')
9220 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
9221 (void) match(parser,
':');
9222 return PM_TOKEN_LABEL;
9225 if (parser->
lex_state != PM_LEX_STATE_DOT) {
9226 if (width == 8 && (lex_keyword(parser, current_start,
"defined?", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_DEFINED, PM_TOKEN_EOF) != PM_TOKEN_EOF)) {
9227 return PM_TOKEN_KEYWORD_DEFINED;
9231 return PM_TOKEN_METHOD_NAME;
9234 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,
'=')) {
9237 return PM_TOKEN_IDENTIFIER;
9241 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
9242 peek(parser) ==
':' && peek_offset(parser, 1) !=
':'
9246 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
9247 (void) match(parser,
':');
9248 return PM_TOKEN_LABEL;
9252 if (parser->
lex_state != PM_LEX_STATE_DOT) {
9253 pm_token_type_t
type;
9256 if (lex_keyword(parser, current_start,
"do", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_DO, PM_TOKEN_EOF) != PM_TOKEN_EOF) {
9257 if (pm_do_loop_stack_p(parser)) {
9258 return PM_TOKEN_KEYWORD_DO_LOOP;
9260 return PM_TOKEN_KEYWORD_DO;
9263 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;
9264 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;
9265 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;
9268 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;
9269 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;
9270 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;
9271 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;
9272 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;
9273 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;
9274 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;
9277 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;
9278 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;
9279 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;
9280 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;
9281 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;
9282 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;
9283 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;
9284 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;
9287 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;
9288 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;
9289 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;
9290 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;
9291 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;
9292 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;
9293 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;
9294 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;
9295 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;
9296 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;
9297 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;
9298 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;
9299 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;
9302 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;
9303 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;
9304 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;
9305 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;
9306 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;
9309 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;
9310 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;
9313 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;
9318 if (encoding_changed) {
9319 return parser->
encoding->
isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
9321 return pm_encoding_utf_8_isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
9347static pm_token_type_t
9348lex_interpolation(
pm_parser_t *parser,
const uint8_t *pound) {
9351 if (pound + 1 >= parser->
end) {
9352 parser->
current.end = pound + 1;
9353 return PM_TOKEN_STRING_CONTENT;
9362 if (pound + 2 >= parser->
end) {
9363 parser->
current.end = pound + 1;
9364 return PM_TOKEN_STRING_CONTENT;
9369 const uint8_t *variable = pound + 2;
9370 if (*variable ==
'@' && pound + 3 < parser->
end) variable++;
9372 if (char_is_identifier_start(parser, variable, parser->
end - variable)) {
9376 if (pound > parser->
current.start) {
9378 return PM_TOKEN_STRING_CONTENT;
9383 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
9384 parser->
current.end = pound + 1;
9385 return PM_TOKEN_EMBVAR;
9391 parser->
current.end = pound + 1;
9392 return PM_TOKEN_NOT_PROVIDED;
9397 if (pound + 2 >= parser->
end) {
9398 parser->
current.end = pound + 1;
9399 return PM_TOKEN_STRING_CONTENT;
9405 const uint8_t *check = pound + 2;
9407 if (pound[2] ==
'-') {
9408 if (pound + 3 >= parser->
end) {
9409 parser->
current.end = pound + 2;
9410 return PM_TOKEN_STRING_CONTENT;
9421 char_is_identifier_start(parser, check, parser->
end - check) ||
9422 (pound[2] !=
'-' && (pm_char_is_decimal_digit(pound[2]) || char_is_global_name_punctuation(pound[2])))
9427 if (pound > parser->
current.start) {
9429 return PM_TOKEN_STRING_CONTENT;
9434 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
9435 parser->
current.end = pound + 1;
9436 return PM_TOKEN_EMBVAR;
9441 parser->
current.end = pound + 1;
9442 return PM_TOKEN_NOT_PROVIDED;
9447 if (pound > parser->
current.start) {
9449 return PM_TOKEN_STRING_CONTENT;
9456 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBEXPR });
9457 parser->
current.end = pound + 2;
9459 pm_do_loop_stack_push(parser,
false);
9460 return PM_TOKEN_EMBEXPR_BEGIN;
9465 parser->
current.end = pound + 1;
9466 return PM_TOKEN_NOT_PROVIDED;
9470static const uint8_t PM_ESCAPE_FLAG_NONE = 0x0;
9471static const uint8_t PM_ESCAPE_FLAG_CONTROL = 0x1;
9472static const uint8_t PM_ESCAPE_FLAG_META = 0x2;
9473static const uint8_t PM_ESCAPE_FLAG_SINGLE = 0x4;
9474static const uint8_t PM_ESCAPE_FLAG_REGEXP = 0x8;
9479static const bool ascii_printable_chars[] = {
9480 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
9481 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9482 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9483 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9484 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9485 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
9486 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9487 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
9491char_is_ascii_printable(
const uint8_t b) {
9492 return (b < 0x80) && ascii_printable_chars[b];
9499static inline uint8_t
9500escape_hexadecimal_digit(
const uint8_t value) {
9501 return (uint8_t) ((value <=
'9') ? (value -
'0') : (value & 0x7) + 9);
9509static inline uint32_t
9510escape_unicode(
pm_parser_t *parser,
const uint8_t *
string,
size_t length) {
9512 for (
size_t index = 0; index < length; index++) {
9513 if (index != 0) value <<= 4;
9514 value |= escape_hexadecimal_digit(
string[index]);
9519 if (value >= 0xD800 && value <= 0xDFFF) {
9520 pm_parser_err(parser,
string,
string + length, PM_ERR_ESCAPE_INVALID_UNICODE);
9530static inline uint8_t
9531escape_byte(uint8_t value,
const uint8_t flags) {
9532 if (flags & PM_ESCAPE_FLAG_CONTROL) value &= 0x9f;
9533 if (flags & PM_ESCAPE_FLAG_META) value |= 0x80;
9541escape_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) {
9545 if (value >= 0x80 || flags & PM_ESCAPE_FLAG_SINGLE) {
9553 if (!pm_buffer_append_unicode_codepoint(buffer, value)) {
9554 pm_parser_err(parser, start, end, PM_ERR_ESCAPE_INVALID_UNICODE);
9555 pm_buffer_append_byte(buffer, 0xEF);
9556 pm_buffer_append_byte(buffer, 0xBF);
9557 pm_buffer_append_byte(buffer, 0xBD);
9569 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_MIXED_ENCODING, parser->
encoding->
name);
9575 pm_buffer_append_byte(buffer,
byte);
9595 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9596 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X",
byte);
9599 escape_write_byte_encoded(parser, buffer,
byte);
9611 width = pm_encoding_utf_8_char_width(parser->
current.end, parser->
end - parser->
current.end);
9615 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(*parser->
current.end++, flags));
9616 }
else if (width > 1) {
9618 pm_buffer_t *b = (flags & PM_ESCAPE_FLAG_REGEXP) ? regular_expression_buffer : buffer;
9619 pm_buffer_append_bytes(b, parser->
current.end, width);
9625 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9635escape_read_warn(
pm_parser_t *parser, uint8_t flags, uint8_t flag,
const char *
type) {
9636#define FLAG(value) ((value & PM_ESCAPE_FLAG_CONTROL) ? "\\C-" : (value & PM_ESCAPE_FLAG_META) ? "\\M-" : "")
9638 PM_PARSER_WARN_TOKEN_FORMAT(
9641 PM_WARN_INVALID_CHARACTER,
9655 uint8_t peeked = peek(parser);
9659 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\\', flags));
9664 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\'', flags));
9669 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\a', flags));
9674 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\b', flags));
9679 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\033', flags));
9684 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\f', flags));
9689 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\n', flags));
9694 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\r', flags));
9699 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
' ', flags));
9704 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\t', flags));
9709 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\v', flags));
9712 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': {
9713 uint8_t value = (uint8_t) (*parser->
current.end -
'0');
9716 if (pm_char_is_octal_digit(peek(parser))) {
9717 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
9720 if (pm_char_is_octal_digit(peek(parser))) {
9721 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
9726 value = escape_byte(value, flags);
9727 escape_write_byte(parser, buffer, regular_expression_buffer, flags, value);
9731 const uint8_t *start = parser->
current.end - 1;
9734 uint8_t
byte = peek(parser);
9736 if (pm_char_is_hexadecimal_digit(
byte)) {
9737 uint8_t value = escape_hexadecimal_digit(
byte);
9740 byte = peek(parser);
9741 if (pm_char_is_hexadecimal_digit(
byte)) {
9742 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(
byte));
9746 value = escape_byte(value, flags);
9747 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9748 if (flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) {
9749 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X", value);
9751 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9755 escape_write_byte_encoded(parser, buffer, value);
9757 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
9763 const uint8_t *start = parser->
current.end - 1;
9767 const uint8_t *start = parser->
current.end - 2;
9768 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9769 }
else if (peek(parser) ==
'{') {
9770 const uint8_t *unicode_codepoints_start = parser->
current.end - 2;
9775 if ((whitespace = pm_strspn_inline_whitespace(parser->
current.end, parser->
end - parser->
current.end)) > 0) {
9776 parser->
current.end += whitespace;
9777 }
else if (peek(parser) ==
'\\' && peek_offset(parser, 1) ==
'n') {
9788 const uint8_t *extra_codepoints_start = NULL;
9789 int codepoints_count = 0;
9792 const uint8_t *unicode_start = parser->
current.end;
9793 size_t hexadecimal_length = pm_strspn_hexadecimal_digit(parser->
current.end, parser->
end - parser->
current.end);
9795 if (hexadecimal_length > 6) {
9797 pm_parser_err(parser, unicode_start, unicode_start + hexadecimal_length, PM_ERR_ESCAPE_INVALID_UNICODE_LONG);
9798 }
else if (hexadecimal_length == 0) {
9801 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9805 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9807 pm_parser_err(parser, parser->
current.end, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE);
9808 pm_parser_err(parser, parser->
current.end, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9814 parser->
current.end += hexadecimal_length;
9816 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count == 2) {
9817 extra_codepoints_start = unicode_start;
9820 uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length);
9821 escape_write_unicode(parser, buffer, flags, unicode_start, parser->
current.end, value);
9828 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count > 1) {
9829 pm_parser_err(parser, extra_codepoints_start, parser->
current.end - 1, PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL);
9833 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_LIST, (
int) (parser->
current.end - start), start);
9834 }
else if (peek(parser) ==
'}') {
9837 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9841 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9843 pm_parser_err(parser, unicode_codepoints_start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9847 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9848 pm_buffer_append_bytes(regular_expression_buffer, unicode_codepoints_start, (
size_t) (parser->
current.end - unicode_codepoints_start));
9851 size_t length = pm_strspn_hexadecimal_digit(parser->
current.end, MIN(parser->
end - parser->
current.end, 4));
9854 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9855 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9857 const uint8_t *start = parser->
current.end - 2;
9858 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9860 }
else if (length == 4) {
9861 uint32_t value = escape_unicode(parser, parser->
current.end, 4);
9863 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9864 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end + 4 - start));
9867 escape_write_unicode(parser, buffer, flags, start, parser->
current.end + 4, value);
9870 parser->
current.end += length;
9872 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9876 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9878 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_UNICODE);
9887 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9888 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9892 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9896 uint8_t peeked = peek(parser);
9900 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9906 if (match(parser,
'u') || match(parser,
'U')) {
9907 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9911 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9915 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9916 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9920 escape_read_warn(parser, flags, 0,
"\\t");
9921 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9924 if (!char_is_ascii_printable(peeked)) {
9925 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9930 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9937 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9938 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9941 if (peek(parser) !=
'-') {
9943 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9949 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9953 uint8_t peeked = peek(parser);
9957 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9963 if (match(parser,
'u') || match(parser,
'U')) {
9964 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9968 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9972 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9973 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9977 escape_read_warn(parser, flags, 0,
"\\t");
9978 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9981 if (!char_is_ascii_printable(peeked)) {
9983 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9988 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9995 if (flags & PM_ESCAPE_FLAG_META) {
9996 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META_REPEAT);
9999 if (peek(parser) !=
'-') {
10001 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
10007 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
10011 uint8_t peeked = peek(parser);
10016 if (match(parser,
'u') || match(parser,
'U')) {
10017 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
10021 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_META);
10025 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_META,
"\\s");
10026 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10030 escape_read_warn(parser, flags & ((uint8_t) ~PM_ESCAPE_FLAG_CONTROL), PM_ESCAPE_FLAG_META,
"\\t");
10031 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10034 if (!char_is_ascii_printable(peeked)) {
10036 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
10041 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10046 if (peek_offset(parser, 1) ==
'\n') {
10048 escape_write_byte_encoded(parser, buffer, escape_byte(
'\n', flags));
10054 if ((flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) && !char_is_ascii_printable(peeked)) {
10056 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
10060 escape_write_escape_encoded(parser, buffer, regular_expression_buffer, flags);
10062 pm_parser_err_current(parser, PM_ERR_INVALID_ESCAPE_CHARACTER);
10094static pm_token_type_t
10096 if (lex_state_end_p(parser)) {
10097 lex_state_set(parser, PM_LEX_STATE_BEG);
10098 return PM_TOKEN_QUESTION_MARK;
10102 pm_parser_err_current(parser, PM_ERR_INCOMPLETE_QUESTION_MARK);
10104 return PM_TOKEN_CHARACTER_LITERAL;
10107 if (pm_char_is_whitespace(*parser->
current.end)) {
10108 lex_state_set(parser, PM_LEX_STATE_BEG);
10109 return PM_TOKEN_QUESTION_MARK;
10112 lex_state_set(parser, PM_LEX_STATE_BEG);
10114 if (match(parser,
'\\')) {
10115 lex_state_set(parser, PM_LEX_STATE_END);
10118 pm_buffer_init_capacity(&buffer, 3);
10120 escape_read(parser, &buffer, NULL, PM_ESCAPE_FLAG_SINGLE);
10123 return PM_TOKEN_CHARACTER_LITERAL;
10132 (parser->
current.end + encoding_width >= parser->
end) ||
10133 !char_is_identifier(parser, parser->
current.end + encoding_width, parser->
end - (parser->
current.end + encoding_width))
10136 lex_state_set(parser, PM_LEX_STATE_END);
10137 parser->
current.end += encoding_width;
10139 return PM_TOKEN_CHARACTER_LITERAL;
10143 return PM_TOKEN_QUESTION_MARK;
10150static pm_token_type_t
10152 pm_token_type_t
type = match(parser,
'@') ? PM_TOKEN_CLASS_VARIABLE : PM_TOKEN_INSTANCE_VARIABLE;
10153 const uint8_t *end = parser->
end;
10156 if ((width = char_is_identifier_start(parser, parser->
current.end, end - parser->
current.end)) > 0) {
10157 parser->
current.end += width;
10159 while ((width = char_is_identifier(parser, parser->
current.end, end - parser->
current.end)) > 0) {
10160 parser->
current.end += width;
10162 }
else if (parser->
current.end < end && pm_char_is_decimal_digit(*parser->
current.end)) {
10163 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE;
10165 diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS_3_3 : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE_3_3;
10169 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, diag_id, (
int) ((parser->
current.end + width) - parser->
current.start), (
const char *) parser->
current.start);
10171 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_CLASS_VARIABLE_BARE : PM_ERR_INSTANCE_VARIABLE_BARE;
10172 pm_parser_err_token(parser, &parser->
current, diag_id);
10178 lex_mode_pop(parser);
10200 if (comment == NULL)
return NULL;
10215static pm_token_type_t
10218 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10220 if (newline == NULL) {
10223 pm_newline_list_append(&parser->
newline_list, newline);
10224 parser->
current.end = newline + 1;
10227 parser->
current.type = PM_TOKEN_EMBDOC_BEGIN;
10228 parser_lex_callback(parser);
10231 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_EMBDOC);
10232 if (comment == NULL)
return PM_TOKEN_EOF;
10236 while (parser->
current.end + 4 <= parser->
end) {
10242 (memcmp(parser->
current.end,
"=end", 4) == 0) &&
10245 pm_char_is_whitespace(parser->
current.end[4]) ||
10246 (parser->
current.end[4] ==
'\0') ||
10247 (parser->
current.end[4] ==
'\004') ||
10248 (parser->
current.end[4] ==
'\032')
10251 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10253 if (newline == NULL) {
10256 pm_newline_list_append(&parser->
newline_list, newline);
10257 parser->
current.end = newline + 1;
10260 parser->
current.type = PM_TOKEN_EMBDOC_END;
10261 parser_lex_callback(parser);
10266 return PM_TOKEN_EMBDOC_END;
10271 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10273 if (newline == NULL) {
10276 pm_newline_list_append(&parser->
newline_list, newline);
10277 parser->
current.end = newline + 1;
10280 parser->
current.type = PM_TOKEN_EMBDOC_LINE;
10281 parser_lex_callback(parser);
10284 pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
10289 return PM_TOKEN_EOF;
10299 parser->
current.type = PM_TOKEN_IGNORED_NEWLINE;
10300 parser_lex_callback(parser);
10324 const uint8_t *cursor = parser->
current.end;
10326 while (cursor < parser->end && *cursor !=
'\n' && *cursor !=
'#') {
10327 if (!pm_char_is_inline_whitespace(*cursor++))
return false;
10390 pm_buffer_append_byte(&token_buffer->
buffer,
byte);
10401static inline size_t
10407 width = pm_encoding_utf_8_char_width(parser->
current.end, parser->
end - parser->
current.end);
10412 return (width == 0 ? 1 : width);
10420 size_t width = parser_char_width(parser);
10421 pm_buffer_append_bytes(&token_buffer->
buffer, parser->
current.end, width);
10422 parser->
current.end += width;
10427 size_t width = parser_char_width(parser);
10428 pm_buffer_append_bytes(&token_buffer->
base.
buffer, parser->
current.end, width);
10430 parser->
current.end += width;
10434pm_slice_ascii_only_p(
const uint8_t *value,
size_t length) {
10435 for (
size_t index = 0; index < length; index++) {
10436 if (value[index] & 0x80)
return false;
10471 if (token_buffer->
cursor == NULL) {
10474 pm_buffer_append_bytes(&token_buffer->
buffer, token_buffer->
cursor, (
size_t) (parser->
current.end - token_buffer->
cursor));
10475 pm_token_buffer_copy(parser, token_buffer);
10487 pm_regexp_token_buffer_copy(parser, token_buffer);
10491#define PM_TOKEN_BUFFER_DEFAULT_SIZE 16
10503 const uint8_t *start;
10504 if (token_buffer->
cursor == NULL) {
10505 pm_buffer_init_capacity(&token_buffer->
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10506 start = parser->
current.start;
10508 start = token_buffer->
cursor;
10511 const uint8_t *end = parser->
current.end - 1;
10512 assert(end >= start);
10513 pm_buffer_append_bytes(&token_buffer->
buffer, start, (
size_t) (end - start));
10515 token_buffer->
cursor = end;
10520 const uint8_t *start;
10522 pm_buffer_init_capacity(&token_buffer->
base.
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10523 pm_buffer_init_capacity(&token_buffer->
regexp_buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10524 start = parser->
current.start;
10529 const uint8_t *end = parser->
current.end - 1;
10530 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, (
size_t) (end - start));
10531 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, (
size_t) (end - start));
10536#undef PM_TOKEN_BUFFER_DEFAULT_SIZE
10542static inline size_t
10544 size_t whitespace = 0;
10547 case PM_HEREDOC_INDENT_NONE:
10552 case PM_HEREDOC_INDENT_DASH:
10554 *cursor += pm_strspn_inline_whitespace(*cursor, parser->
end - *cursor);
10556 case PM_HEREDOC_INDENT_TILDE:
10559 while (*cursor < parser->end && pm_char_is_inline_whitespace(**cursor)) {
10560 if (**cursor ==
'\t') {
10561 whitespace = (whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
10580 size_t eol_length = match_eol(parser);
10587 parser_flush_heredoc_end(parser);
10593 uint8_t delimiter = *parser->
current.end;
10597 if (eol_length == 2) {
10598 delimiter = *(parser->
current.end + 1);
10601 parser->
current.end += eol_length;
10605 return *parser->
current.end++;
10612#define LEX(token_type) parser->current.type = token_type; parser_lex_callback(parser); return
10631 bool lexed_comment =
false;
10639 case PM_LEX_DEFAULT:
10640 case PM_LEX_EMBEXPR:
10641 case PM_LEX_EMBVAR:
10657 bool space_seen =
false;
10661 bool chomping =
true;
10662 while (parser->
current.end < parser->
end && chomping) {
10663 switch (*parser->
current.end) {
10672 if (match_eol_offset(parser, 1)) {
10675 pm_parser_warn(parser, parser->
current.end, parser->
current.end + 1, PM_WARN_UNEXPECTED_CARRIAGE_RETURN);
10681 size_t eol_length = match_eol_offset(parser, 1);
10687 parser->
current.end += eol_length + 1;
10691 }
else if (pm_char_is_inline_whitespace(*parser->
current.end)) {
10724 switch (*parser->
current.end++) {
10732 const uint8_t *ending = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10733 parser->
current.end = ending == NULL ? parser->
end : ending;
10738 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_INLINE);
10741 if (ending) parser->
current.end++;
10742 parser->
current.type = PM_TOKEN_COMMENT;
10743 parser_lex_callback(parser);
10755 parser_lex_magic_comment_encoding(parser);
10759 lexed_comment =
true;
10765 size_t eol_length = match_eol_at(parser, parser->
current.end - 1);
10777 if (!lexed_comment) {
10778 parser->
current.end += eol_length - 1;
10787 parser_flush_heredoc_end(parser);
10792 switch (lex_state_ignored_p(parser)) {
10793 case PM_IGNORED_NEWLINE_NONE:
10795 case PM_IGNORED_NEWLINE_PATTERN:
10797 if (!lexed_comment) parser_lex_ignored_newline(parser);
10798 lex_state_set(parser, PM_LEX_STATE_BEG);
10800 parser->
current.type = PM_TOKEN_NEWLINE;
10804 case PM_IGNORED_NEWLINE_ALL:
10805 if (!lexed_comment) parser_lex_ignored_newline(parser);
10806 lexed_comment =
false;
10807 goto lex_next_token;
10815 next_content += pm_strspn_inline_whitespace(next_content, parser->
end - next_content);
10817 if (next_content < parser->end) {
10823 if (next_content[0] ==
'#') {
10825 const uint8_t *following = next_newline(next_content, parser->
end - next_content);
10827 while (following && (following + 1 < parser->
end)) {
10829 following += pm_strspn_inline_whitespace(following, parser->
end - following);
10833 if (peek_at(parser, following) !=
'#')
break;
10837 following = next_newline(following, parser->
end - following);
10842 if (lex_state_ignored_p(parser)) {
10843 if (!lexed_comment) parser_lex_ignored_newline(parser);
10844 lexed_comment =
false;
10845 goto lex_next_token;
10851 (peek_at(parser, following) ==
'.') ||
10852 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'.')
10854 if (!lexed_comment) parser_lex_ignored_newline(parser);
10855 lexed_comment =
false;
10856 goto lex_next_token;
10866 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'&') ||
10867 (peek_at(parser, following) ==
'|' && peek_at(parser, following + 1) ==
'|') ||
10868 (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))) ||
10869 (peek_at(parser, following) ==
'o' && peek_at(parser, following + 1) ==
'r' && !char_is_identifier(parser, following + 2, parser->
end - (following + 2)))
10872 if (!lexed_comment) parser_lex_ignored_newline(parser);
10873 lexed_comment =
false;
10874 goto lex_next_token;
10880 if (next_content[0] ==
'.') {
10884 if (peek_at(parser, next_content + 1) ==
'.') {
10885 if (!lexed_comment) parser_lex_ignored_newline(parser);
10886 lex_state_set(parser, PM_LEX_STATE_BEG);
10888 parser->
current.type = PM_TOKEN_NEWLINE;
10892 if (!lexed_comment) parser_lex_ignored_newline(parser);
10893 lex_state_set(parser, PM_LEX_STATE_DOT);
10894 parser->
current.start = next_content;
10895 parser->
current.end = next_content + 1;
10902 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'.') {
10903 if (!lexed_comment) parser_lex_ignored_newline(parser);
10904 lex_state_set(parser, PM_LEX_STATE_DOT);
10905 parser->
current.start = next_content;
10906 parser->
current.end = next_content + 2;
10908 LEX(PM_TOKEN_AMPERSAND_DOT);
10914 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'&') {
10915 if (!lexed_comment) parser_lex_ignored_newline(parser);
10916 lex_state_set(parser, PM_LEX_STATE_BEG);
10917 parser->
current.start = next_content;
10918 parser->
current.end = next_content + 2;
10920 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
10925 if (peek_at(parser, next_content) ==
'|' && peek_at(parser, next_content + 1) ==
'|') {
10926 if (!lexed_comment) parser_lex_ignored_newline(parser);
10927 lex_state_set(parser, PM_LEX_STATE_BEG);
10928 parser->
current.start = next_content;
10929 parser->
current.end = next_content + 2;
10931 LEX(PM_TOKEN_PIPE_PIPE);
10937 peek_at(parser, next_content) ==
'a' &&
10938 peek_at(parser, next_content + 1) ==
'n' &&
10939 peek_at(parser, next_content + 2) ==
'd' &&
10940 !char_is_identifier(parser, next_content + 3, parser->
end - (next_content + 3))
10942 if (!lexed_comment) parser_lex_ignored_newline(parser);
10943 lex_state_set(parser, PM_LEX_STATE_BEG);
10944 parser->
current.start = next_content;
10945 parser->
current.end = next_content + 3;
10948 LEX(PM_TOKEN_KEYWORD_AND);
10954 peek_at(parser, next_content) ==
'o' &&
10955 peek_at(parser, next_content + 1) ==
'r' &&
10956 !char_is_identifier(parser, next_content + 2, parser->
end - (next_content + 2))
10958 if (!lexed_comment) parser_lex_ignored_newline(parser);
10959 lex_state_set(parser, PM_LEX_STATE_BEG);
10960 parser->
current.start = next_content;
10961 parser->
current.end = next_content + 2;
10964 LEX(PM_TOKEN_KEYWORD_OR);
10971 lex_state_set(parser, PM_LEX_STATE_BEG);
10973 parser->
current.type = PM_TOKEN_NEWLINE;
10974 if (!lexed_comment) parser_lex_callback(parser);
10984 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10985 LEX(PM_TOKEN_COMMA);
10989 pm_token_type_t
type = PM_TOKEN_PARENTHESIS_LEFT;
10991 if (space_seen && (lex_state_arg_p(parser) || parser->
lex_state == (PM_LEX_STATE_END | PM_LEX_STATE_LABEL))) {
10992 type = PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES;
10996 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10997 pm_do_loop_stack_push(parser,
false);
11004 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11005 pm_do_loop_stack_pop(parser);
11006 LEX(PM_TOKEN_PARENTHESIS_RIGHT);
11010 lex_state_set(parser, PM_LEX_STATE_BEG);
11012 LEX(PM_TOKEN_SEMICOLON);
11017 pm_token_type_t
type = PM_TOKEN_BRACKET_LEFT;
11019 if (lex_state_operator_p(parser)) {
11020 if (match(parser,
']')) {
11022 lex_state_set(parser, PM_LEX_STATE_ARG);
11023 LEX(match(parser,
'=') ? PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL : PM_TOKEN_BRACKET_LEFT_RIGHT);
11026 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABEL);
11030 if (lex_state_beg_p(parser) || (lex_state_arg_p(parser) && (space_seen || lex_state_p(parser, PM_LEX_STATE_LABELED)))) {
11031 type = PM_TOKEN_BRACKET_LEFT_ARRAY;
11034 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
11035 pm_do_loop_stack_push(parser,
false);
11041 lex_state_set(parser, PM_LEX_STATE_END);
11042 pm_do_loop_stack_pop(parser);
11043 LEX(PM_TOKEN_BRACKET_RIGHT);
11047 pm_token_type_t
type = PM_TOKEN_BRACE_LEFT;
11052 lex_state_set(parser, PM_LEX_STATE_BEG);
11053 type = PM_TOKEN_LAMBDA_BEGIN;
11054 }
else if (lex_state_p(parser, PM_LEX_STATE_LABELED)) {
11056 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
11057 }
else if (lex_state_p(parser, PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_END | PM_LEX_STATE_ENDFN)) {
11060 lex_state_set(parser, PM_LEX_STATE_BEG);
11061 }
else if (lex_state_p(parser, PM_LEX_STATE_ENDARG)) {
11064 lex_state_set(parser, PM_LEX_STATE_BEG);
11067 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
11072 pm_do_loop_stack_push(parser,
false);
11080 pm_do_loop_stack_pop(parser);
11083 lex_mode_pop(parser);
11084 LEX(PM_TOKEN_EMBEXPR_END);
11088 lex_state_set(parser, PM_LEX_STATE_END);
11089 LEX(PM_TOKEN_BRACE_RIGHT);
11093 if (match(parser,
'*')) {
11094 if (match(parser,
'=')) {
11095 lex_state_set(parser, PM_LEX_STATE_BEG);
11096 LEX(PM_TOKEN_STAR_STAR_EQUAL);
11099 pm_token_type_t
type = PM_TOKEN_STAR_STAR;
11101 if (lex_state_spcarg_p(parser, space_seen)) {
11102 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR_STAR);
11103 type = PM_TOKEN_USTAR_STAR;
11104 }
else if (lex_state_beg_p(parser)) {
11105 type = PM_TOKEN_USTAR_STAR;
11106 }
else if (ambiguous_operator_p(parser, space_seen)) {
11107 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"**",
"argument prefix");
11110 if (lex_state_operator_p(parser)) {
11111 lex_state_set(parser, PM_LEX_STATE_ARG);
11113 lex_state_set(parser, PM_LEX_STATE_BEG);
11119 if (match(parser,
'=')) {
11120 lex_state_set(parser, PM_LEX_STATE_BEG);
11121 LEX(PM_TOKEN_STAR_EQUAL);
11124 pm_token_type_t
type = PM_TOKEN_STAR;
11126 if (lex_state_spcarg_p(parser, space_seen)) {
11127 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR);
11128 type = PM_TOKEN_USTAR;
11129 }
else if (lex_state_beg_p(parser)) {
11130 type = PM_TOKEN_USTAR;
11131 }
else if (ambiguous_operator_p(parser, space_seen)) {
11132 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"*",
"argument prefix");
11135 if (lex_state_operator_p(parser)) {
11136 lex_state_set(parser, PM_LEX_STATE_ARG);
11138 lex_state_set(parser, PM_LEX_STATE_BEG);
11146 if (lex_state_operator_p(parser)) {
11147 lex_state_set(parser, PM_LEX_STATE_ARG);
11148 if (match(parser,
'@')) {
11149 LEX(PM_TOKEN_BANG);
11152 lex_state_set(parser, PM_LEX_STATE_BEG);
11155 if (match(parser,
'=')) {
11156 LEX(PM_TOKEN_BANG_EQUAL);
11159 if (match(parser,
'~')) {
11160 LEX(PM_TOKEN_BANG_TILDE);
11163 LEX(PM_TOKEN_BANG);
11168 current_token_starts_line(parser) &&
11170 memcmp(parser->
current.end,
"begin", 5) == 0 &&
11171 (pm_char_is_whitespace(peek_offset(parser, 5)) || (peek_offset(parser, 5) ==
'\0'))
11173 pm_token_type_t
type = lex_embdoc(parser);
11174 if (
type == PM_TOKEN_EOF) {
11178 goto lex_next_token;
11181 if (lex_state_operator_p(parser)) {
11182 lex_state_set(parser, PM_LEX_STATE_ARG);
11184 lex_state_set(parser, PM_LEX_STATE_BEG);
11187 if (match(parser,
'>')) {
11188 LEX(PM_TOKEN_EQUAL_GREATER);
11191 if (match(parser,
'~')) {
11192 LEX(PM_TOKEN_EQUAL_TILDE);
11195 if (match(parser,
'=')) {
11196 LEX(match(parser,
'=') ? PM_TOKEN_EQUAL_EQUAL_EQUAL : PM_TOKEN_EQUAL_EQUAL);
11199 LEX(PM_TOKEN_EQUAL);
11203 if (match(parser,
'<')) {
11205 !lex_state_p(parser, PM_LEX_STATE_DOT | PM_LEX_STATE_CLASS) &&
11206 !lex_state_end_p(parser) &&
11207 (!lex_state_p(parser, PM_LEX_STATE_ARG_ANY) || lex_state_p(parser, PM_LEX_STATE_LABELED) || space_seen)
11209 const uint8_t *end = parser->
current.end;
11214 if (match(parser,
'-')) {
11215 indent = PM_HEREDOC_INDENT_DASH;
11217 else if (match(parser,
'~')) {
11218 indent = PM_HEREDOC_INDENT_TILDE;
11221 if (match(parser,
'`')) {
11222 quote = PM_HEREDOC_QUOTE_BACKTICK;
11224 else if (match(parser,
'"')) {
11225 quote = PM_HEREDOC_QUOTE_DOUBLE;
11227 else if (match(parser,
'\'')) {
11228 quote = PM_HEREDOC_QUOTE_SINGLE;
11231 const uint8_t *ident_start = parser->
current.end;
11236 }
else if (quote == PM_HEREDOC_QUOTE_NONE && (width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) == 0) {
11239 if (quote == PM_HEREDOC_QUOTE_NONE) {
11240 parser->
current.end += width;
11242 while ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end))) {
11243 parser->
current.end += width;
11249 if (*parser->
current.end ==
'\r' || *parser->
current.end ==
'\n')
break;
11254 size_t ident_length = (size_t) (parser->
current.end - ident_start);
11255 bool ident_error =
false;
11257 if (quote != PM_HEREDOC_QUOTE_NONE && !match(parser, (uint8_t) quote)) {
11258 pm_parser_err(parser, ident_start, ident_start + ident_length, PM_ERR_HEREDOC_IDENTIFIER);
11259 ident_error =
true;
11264 .mode = PM_LEX_HEREDOC,
11267 .ident_start = ident_start,
11268 .ident_length = ident_length,
11272 .next_start = parser->
current.end,
11274 .line_continuation =
false
11279 const uint8_t *body_start = next_newline(parser->
current.end, parser->
end - parser->
current.end);
11281 if (body_start == NULL) {
11286 if (!ident_error) pm_parser_err_heredoc_term(parser, ident_start, ident_length);
11287 body_start = parser->
end;
11291 pm_newline_list_append(&parser->
newline_list, body_start);
11300 LEX(PM_TOKEN_HEREDOC_START);
11304 if (match(parser,
'=')) {
11305 lex_state_set(parser, PM_LEX_STATE_BEG);
11306 LEX(PM_TOKEN_LESS_LESS_EQUAL);
11309 if (ambiguous_operator_p(parser, space_seen)) {
11310 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"<<",
"here document");
11313 if (lex_state_operator_p(parser)) {
11314 lex_state_set(parser, PM_LEX_STATE_ARG);
11316 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
11317 lex_state_set(parser, PM_LEX_STATE_BEG);
11320 LEX(PM_TOKEN_LESS_LESS);
11323 if (lex_state_operator_p(parser)) {
11324 lex_state_set(parser, PM_LEX_STATE_ARG);
11326 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
11327 lex_state_set(parser, PM_LEX_STATE_BEG);
11330 if (match(parser,
'=')) {
11331 if (match(parser,
'>')) {
11332 LEX(PM_TOKEN_LESS_EQUAL_GREATER);
11335 LEX(PM_TOKEN_LESS_EQUAL);
11338 LEX(PM_TOKEN_LESS);
11342 if (match(parser,
'>')) {
11343 if (lex_state_operator_p(parser)) {
11344 lex_state_set(parser, PM_LEX_STATE_ARG);
11346 lex_state_set(parser, PM_LEX_STATE_BEG);
11348 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_GREATER_EQUAL : PM_TOKEN_GREATER_GREATER);
11351 if (lex_state_operator_p(parser)) {
11352 lex_state_set(parser, PM_LEX_STATE_ARG);
11354 lex_state_set(parser, PM_LEX_STATE_BEG);
11357 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_EQUAL : PM_TOKEN_GREATER);
11361 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
11362 lex_mode_push_string(parser,
true, label_allowed,
'\0',
'"');
11363 LEX(PM_TOKEN_STRING_BEGIN);
11368 if (lex_state_p(parser, PM_LEX_STATE_FNAME)) {
11369 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11370 LEX(PM_TOKEN_BACKTICK);
11373 if (lex_state_p(parser, PM_LEX_STATE_DOT)) {
11374 if (previous_command_start) {
11375 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11377 lex_state_set(parser, PM_LEX_STATE_ARG);
11380 LEX(PM_TOKEN_BACKTICK);
11383 lex_mode_push_string(parser,
true,
false,
'\0',
'`');
11384 LEX(PM_TOKEN_BACKTICK);
11389 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
11390 lex_mode_push_string(parser,
false, label_allowed,
'\0',
'\'');
11391 LEX(PM_TOKEN_STRING_BEGIN);
11396 LEX(lex_question_mark(parser));
11400 if (match(parser,
'&')) {
11401 lex_state_set(parser, PM_LEX_STATE_BEG);
11403 if (match(parser,
'=')) {
11404 LEX(PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
11407 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
11410 if (match(parser,
'=')) {
11411 lex_state_set(parser, PM_LEX_STATE_BEG);
11412 LEX(PM_TOKEN_AMPERSAND_EQUAL);
11415 if (match(parser,
'.')) {
11416 lex_state_set(parser, PM_LEX_STATE_DOT);
11417 LEX(PM_TOKEN_AMPERSAND_DOT);
11420 pm_token_type_t
type = PM_TOKEN_AMPERSAND;
11421 if (lex_state_spcarg_p(parser, space_seen)) {
11422 if ((peek(parser) !=
':') || (peek_offset(parser, 1) ==
'\0')) {
11423 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
11425 const uint8_t delim = peek_offset(parser, 1);
11427 if ((delim !=
'\'') && (delim !=
'"') && !char_is_identifier(parser, parser->
current.end + 1, parser->
end - (parser->
current.end + 1))) {
11428 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
11432 type = PM_TOKEN_UAMPERSAND;
11433 }
else if (lex_state_beg_p(parser)) {
11434 type = PM_TOKEN_UAMPERSAND;
11435 }
else if (ambiguous_operator_p(parser, space_seen)) {
11436 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"&",
"argument prefix");
11439 if (lex_state_operator_p(parser)) {
11440 lex_state_set(parser, PM_LEX_STATE_ARG);
11442 lex_state_set(parser, PM_LEX_STATE_BEG);
11450 if (match(parser,
'|')) {
11451 if (match(parser,
'=')) {
11452 lex_state_set(parser, PM_LEX_STATE_BEG);
11453 LEX(PM_TOKEN_PIPE_PIPE_EQUAL);
11456 if (lex_state_p(parser, PM_LEX_STATE_BEG)) {
11458 LEX(PM_TOKEN_PIPE);
11461 lex_state_set(parser, PM_LEX_STATE_BEG);
11462 LEX(PM_TOKEN_PIPE_PIPE);
11465 if (match(parser,
'=')) {
11466 lex_state_set(parser, PM_LEX_STATE_BEG);
11467 LEX(PM_TOKEN_PIPE_EQUAL);
11470 if (lex_state_operator_p(parser)) {
11471 lex_state_set(parser, PM_LEX_STATE_ARG);
11473 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
11476 LEX(PM_TOKEN_PIPE);
11480 if (lex_state_operator_p(parser)) {
11481 lex_state_set(parser, PM_LEX_STATE_ARG);
11483 if (match(parser,
'@')) {
11484 LEX(PM_TOKEN_UPLUS);
11487 LEX(PM_TOKEN_PLUS);
11490 if (match(parser,
'=')) {
11491 lex_state_set(parser, PM_LEX_STATE_BEG);
11492 LEX(PM_TOKEN_PLUS_EQUAL);
11496 lex_state_beg_p(parser) ||
11497 (lex_state_spcarg_p(parser, space_seen) ? (pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS),
true) : false)
11499 lex_state_set(parser, PM_LEX_STATE_BEG);
11501 if (pm_char_is_decimal_digit(peek(parser))) {
11503 pm_token_type_t
type = lex_numeric(parser);
11504 lex_state_set(parser, PM_LEX_STATE_END);
11508 LEX(PM_TOKEN_UPLUS);
11511 if (ambiguous_operator_p(parser, space_seen)) {
11512 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"+",
"unary operator");
11515 lex_state_set(parser, PM_LEX_STATE_BEG);
11516 LEX(PM_TOKEN_PLUS);
11521 if (lex_state_operator_p(parser)) {
11522 lex_state_set(parser, PM_LEX_STATE_ARG);
11524 if (match(parser,
'@')) {
11525 LEX(PM_TOKEN_UMINUS);
11528 LEX(PM_TOKEN_MINUS);
11531 if (match(parser,
'=')) {
11532 lex_state_set(parser, PM_LEX_STATE_BEG);
11533 LEX(PM_TOKEN_MINUS_EQUAL);
11536 if (match(parser,
'>')) {
11537 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11538 LEX(PM_TOKEN_MINUS_GREATER);
11541 bool spcarg = lex_state_spcarg_p(parser, space_seen);
11542 bool is_beg = lex_state_beg_p(parser);
11543 if (!is_beg && spcarg) {
11544 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS);
11547 if (is_beg || spcarg) {
11548 lex_state_set(parser, PM_LEX_STATE_BEG);
11549 LEX(pm_char_is_decimal_digit(peek(parser)) ? PM_TOKEN_UMINUS_NUM : PM_TOKEN_UMINUS);
11552 if (ambiguous_operator_p(parser, space_seen)) {
11553 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"-",
"unary operator");
11556 lex_state_set(parser, PM_LEX_STATE_BEG);
11557 LEX(PM_TOKEN_MINUS);
11562 bool beg_p = lex_state_beg_p(parser);
11564 if (match(parser,
'.')) {
11565 if (match(parser,
'.')) {
11568 if (lex_state_p(parser, PM_LEX_STATE_END)) {
11569 lex_state_set(parser, PM_LEX_STATE_BEG);
11571 lex_state_set(parser, PM_LEX_STATE_ENDARG);
11573 LEX(PM_TOKEN_UDOT_DOT_DOT);
11577 pm_parser_warn_token(parser, &parser->
current, PM_WARN_DOT_DOT_DOT_EOL);
11580 lex_state_set(parser, PM_LEX_STATE_BEG);
11581 LEX(beg_p ? PM_TOKEN_UDOT_DOT_DOT : PM_TOKEN_DOT_DOT_DOT);
11584 lex_state_set(parser, PM_LEX_STATE_BEG);
11585 LEX(beg_p ? PM_TOKEN_UDOT_DOT : PM_TOKEN_DOT_DOT);
11588 lex_state_set(parser, PM_LEX_STATE_DOT);
11603 pm_token_type_t
type = lex_numeric(parser);
11604 lex_state_set(parser, PM_LEX_STATE_END);
11610 if (match(parser,
':')) {
11611 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)) {
11612 lex_state_set(parser, PM_LEX_STATE_BEG);
11613 LEX(PM_TOKEN_UCOLON_COLON);
11616 lex_state_set(parser, PM_LEX_STATE_DOT);
11617 LEX(PM_TOKEN_COLON_COLON);
11620 if (lex_state_end_p(parser) || pm_char_is_whitespace(peek(parser)) || peek(parser) ==
'#') {
11621 lex_state_set(parser, PM_LEX_STATE_BEG);
11622 LEX(PM_TOKEN_COLON);
11625 if (peek(parser) ==
'"' || peek(parser) ==
'\'') {
11626 lex_mode_push_string(parser, peek(parser) ==
'"',
false,
'\0', *parser->
current.end);
11630 lex_state_set(parser, PM_LEX_STATE_FNAME);
11631 LEX(PM_TOKEN_SYMBOL_BEGIN);
11635 if (lex_state_beg_p(parser)) {
11636 lex_mode_push_regexp(parser,
'\0',
'/');
11637 LEX(PM_TOKEN_REGEXP_BEGIN);
11640 if (match(parser,
'=')) {
11641 lex_state_set(parser, PM_LEX_STATE_BEG);
11642 LEX(PM_TOKEN_SLASH_EQUAL);
11645 if (lex_state_spcarg_p(parser, space_seen)) {
11646 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_SLASH);
11647 lex_mode_push_regexp(parser,
'\0',
'/');
11648 LEX(PM_TOKEN_REGEXP_BEGIN);
11651 if (ambiguous_operator_p(parser, space_seen)) {
11652 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"/",
"regexp literal");
11655 if (lex_state_operator_p(parser)) {
11656 lex_state_set(parser, PM_LEX_STATE_ARG);
11658 lex_state_set(parser, PM_LEX_STATE_BEG);
11661 LEX(PM_TOKEN_SLASH);
11665 if (lex_state_operator_p(parser)) {
11666 lex_state_set(parser, PM_LEX_STATE_ARG);
11668 lex_state_set(parser, PM_LEX_STATE_BEG);
11670 LEX(match(parser,
'=') ? PM_TOKEN_CARET_EQUAL : PM_TOKEN_CARET);
11674 if (lex_state_operator_p(parser)) {
11675 (void) match(parser,
'@');
11676 lex_state_set(parser, PM_LEX_STATE_ARG);
11678 lex_state_set(parser, PM_LEX_STATE_BEG);
11681 LEX(PM_TOKEN_TILDE);
11689 if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->
current.end >= parser->
end)) {
11690 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT_EOF);
11691 LEX(PM_TOKEN_PERCENT);
11694 if (!lex_state_beg_p(parser) && match(parser,
'=')) {
11695 lex_state_set(parser, PM_LEX_STATE_BEG);
11696 LEX(PM_TOKEN_PERCENT_EQUAL);
11698 lex_state_beg_p(parser) ||
11699 (lex_state_p(parser, PM_LEX_STATE_FITEM) && (peek(parser) ==
's')) ||
11700 lex_state_spcarg_p(parser, space_seen)
11703 if (*parser->
current.end >= 0x80) {
11704 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11707 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11708 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11709 LEX(PM_TOKEN_STRING_BEGIN);
11714 uint8_t delimiter = peek_offset(parser, 1);
11716 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11717 goto lex_next_token;
11720 switch (peek(parser)) {
11725 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11727 lex_mode_push_list_eof(parser);
11730 LEX(PM_TOKEN_PERCENT_LOWER_I);
11736 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11738 lex_mode_push_list_eof(parser);
11741 LEX(PM_TOKEN_PERCENT_UPPER_I);
11747 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11748 lex_mode_push_regexp(parser, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11750 lex_mode_push_regexp(parser,
'\0',
'\0');
11753 LEX(PM_TOKEN_REGEXP_BEGIN);
11759 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11760 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11762 lex_mode_push_string_eof(parser);
11765 LEX(PM_TOKEN_STRING_BEGIN);
11771 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11772 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11774 lex_mode_push_string_eof(parser);
11777 LEX(PM_TOKEN_STRING_BEGIN);
11783 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11784 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11785 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
11787 lex_mode_push_string_eof(parser);
11790 LEX(PM_TOKEN_SYMBOL_BEGIN);
11796 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11798 lex_mode_push_list_eof(parser);
11801 LEX(PM_TOKEN_PERCENT_LOWER_W);
11807 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11809 lex_mode_push_list_eof(parser);
11812 LEX(PM_TOKEN_PERCENT_UPPER_W);
11818 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11819 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11821 lex_mode_push_string_eof(parser);
11824 LEX(PM_TOKEN_PERCENT_LOWER_X);
11831 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11832 goto lex_next_token;
11836 if (ambiguous_operator_p(parser, space_seen)) {
11837 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"%",
"string literal");
11840 lex_state_set(parser, lex_state_operator_p(parser) ? PM_LEX_STATE_ARG : PM_LEX_STATE_BEG);
11841 LEX(PM_TOKEN_PERCENT);
11846 pm_token_type_t
type = lex_global_variable(parser);
11851 lex_mode_pop(parser);
11854 lex_state_set(parser, PM_LEX_STATE_END);
11860 lex_state_set(parser, parser->
lex_state & PM_LEX_STATE_FNAME ? PM_LEX_STATE_ENDFN : PM_LEX_STATE_END);
11861 LEX(lex_at_variable(parser));
11864 if (*parser->
current.start !=
'_') {
11865 size_t width = char_is_identifier_start(parser, parser->
current.start, parser->
end - parser->
current.start);
11872 if (*parser->
current.start >= 0x80) {
11873 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *parser->
current.start);
11874 }
else if (*parser->
current.start ==
'\\') {
11875 switch (peek_at(parser, parser->
current.start + 1)) {
11878 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped space");
11882 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped form feed");
11886 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped horizontal tab");
11890 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped vertical tab");
11893 if (peek_at(parser, parser->
current.start + 2) !=
'\n') {
11895 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped carriage return");
11900 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"backslash");
11903 }
else if (char_is_ascii_printable(*parser->
current.start)) {
11904 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_PRINTABLE_CHARACTER, *parser->
current.start);
11906 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_CHARACTER, *parser->
current.start);
11909 goto lex_next_token;
11915 pm_token_type_t
type = lex_identifier(parser, previous_command_start);
11923 current_token_starts_line(parser) &&
11924 (memcmp(parser->
current.start,
"__END__", 7) == 0) &&
11925 (parser->
current.end == parser->
end || match_eol(parser))
11930 const uint8_t *cursor = parser->
current.end;
11931 while ((cursor = next_newline(cursor, parser->
end - cursor)) != NULL) {
11932 pm_newline_list_append(&parser->
newline_list, cursor++);
11936 parser->
current.type = PM_TOKEN___END__;
11937 parser_lex_callback(parser);
11947 if (
type == PM_TOKEN_IDENTIFIER ||
type == PM_TOKEN_CONSTANT ||
type == PM_TOKEN_METHOD_NAME) {
11948 if (lex_state_p(parser, PM_LEX_STATE_BEG_ANY | PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_DOT)) {
11949 if (previous_command_start) {
11950 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11952 lex_state_set(parser, PM_LEX_STATE_ARG);
11954 }
else if (parser->
lex_state == PM_LEX_STATE_FNAME) {
11955 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11957 lex_state_set(parser, PM_LEX_STATE_END);
11962 !(last_state & (PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME)) &&
11963 (
type == PM_TOKEN_IDENTIFIER) &&
11964 ((pm_parser_local_depth(parser, &parser->
current) != -1) ||
11965 pm_token_is_numbered_parameter(parser->
current.start, parser->
current.end))
11967 lex_state_set(parser, PM_LEX_STATE_END | PM_LEX_STATE_LABEL);
11974 case PM_LEX_LIST: {
11988 whitespace = pm_strspn_inline_whitespace(parser->
current.end, parser->
end - parser->
current.end);
11989 if (peek_offset(parser, (ptrdiff_t)whitespace) ==
'\n') {
11996 if (whitespace > 0) {
11997 parser->
current.end += whitespace;
11998 if (peek_offset(parser, -1) ==
'\n') {
12000 parser_flush_heredoc_end(parser);
12002 LEX(PM_TOKEN_WORDS_SEP);
12014 const uint8_t *breakpoints = lex_mode->
as.list.
breakpoints;
12015 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12021 while (breakpoint != NULL) {
12024 if (pm_char_is_whitespace(*breakpoint)) {
12025 parser->
current.end = breakpoint;
12026 pm_token_buffer_flush(parser, &token_buffer);
12027 LEX(PM_TOKEN_STRING_CONTENT);
12036 parser->
current.end = breakpoint + 1;
12037 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12044 if (breakpoint > parser->
current.start) {
12045 parser->
current.end = breakpoint;
12046 pm_token_buffer_flush(parser, &token_buffer);
12047 LEX(PM_TOKEN_STRING_CONTENT);
12052 parser->
current.end = breakpoint + 1;
12053 lex_mode_pop(parser);
12054 lex_state_set(parser, PM_LEX_STATE_END);
12055 LEX(PM_TOKEN_STRING_END);
12059 if (*breakpoint ==
'\0') {
12060 breakpoint = pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->
end - (breakpoint + 1),
true);
12067 if (*breakpoint ==
'\\') {
12068 parser->
current.end = breakpoint + 1;
12077 pm_token_buffer_escape(parser, &token_buffer);
12078 uint8_t peeked = peek(parser);
12086 pm_token_buffer_push_byte(&token_buffer, peeked);
12091 if (peek(parser) !=
'\n') {
12092 pm_token_buffer_push_byte(&token_buffer,
'\r');
12097 pm_token_buffer_push_byte(&token_buffer,
'\n');
12103 parser_flush_heredoc_end(parser);
12104 pm_token_buffer_copy(parser, &token_buffer);
12105 LEX(PM_TOKEN_STRING_CONTENT);
12115 pm_token_buffer_push_byte(&token_buffer, peeked);
12118 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12120 pm_token_buffer_push_byte(&token_buffer,
'\\');
12121 pm_token_buffer_push_escaped(&token_buffer, parser);
12128 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12133 if (*breakpoint ==
'#') {
12134 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12136 if (
type == PM_TOKEN_NOT_PROVIDED) {
12141 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12145 if (
type == PM_TOKEN_STRING_CONTENT) {
12146 pm_token_buffer_flush(parser, &token_buffer);
12155 parser->
current.end = breakpoint + 1;
12156 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12162 pm_token_buffer_flush(parser, &token_buffer);
12163 LEX(PM_TOKEN_STRING_CONTENT);
12169 pm_token_buffer_flush(parser, &token_buffer);
12170 LEX(PM_TOKEN_STRING_CONTENT);
12172 case PM_LEX_REGEXP: {
12194 const uint8_t *breakpoints = lex_mode->
as.regexp.
breakpoints;
12195 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12198 while (breakpoint != NULL) {
12200 bool is_terminator = (*breakpoint == term);
12205 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
12206 if (term ==
'\n') {
12207 is_terminator =
true;
12213 if (term ==
'\r') {
12214 is_terminator =
false;
12220 if (is_terminator) {
12222 parser->
current.end = breakpoint + 1;
12223 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12231 if (breakpoint > parser->
current.start) {
12232 parser->
current.end = breakpoint;
12233 pm_regexp_token_buffer_flush(parser, &token_buffer);
12234 LEX(PM_TOKEN_STRING_CONTENT);
12238 size_t eol_length = match_eol_at(parser, breakpoint);
12240 parser->
current.end = breakpoint + eol_length;
12243 parser->
current.end = breakpoint + 1;
12250 lex_mode_pop(parser);
12251 lex_state_set(parser, PM_LEX_STATE_END);
12252 LEX(PM_TOKEN_REGEXP_END);
12257 if (*breakpoint && *breakpoint == lex_mode->
as.regexp.
incrementor) {
12258 parser->
current.end = breakpoint + 1;
12259 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12264 switch (*breakpoint) {
12267 parser->
current.end = breakpoint + 1;
12268 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12271 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12272 parser->
current.end = breakpoint + 1;
12273 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12278 parser->
current.end = breakpoint;
12279 pm_regexp_token_buffer_escape(parser, &token_buffer);
12287 pm_newline_list_append(&parser->
newline_list, breakpoint);
12288 parser->
current.end = breakpoint + 1;
12289 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12293 parser->
current.end = breakpoint + 1;
12294 parser_flush_heredoc_end(parser);
12295 pm_regexp_token_buffer_flush(parser, &token_buffer);
12296 LEX(PM_TOKEN_STRING_CONTENT);
12301 parser->
current.end = breakpoint + 1;
12310 pm_regexp_token_buffer_escape(parser, &token_buffer);
12311 uint8_t peeked = peek(parser);
12316 if (peek(parser) !=
'\n') {
12318 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12320 pm_regexp_token_buffer_push_byte(&token_buffer,
'\r');
12321 pm_token_buffer_push_byte(&token_buffer.
base,
'\r');
12330 parser_flush_heredoc_end(parser);
12331 pm_regexp_token_buffer_copy(parser, &token_buffer);
12332 LEX(PM_TOKEN_STRING_CONTENT);
12353 case '$':
case ')':
case '*':
case '+':
12354 case '.':
case '>':
case '?':
case ']':
12355 case '^':
case '|':
case '}':
12356 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12362 pm_regexp_token_buffer_push_byte(&token_buffer, peeked);
12363 pm_token_buffer_push_byte(&token_buffer.
base, peeked);
12368 if (peeked < 0x80) pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12369 pm_regexp_token_buffer_push_escaped(&token_buffer, parser);
12374 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12380 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12382 if (
type == PM_TOKEN_NOT_PROVIDED) {
12387 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12391 if (
type == PM_TOKEN_STRING_CONTENT) {
12392 pm_regexp_token_buffer_flush(parser, &token_buffer);
12398 assert(
false &&
"unreachable");
12404 pm_regexp_token_buffer_flush(parser, &token_buffer);
12405 LEX(PM_TOKEN_STRING_CONTENT);
12411 pm_regexp_token_buffer_flush(parser, &token_buffer);
12412 LEX(PM_TOKEN_STRING_CONTENT);
12414 case PM_LEX_STRING: {
12433 const uint8_t *breakpoints = lex_mode->
as.string.
breakpoints;
12434 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12440 while (breakpoint != NULL) {
12445 parser->
current.end = breakpoint + 1;
12446 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12451 bool is_terminator = (*breakpoint == term);
12456 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
12457 if (term ==
'\n') {
12458 is_terminator =
true;
12464 if (term ==
'\r') {
12465 is_terminator =
false;
12472 if (is_terminator) {
12476 parser->
current.end = breakpoint + 1;
12477 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12484 if (breakpoint > parser->
current.start) {
12485 parser->
current.end = breakpoint;
12486 pm_token_buffer_flush(parser, &token_buffer);
12487 LEX(PM_TOKEN_STRING_CONTENT);
12492 size_t eol_length = match_eol_at(parser, breakpoint);
12494 parser->
current.end = breakpoint + eol_length;
12497 parser->
current.end = breakpoint + 1;
12500 if (lex_mode->
as.string.
label_allowed && (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')) {
12502 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
12503 lex_mode_pop(parser);
12504 LEX(PM_TOKEN_LABEL_END);
12507 lex_state_set(parser, PM_LEX_STATE_END);
12508 lex_mode_pop(parser);
12509 LEX(PM_TOKEN_STRING_END);
12512 switch (*breakpoint) {
12515 parser->
current.end = breakpoint + 1;
12516 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12519 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12520 parser->
current.end = breakpoint + 1;
12521 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12528 parser->
current.end = breakpoint;
12529 pm_token_buffer_escape(parser, &token_buffer);
12530 token_buffer.
cursor = breakpoint;
12539 pm_newline_list_append(&parser->
newline_list, breakpoint);
12540 parser->
current.end = breakpoint + 1;
12541 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12545 parser->
current.end = breakpoint + 1;
12546 parser_flush_heredoc_end(parser);
12547 pm_token_buffer_flush(parser, &token_buffer);
12548 LEX(PM_TOKEN_STRING_CONTENT);
12551 parser->
current.end = breakpoint + 1;
12560 pm_token_buffer_escape(parser, &token_buffer);
12561 uint8_t peeked = peek(parser);
12565 pm_token_buffer_push_byte(&token_buffer,
'\\');
12570 if (peek(parser) !=
'\n') {
12572 pm_token_buffer_push_byte(&token_buffer,
'\\');
12574 pm_token_buffer_push_byte(&token_buffer,
'\r');
12580 pm_token_buffer_push_byte(&token_buffer,
'\\');
12581 pm_token_buffer_push_byte(&token_buffer,
'\n');
12588 parser_flush_heredoc_end(parser);
12589 pm_token_buffer_copy(parser, &token_buffer);
12590 LEX(PM_TOKEN_STRING_CONTENT);
12600 pm_token_buffer_push_byte(&token_buffer, peeked);
12603 pm_token_buffer_push_byte(&token_buffer, peeked);
12606 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12608 pm_token_buffer_push_byte(&token_buffer,
'\\');
12609 pm_token_buffer_push_escaped(&token_buffer, parser);
12616 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12620 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12622 if (
type == PM_TOKEN_NOT_PROVIDED) {
12627 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12631 if (
type == PM_TOKEN_STRING_CONTENT) {
12632 pm_token_buffer_flush(parser, &token_buffer);
12638 assert(
false &&
"unreachable");
12643 pm_token_buffer_flush(parser, &token_buffer);
12644 LEX(PM_TOKEN_STRING_CONTENT);
12650 pm_token_buffer_flush(parser, &token_buffer);
12651 LEX(PM_TOKEN_STRING_CONTENT);
12653 case PM_LEX_HEREDOC: {
12680 lex_state_set(parser, PM_LEX_STATE_END);
12681 lex_mode_pop(parser);
12682 LEX(PM_TOKEN_HEREDOC_END);
12685 const uint8_t *ident_start = heredoc_lex_mode->
ident_start;
12690 if (current_token_starts_line(parser)) {
12691 const uint8_t *start = parser->
current.start;
12693 if (!line_continuation && (start + ident_length <= parser->end)) {
12694 const uint8_t *newline = next_newline(start, parser->
end - start);
12695 const uint8_t *ident_end = newline;
12696 const uint8_t *terminator_end = newline;
12698 if (newline == NULL) {
12699 terminator_end = parser->
end;
12700 ident_end = parser->
end;
12703 if (newline[-1] ==
'\r') {
12708 const uint8_t *terminator_start = ident_end - ident_length;
12709 const uint8_t *cursor = start;
12711 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12712 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12718 (cursor == terminator_start) &&
12719 (memcmp(terminator_start, ident_start, ident_length) == 0)
12721 if (newline != NULL) {
12722 pm_newline_list_append(&parser->
newline_list, newline);
12725 parser->
current.end = terminator_end;
12733 lex_state_set(parser, PM_LEX_STATE_END);
12734 lex_mode_pop(parser);
12735 LEX(PM_TOKEN_HEREDOC_END);
12739 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, heredoc_lex_mode->
indent);
12741 heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE &&
12744 peek_at(parser, start) !=
'\n'
12753 uint8_t breakpoints[] =
"\r\n\\#";
12756 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12757 breakpoints[3] =
'\0';
12760 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12762 bool was_line_continuation =
false;
12764 while (breakpoint != NULL) {
12765 switch (*breakpoint) {
12768 parser->
current.end = breakpoint + 1;
12769 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12772 parser->
current.end = breakpoint + 1;
12774 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12775 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12782 pm_token_buffer_escape(parser, &token_buffer);
12783 token_buffer.
cursor = breakpoint;
12788 parser_flush_heredoc_end(parser);
12789 parser->
current.end = breakpoint + 1;
12790 pm_token_buffer_flush(parser, &token_buffer);
12791 LEX(PM_TOKEN_STRING_CONTENT);
12794 pm_newline_list_append(&parser->
newline_list, breakpoint);
12798 const uint8_t *start = breakpoint + 1;
12800 if (!was_line_continuation && (start + ident_length <= parser->end)) {
12803 const uint8_t *newline = next_newline(start, parser->
end - start);
12805 if (newline == NULL) {
12806 newline = parser->
end;
12807 }
else if (newline[-1] ==
'\r') {
12812 const uint8_t *terminator_start = newline - ident_length;
12816 const uint8_t *cursor = start;
12818 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12819 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12825 cursor == terminator_start &&
12826 (memcmp(terminator_start, ident_start, ident_length) == 0)
12828 parser->
current.end = breakpoint + 1;
12829 pm_token_buffer_flush(parser, &token_buffer);
12830 LEX(PM_TOKEN_STRING_CONTENT);
12834 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->
as.heredoc.
base.
indent);
12841 if (lex_mode->
as.heredoc.
base.
indent == PM_HEREDOC_INDENT_TILDE) {
12846 parser->
current.end = breakpoint + 1;
12847 pm_token_buffer_flush(parser, &token_buffer);
12848 LEX(PM_TOKEN_STRING_CONTENT);
12853 parser->
current.end = breakpoint + 1;
12854 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12864 parser->
current.end = breakpoint + 1;
12873 pm_token_buffer_escape(parser, &token_buffer);
12874 uint8_t peeked = peek(parser);
12876 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12880 if (peek(parser) !=
'\n') {
12881 pm_token_buffer_push_byte(&token_buffer,
'\\');
12882 pm_token_buffer_push_byte(&token_buffer,
'\r');
12887 pm_token_buffer_push_byte(&token_buffer,
'\\');
12888 pm_token_buffer_push_byte(&token_buffer,
'\n');
12890 breakpoint = parser->
current.end;
12893 pm_token_buffer_push_byte(&token_buffer,
'\\');
12894 pm_token_buffer_push_escaped(&token_buffer, parser);
12901 if (peek(parser) !=
'\n') {
12902 pm_token_buffer_push_byte(&token_buffer,
'\r');
12910 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12911 const uint8_t *end = parser->
current.end;
12916 parser->
current.end = breakpoint;
12917 pm_token_buffer_flush(parser, &token_buffer);
12921 parser->
current.end = end + 1;
12923 LEX(PM_TOKEN_STRING_CONTENT);
12926 was_line_continuation =
true;
12928 breakpoint = parser->
current.end;
12931 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12937 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12941 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12943 if (
type == PM_TOKEN_NOT_PROVIDED) {
12949 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12953 if (
type == PM_TOKEN_STRING_CONTENT) {
12954 pm_token_buffer_flush(parser, &token_buffer);
12960 assert(
false &&
"unreachable");
12963 was_line_continuation =
false;
12968 pm_token_buffer_flush(parser, &token_buffer);
12969 LEX(PM_TOKEN_STRING_CONTENT);
12975 pm_token_buffer_flush(parser, &token_buffer);
12976 LEX(PM_TOKEN_STRING_CONTENT);
12980 assert(
false &&
"unreachable");
12998 PM_BINDING_POWER_UNSET = 0,
12999 PM_BINDING_POWER_STATEMENT = 2,
13000 PM_BINDING_POWER_MODIFIER_RESCUE = 4,
13001 PM_BINDING_POWER_MODIFIER = 6,
13002 PM_BINDING_POWER_COMPOSITION = 8,
13003 PM_BINDING_POWER_NOT = 10,
13004 PM_BINDING_POWER_MATCH = 12,
13005 PM_BINDING_POWER_DEFINED = 14,
13006 PM_BINDING_POWER_MULTI_ASSIGNMENT = 16,
13007 PM_BINDING_POWER_ASSIGNMENT = 18,
13008 PM_BINDING_POWER_TERNARY = 20,
13009 PM_BINDING_POWER_RANGE = 22,
13010 PM_BINDING_POWER_LOGICAL_OR = 24,
13011 PM_BINDING_POWER_LOGICAL_AND = 26,
13012 PM_BINDING_POWER_EQUALITY = 28,
13013 PM_BINDING_POWER_COMPARISON = 30,
13014 PM_BINDING_POWER_BITWISE_OR = 32,
13015 PM_BINDING_POWER_BITWISE_AND = 34,
13016 PM_BINDING_POWER_SHIFT = 36,
13017 PM_BINDING_POWER_TERM = 38,
13018 PM_BINDING_POWER_FACTOR = 40,
13019 PM_BINDING_POWER_UMINUS = 42,
13020 PM_BINDING_POWER_EXPONENT = 44,
13021 PM_BINDING_POWER_UNARY = 46,
13022 PM_BINDING_POWER_INDEX = 48,
13023 PM_BINDING_POWER_CALL = 50,
13024 PM_BINDING_POWER_MAX = 52
13025} pm_binding_power_t;
13048#define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true, false }
13049#define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, false }
13050#define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true, false }
13051#define NON_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, true }
13052#define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false, false }
13056 [PM_TOKEN_KEYWORD_RESCUE_MODIFIER] = { PM_BINDING_POWER_MODIFIER_RESCUE, PM_BINDING_POWER_COMPOSITION,
true,
false },
13059 [PM_TOKEN_KEYWORD_IF_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
13060 [PM_TOKEN_KEYWORD_UNLESS_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
13061 [PM_TOKEN_KEYWORD_UNTIL_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
13062 [PM_TOKEN_KEYWORD_WHILE_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
13065 [PM_TOKEN_KEYWORD_AND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
13066 [PM_TOKEN_KEYWORD_OR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
13069 [PM_TOKEN_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
13070 [PM_TOKEN_KEYWORD_IN] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
13073 [PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
13074 [PM_TOKEN_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
13075 [PM_TOKEN_CARET_EQUAL] = BINDING_POWER_ASSIGNMENT,
13076 [PM_TOKEN_EQUAL] = BINDING_POWER_ASSIGNMENT,
13077 [PM_TOKEN_GREATER_GREATER_EQUAL] = BINDING_POWER_ASSIGNMENT,
13078 [PM_TOKEN_LESS_LESS_EQUAL] = BINDING_POWER_ASSIGNMENT,
13079 [PM_TOKEN_MINUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
13080 [PM_TOKEN_PERCENT_EQUAL] = BINDING_POWER_ASSIGNMENT,
13081 [PM_TOKEN_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
13082 [PM_TOKEN_PIPE_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
13083 [PM_TOKEN_PLUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
13084 [PM_TOKEN_SLASH_EQUAL] = BINDING_POWER_ASSIGNMENT,
13085 [PM_TOKEN_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
13086 [PM_TOKEN_STAR_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
13089 [PM_TOKEN_QUESTION_MARK] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_TERNARY),
13092 [PM_TOKEN_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
13093 [PM_TOKEN_DOT_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
13094 [PM_TOKEN_UDOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
13095 [PM_TOKEN_UDOT_DOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
13098 [PM_TOKEN_PIPE_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_OR),
13101 [PM_TOKEN_AMPERSAND_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_AND),
13104 [PM_TOKEN_BANG_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
13105 [PM_TOKEN_BANG_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
13106 [PM_TOKEN_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
13107 [PM_TOKEN_EQUAL_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
13108 [PM_TOKEN_EQUAL_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
13109 [PM_TOKEN_LESS_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
13112 [PM_TOKEN_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
13113 [PM_TOKEN_GREATER_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
13114 [PM_TOKEN_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
13115 [PM_TOKEN_LESS_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
13118 [PM_TOKEN_CARET] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
13119 [PM_TOKEN_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
13122 [PM_TOKEN_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_AND),
13125 [PM_TOKEN_GREATER_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
13126 [PM_TOKEN_LESS_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
13129 [PM_TOKEN_MINUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
13130 [PM_TOKEN_PLUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
13133 [PM_TOKEN_PERCENT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
13134 [PM_TOKEN_SLASH] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
13135 [PM_TOKEN_STAR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
13136 [PM_TOKEN_USTAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_FACTOR),
13139 [PM_TOKEN_UMINUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UMINUS),
13140 [PM_TOKEN_UMINUS_NUM] = { PM_BINDING_POWER_UMINUS, PM_BINDING_POWER_MAX,
false,
false },
13143 [PM_TOKEN_STAR_STAR] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_EXPONENT),
13144 [PM_TOKEN_USTAR_STAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13147 [PM_TOKEN_BANG] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13148 [PM_TOKEN_TILDE] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13149 [PM_TOKEN_UPLUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13152 [PM_TOKEN_BRACKET_LEFT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_INDEX),
13155 [PM_TOKEN_COLON_COLON] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
13156 [PM_TOKEN_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
13157 [PM_TOKEN_AMPERSAND_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL)
13160#undef BINDING_POWER_ASSIGNMENT
13161#undef LEFT_ASSOCIATIVE
13162#undef RIGHT_ASSOCIATIVE
13163#undef RIGHT_ASSOCIATIVE_UNARY
13177match2(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
13178 return match1(parser, type1) || match1(parser, type2);
13185match3(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3) {
13186 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3);
13193match4(
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) {
13194 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4);
13201match7(
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) {
13202 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7);
13209match8(
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) {
13210 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);
13221 if (match1(parser,
type)) {
13222 parser_lex(parser);
13233accept2(
pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
13234 if (match2(parser, type1, type2)) {
13235 parser_lex(parser);
13254 if (accept1(parser,
type))
return;
13257 pm_parser_err(parser, location, location, diag_id);
13269 if (accept2(parser, type1, type2))
return;
13272 pm_parser_err(parser, location, location, diag_id);
13283expect1_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
13284 if (match1(parser, PM_TOKEN_HEREDOC_END)) {
13285 parser_lex(parser);
13287 pm_parser_err_heredoc_term(parser, ident_start, ident_length);
13294parse_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);
13301parse_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) {
13302 pm_node_t *node = parse_expression(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
13303 pm_assert_value_expression(parser, node);
13326token_begins_expression_p(pm_token_type_t
type) {
13328 case PM_TOKEN_EQUAL_GREATER:
13329 case PM_TOKEN_KEYWORD_IN:
13333 case PM_TOKEN_BRACE_RIGHT:
13334 case PM_TOKEN_BRACKET_RIGHT:
13335 case PM_TOKEN_COLON:
13336 case PM_TOKEN_COMMA:
13337 case PM_TOKEN_EMBEXPR_END:
13339 case PM_TOKEN_LAMBDA_BEGIN:
13340 case PM_TOKEN_KEYWORD_DO:
13341 case PM_TOKEN_KEYWORD_DO_LOOP:
13342 case PM_TOKEN_KEYWORD_END:
13343 case PM_TOKEN_KEYWORD_ELSE:
13344 case PM_TOKEN_KEYWORD_ELSIF:
13345 case PM_TOKEN_KEYWORD_ENSURE:
13346 case PM_TOKEN_KEYWORD_THEN:
13347 case PM_TOKEN_KEYWORD_RESCUE:
13348 case PM_TOKEN_KEYWORD_WHEN:
13349 case PM_TOKEN_NEWLINE:
13350 case PM_TOKEN_PARENTHESIS_RIGHT:
13351 case PM_TOKEN_SEMICOLON:
13357 assert(pm_binding_powers[
type].left == PM_BINDING_POWER_UNSET);
13359 case PM_TOKEN_UAMPERSAND:
13363 case PM_TOKEN_UCOLON_COLON:
13364 case PM_TOKEN_UMINUS:
13365 case PM_TOKEN_UMINUS_NUM:
13366 case PM_TOKEN_UPLUS:
13367 case PM_TOKEN_BANG:
13368 case PM_TOKEN_TILDE:
13369 case PM_TOKEN_UDOT_DOT:
13370 case PM_TOKEN_UDOT_DOT_DOT:
13377 return pm_binding_powers[
type].
left == PM_BINDING_POWER_UNSET;
13386parse_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) {
13387 if (accept1(parser, PM_TOKEN_USTAR)) {
13389 pm_node_t *expression = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13390 return (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
13393 return parse_value_expression(parser, binding_power, accepts_command_call,
false, diag_id, depth);
13407 size_t length = constant->
length;
13408 uint8_t *name =
xcalloc(length + 1,
sizeof(uint8_t));
13409 if (name == NULL)
return;
13411 memcpy(name, constant->
start, length);
13412 name[length] =
'=';
13417 *name_field = pm_constant_pool_insert_owned(&parser->
constant_pool, name, length + 1);
13428 switch (PM_NODE_TYPE(target)) {
13429 case PM_SOURCE_ENCODING_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13430 case PM_FALSE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13431 case PM_SOURCE_FILE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13432 case PM_SOURCE_LINE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13433 case PM_NIL_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13434 case PM_SELF_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13435 case PM_TRUE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13442 pm_node_destroy(parser, target);
13455 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
13456 if (implicit_parameters->
nodes[index] == node) {
13460 if (index != implicit_parameters->
size - 1) {
13461 memcpy(&implicit_parameters->
nodes[index], &implicit_parameters->
nodes[index + 1], (implicit_parameters->
size - index - 1) *
sizeof(
pm_node_t *));
13464 implicit_parameters->
size--;
13480 switch (PM_NODE_TYPE(target)) {
13481 case PM_MISSING_NODE:
13483 case PM_SOURCE_ENCODING_NODE:
13484 case PM_FALSE_NODE:
13485 case PM_SOURCE_FILE_NODE:
13486 case PM_SOURCE_LINE_NODE:
13489 case PM_TRUE_NODE: {
13492 return parse_unwriteable_target(parser, target);
13494 case PM_CLASS_VARIABLE_READ_NODE:
13496 target->
type = PM_CLASS_VARIABLE_TARGET_NODE;
13498 case PM_CONSTANT_PATH_NODE:
13499 if (context_def_p(parser)) {
13500 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13504 target->
type = PM_CONSTANT_PATH_TARGET_NODE;
13507 case PM_CONSTANT_READ_NODE:
13508 if (context_def_p(parser)) {
13509 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13513 target->
type = PM_CONSTANT_TARGET_NODE;
13516 case PM_BACK_REFERENCE_READ_NODE:
13517 case PM_NUMBERED_REFERENCE_READ_NODE:
13518 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13520 case PM_GLOBAL_VARIABLE_READ_NODE:
13522 target->
type = PM_GLOBAL_VARIABLE_TARGET_NODE;
13524 case PM_LOCAL_VARIABLE_READ_NODE: {
13527 parse_target_implicit_parameter(parser, target);
13531 uint32_t name = cast->
name;
13532 uint32_t depth = cast->
depth;
13533 pm_locals_unread(&pm_parser_scope_find(parser, depth)->locals, name);
13536 target->
type = PM_LOCAL_VARIABLE_TARGET_NODE;
13540 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
13544 parse_target_implicit_parameter(parser, target);
13545 pm_node_destroy(parser, target);
13549 case PM_INSTANCE_VARIABLE_READ_NODE:
13551 target->
type = PM_INSTANCE_VARIABLE_TARGET_NODE;
13553 case PM_MULTI_TARGET_NODE:
13554 if (splat_parent) {
13557 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13561 case PM_SPLAT_NODE: {
13570 case PM_CALL_NODE: {
13582 (call->
block == NULL)
13597 pm_node_destroy(parser, target);
13599 return (
pm_node_t *) pm_local_variable_target_node_create(parser, &message_loc, name, 0);
13603 if (multiple && PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
13604 pm_parser_err_node(parser, (
const pm_node_t *) call, PM_ERR_UNEXPECTED_SAFE_NAVIGATION);
13607 parse_write_name(parser, &call->
name);
13608 return (
pm_node_t *) pm_call_target_node_create(parser, call);
13615 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
13616 return (
pm_node_t *) pm_index_target_node_create(parser, call);
13624 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13635 pm_node_t *result = parse_target(parser, target, multiple,
false);
13640 !match1(parser, PM_TOKEN_EQUAL) &&
13642 !(context_p(parser,
PM_CONTEXT_PARENS) && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
13644 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13658 if (shareable_constant != PM_SCOPE_SHAREABLE_CONSTANT_NONE) {
13659 return (
pm_node_t *) pm_shareable_constant_node_create(parser, write, shareable_constant);
13670 switch (PM_NODE_TYPE(target)) {
13671 case PM_MISSING_NODE:
13672 pm_node_destroy(parser, value);
13674 case PM_CLASS_VARIABLE_READ_NODE: {
13676 pm_node_destroy(parser, target);
13679 case PM_CONSTANT_PATH_NODE: {
13682 if (context_def_p(parser)) {
13683 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13686 return parse_shareable_constant_write(parser, node);
13688 case PM_CONSTANT_READ_NODE: {
13691 if (context_def_p(parser)) {
13692 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13695 pm_node_destroy(parser, target);
13696 return parse_shareable_constant_write(parser, node);
13698 case PM_BACK_REFERENCE_READ_NODE:
13699 case PM_NUMBERED_REFERENCE_READ_NODE:
13700 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13702 case PM_GLOBAL_VARIABLE_READ_NODE: {
13704 pm_node_destroy(parser, target);
13707 case PM_LOCAL_VARIABLE_READ_NODE: {
13713 uint32_t depth = local_read->
depth;
13714 pm_scope_t *scope = pm_parser_scope_find(parser, depth);
13717 pm_diagnostic_id_t diag_id = (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND) ? PM_ERR_EXPRESSION_NOT_WRITABLE_NUMBERED : PM_ERR_PARAMETER_NUMBERED_RESERVED;
13719 parse_target_implicit_parameter(parser, target);
13722 pm_locals_unread(&scope->
locals, name);
13723 pm_node_destroy(parser, target);
13725 return (
pm_node_t *) pm_local_variable_write_node_create(parser, name, depth, value, &name_loc,
operator);
13727 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
13731 parse_target_implicit_parameter(parser, target);
13732 pm_node_destroy(parser, target);
13736 case PM_INSTANCE_VARIABLE_READ_NODE: {
13738 pm_node_destroy(parser, target);
13741 case PM_MULTI_TARGET_NODE:
13743 case PM_SPLAT_NODE: {
13751 pm_multi_target_node_targets_append(parser, multi_target, (
pm_node_t *) splat);
13753 return (
pm_node_t *) pm_multi_write_node_create(parser, multi_target,
operator, value);
13755 case PM_CALL_NODE: {
13767 (call->
block == NULL)
13781 pm_parser_local_add_location(parser, message.
start, message.
end, 0);
13782 pm_node_destroy(parser, target);
13785 target = (
pm_node_t *) pm_local_variable_write_node_create(parser, constant_id, 0, value, &message,
operator);
13787 pm_refute_numbered_parameter(parser, message.
start, message.
end);
13805 pm_arguments_node_arguments_append(arguments, value);
13808 parse_write_name(parser, &call->
name);
13809 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));
13818 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
13820 call->
arguments = pm_arguments_node_create(parser);
13823 pm_arguments_node_arguments_append(call->
arguments, value);
13827 call->
name = pm_parser_constant_id_constant(parser,
"[]=", 3);
13831 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));
13841 pm_node_destroy(parser, value);
13848 pm_parser_err_token(parser,
operator, PM_ERR_WRITE_TARGET_UNEXPECTED);
13861 switch (PM_NODE_TYPE(target)) {
13862 case PM_SOURCE_ENCODING_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13863 case PM_FALSE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13864 case PM_SOURCE_FILE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13865 case PM_SOURCE_LINE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13866 case PM_NIL_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13867 case PM_SELF_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13868 case PM_TRUE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13875 pm_node_destroy(parser, target);
13890parse_targets(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13891 bool has_rest = PM_NODE_TYPE_P(first_target, PM_SPLAT_NODE);
13894 pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target,
true,
false));
13896 while (accept1(parser, PM_TOKEN_COMMA)) {
13897 if (accept1(parser, PM_TOKEN_USTAR)) {
13902 pm_parser_err_previous(parser, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
13908 if (token_begins_expression_p(parser->
current.type)) {
13909 name = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13910 name = parse_target(parser, name,
true,
true);
13913 pm_node_t *splat = (
pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
13914 pm_multi_target_node_targets_append(parser, result, splat);
13916 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
13918 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13919 target = parse_target(parser, target,
true,
false);
13921 pm_multi_target_node_targets_append(parser, result, target);
13922 context_pop(parser);
13923 }
else if (token_begins_expression_p(parser->
current.type)) {
13924 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13925 target = parse_target(parser, target,
true,
false);
13927 pm_multi_target_node_targets_append(parser, result, target);
13928 }
else if (!match1(parser, PM_TOKEN_EOF)) {
13932 pm_multi_target_node_targets_append(parser, result, rest);
13945parse_targets_validate(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13946 pm_node_t *result = parse_targets(parser, first_target, binding_power, depth);
13947 accept1(parser, PM_TOKEN_NEWLINE);
13950 if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
13951 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13964 while (accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE));
13967 if (context_terminator(context, &parser->
current))
return NULL;
13973 context_push(parser, context);
13976 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
13977 pm_statements_node_body_append(parser, statements, node,
true);
13990 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
13993 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13994 if (context_terminator(context, &parser->
current))
break;
14004 if (context_terminator(context, &parser->
current))
break;
14016 if (PM_NODE_TYPE_P(node, PM_MISSING_NODE)) {
14017 parser_lex(parser);
14023 if (match1(parser, PM_TOKEN_EOF)) {
14028 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
14029 if (context_terminator(context, &parser->
current))
break;
14030 }
else if (!accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_EOF)) {
14040 context_pop(parser);
14041 bool last_value =
true;
14045 last_value =
false;
14050 pm_void_statements_check(parser, statements, last_value);
14063 if (duplicated != NULL) {
14067 pm_diagnostic_list_append_format(
14071 PM_WARN_DUPLICATED_HASH_KEY,
14089 if ((previous = pm_static_literals_add(&parser->
newline_list, parser->
start_line, literals, node,
false)) != NULL) {
14090 pm_diagnostic_list_append_format(
14094 PM_WARN_DUPLICATED_WHEN_CLAUSE,
14106 assert(PM_NODE_TYPE_P(node, PM_HASH_NODE) || PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE));
14107 bool contains_keyword_splat =
false;
14112 switch (parser->
current.type) {
14113 case PM_TOKEN_USTAR_STAR: {
14114 parser_lex(parser);
14118 if (match1(parser, PM_TOKEN_BRACE_LEFT)) {
14124 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
14125 }
else if (token_begins_expression_p(parser->
current.type)) {
14126 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
14128 pm_parser_scope_forwarding_keywords_check(parser, &
operator);
14131 element = (
pm_node_t *) pm_assoc_splat_node_create(parser, value, &
operator);
14132 contains_keyword_splat =
true;
14135 case PM_TOKEN_LABEL: {
14137 parser_lex(parser);
14140 pm_hash_key_static_literals_add(parser, literals, key);
14145 if (token_begins_expression_p(parser->
current.type)) {
14146 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_EXPRESSION_AFTER_LABEL, (uint16_t) (depth + 1));
14149 pm_token_t constant = { .type = PM_TOKEN_CONSTANT, .start = label.
start, .end = label.
end - 1 };
14150 value = (
pm_node_t *) pm_constant_read_node_create(parser, &constant);
14155 if (identifier.
end[-1] ==
'!' || identifier.
end[-1] ==
'?') {
14156 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, identifier, PM_ERR_INVALID_LOCAL_VARIABLE_READ);
14158 depth = pm_parser_local_depth(parser, &identifier);
14162 value = (
pm_node_t *) pm_call_node_variable_call_create(parser, &identifier);
14164 value = (
pm_node_t *) pm_local_variable_read_node_create(parser, &identifier, (uint32_t) depth);
14169 value = (
pm_node_t *) pm_implicit_node_create(parser, value);
14172 element = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
14176 pm_node_t *key = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_HASH_KEY, (uint16_t) (depth + 1));
14180 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
14181 pm_node_flag_set(key, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
14184 pm_hash_key_static_literals_add(parser, literals, key);
14187 if (pm_symbol_node_label_p(key)) {
14188 operator = not_provided(parser);
14190 expect1(parser, PM_TOKEN_EQUAL_GREATER, PM_ERR_HASH_ROCKET);
14194 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
14195 element = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
14200 if (PM_NODE_TYPE_P(node, PM_HASH_NODE)) {
14207 if (!accept1(parser, PM_TOKEN_COMMA))
break;
14211 if (match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL))
continue;
14215 if (token_begins_expression_p(parser->
current.type))
continue;
14221 return contains_keyword_splat;
14230 arguments->
arguments = pm_arguments_node_create(parser);
14233 pm_arguments_node_arguments_append(arguments->
arguments, argument);
14240parse_arguments(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_forwarding, pm_token_type_t terminator, uint16_t depth) {
14241 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].
left;
14246 match2(parser, terminator, PM_TOKEN_EOF) ||
14247 (binding_power != PM_BINDING_POWER_UNSET && binding_power < PM_BINDING_POWER_RANGE) ||
14253 bool parsed_first_argument =
false;
14254 bool parsed_bare_hash =
false;
14255 bool parsed_block_argument =
false;
14256 bool parsed_forwarding_arguments =
false;
14258 while (!match1(parser, PM_TOKEN_EOF)) {
14259 if (parsed_forwarding_arguments) {
14260 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES);
14265 switch (parser->
current.type) {
14266 case PM_TOKEN_USTAR_STAR:
14267 case PM_TOKEN_LABEL: {
14268 if (parsed_bare_hash) {
14269 pm_parser_err_current(parser, PM_ERR_ARGUMENT_BARE_HASH);
14276 bool contains_keyword_splat = parse_assocs(parser, &hash_keys, (
pm_node_t *) hash, (uint16_t) (depth + 1));
14278 parse_arguments_append(parser, arguments, argument);
14280 pm_node_flags_t flags = PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
14281 if (contains_keyword_splat) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
14284 pm_static_literals_free(&hash_keys);
14285 parsed_bare_hash =
true;
14289 case PM_TOKEN_UAMPERSAND: {
14290 parser_lex(parser);
14294 if (token_begins_expression_p(parser->
current.type)) {
14295 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14297 pm_parser_scope_forwarding_block_check(parser, &
operator);
14300 argument = (
pm_node_t *) pm_block_argument_node_create(parser, &
operator, expression);
14301 if (parsed_block_argument) {
14302 parse_arguments_append(parser, arguments, argument);
14304 arguments->
block = argument;
14307 if (match1(parser, PM_TOKEN_COMMA)) {
14308 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK);
14311 parsed_block_argument =
true;
14314 case PM_TOKEN_USTAR: {
14315 parser_lex(parser);
14318 if (match4(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_SEMICOLON, PM_TOKEN_BRACKET_RIGHT)) {
14319 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
14320 argument = (
pm_node_t *) pm_splat_node_create(parser, &
operator, NULL);
14321 if (parsed_bare_hash) {
14322 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
14325 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT, (uint16_t) (depth + 1));
14327 if (parsed_bare_hash) {
14328 pm_parser_err(parser,
operator.start, expression->
location.
end, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
14331 argument = (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
14334 parse_arguments_append(parser, arguments, argument);
14337 case PM_TOKEN_UDOT_DOT_DOT: {
14338 if (accepts_forwarding) {
14339 parser_lex(parser);
14341 if (token_begins_expression_p(parser->
current.type)) {
14346 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_RANGE,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
14351 if (PM_NODE_TYPE_P(right, PM_RANGE_NODE)) {
14353 pm_parser_err(parser, range->operator_loc.start, range->operator_loc.end, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
14356 argument = (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
14358 pm_parser_scope_forwarding_all_check(parser, &parser->
previous);
14359 if (parsed_first_argument && terminator == PM_TOKEN_EOF) {
14360 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORWARDING_UNBOUND);
14363 argument = (
pm_node_t *) pm_forwarding_arguments_node_create(parser, &parser->
previous);
14364 parse_arguments_append(parser, arguments, argument);
14365 pm_node_flag_set((
pm_node_t *) arguments->
arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING);
14367 parsed_forwarding_arguments =
true;
14374 if (argument == NULL) {
14375 argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, !parsed_first_argument,
true, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14378 bool contains_keywords =
false;
14379 bool contains_keyword_splat =
false;
14381 if (pm_symbol_node_label_p(argument) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
14382 if (parsed_bare_hash) {
14383 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
14387 if (parser->
previous.
type == PM_TOKEN_EQUAL_GREATER) {
14390 operator = not_provided(parser);
14394 contains_keywords =
true;
14398 pm_hash_key_static_literals_add(parser, &hash_keys, argument);
14401 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
14402 argument = (
pm_node_t *) pm_assoc_node_create(parser, argument, &
operator, value);
14404 pm_keyword_hash_node_elements_append(bare_hash, argument);
14408 if (accept1(parser, PM_TOKEN_COMMA) && (
14409 token_begins_expression_p(parser->
current.type) ||
14410 match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL)
14412 contains_keyword_splat = parse_assocs(parser, &hash_keys, (
pm_node_t *) bare_hash, (uint16_t) (depth + 1));
14415 pm_static_literals_free(&hash_keys);
14416 parsed_bare_hash =
true;
14419 parse_arguments_append(parser, arguments, argument);
14421 pm_node_flags_t flags = 0;
14422 if (contains_keywords) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
14423 if (contains_keyword_splat) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
14430 parsed_first_argument =
true;
14433 if (PM_NODE_TYPE_P(argument, PM_MISSING_NODE) || parser->
recovering)
break;
14438 bool accepted_newline =
false;
14439 if (terminator != PM_TOKEN_EOF) {
14440 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
14443 if (parser->
previous.
type == PM_TOKEN_COMMA && parsed_bare_hash) {
14447 }
else if (accept1(parser, PM_TOKEN_COMMA)) {
14450 if (accepted_newline) {
14451 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14457 if (PM_NODE_TYPE_P(argument, PM_CALL_NODE)) {
14460 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14472 if (match1(parser, terminator))
break;
14487parse_required_destructured_parameter(
pm_parser_t *parser) {
14488 expect1(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_ERR_EXPECT_LPAREN_REQ_PARAMETER);
14491 pm_multi_target_node_opening_set(node, &parser->
previous);
14500 if (node->
lefts.
size > 0 && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
14502 pm_multi_target_node_targets_append(parser, node, param);
14503 pm_parser_err_current(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14507 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
14508 param = (
pm_node_t *) parse_required_destructured_parameter(parser);
14509 }
else if (accept1(parser, PM_TOKEN_USTAR)) {
14513 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14515 value = (
pm_node_t *) pm_required_parameter_node_create(parser, &name);
14516 if (pm_parser_parameter_name_check(parser, &name)) {
14517 pm_node_flag_set_repeated_parameter(value);
14519 pm_parser_local_add_token(parser, &name, 1);
14522 param = (
pm_node_t *) pm_splat_node_create(parser, &star, value);
14524 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EXPECT_IDENT_REQ_PARAMETER);
14527 param = (
pm_node_t *) pm_required_parameter_node_create(parser, &name);
14528 if (pm_parser_parameter_name_check(parser, &name)) {
14529 pm_node_flag_set_repeated_parameter(param);
14531 pm_parser_local_add_token(parser, &name, 1);
14534 pm_multi_target_node_targets_append(parser, node, param);
14535 }
while (accept1(parser, PM_TOKEN_COMMA));
14537 accept1(parser, PM_TOKEN_NEWLINE);
14538 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN_REQ_PARAMETER);
14539 pm_multi_target_node_closing_set(node, &parser->
previous);
14549 PM_PARAMETERS_NO_CHANGE = 0,
14550 PM_PARAMETERS_ORDER_NOTHING_AFTER = 1,
14551 PM_PARAMETERS_ORDER_KEYWORDS_REST,
14552 PM_PARAMETERS_ORDER_KEYWORDS,
14553 PM_PARAMETERS_ORDER_REST,
14554 PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14555 PM_PARAMETERS_ORDER_OPTIONAL,
14556 PM_PARAMETERS_ORDER_NAMED,
14557 PM_PARAMETERS_ORDER_NONE,
14558} pm_parameters_order_t;
14563static pm_parameters_order_t parameters_ordering[PM_TOKEN_MAXIMUM] = {
14564 [0] = PM_PARAMETERS_NO_CHANGE,
14565 [PM_TOKEN_UAMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14566 [PM_TOKEN_AMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14567 [PM_TOKEN_UDOT_DOT_DOT] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14568 [PM_TOKEN_IDENTIFIER] = PM_PARAMETERS_ORDER_NAMED,
14569 [PM_TOKEN_PARENTHESIS_LEFT] = PM_PARAMETERS_ORDER_NAMED,
14570 [PM_TOKEN_EQUAL] = PM_PARAMETERS_ORDER_OPTIONAL,
14571 [PM_TOKEN_LABEL] = PM_PARAMETERS_ORDER_KEYWORDS,
14572 [PM_TOKEN_USTAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14573 [PM_TOKEN_STAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14574 [PM_TOKEN_USTAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST,
14575 [PM_TOKEN_STAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST
14587 pm_parameters_order_t state = parameters_ordering[token->type];
14588 if (state == PM_PARAMETERS_NO_CHANGE)
return true;
14592 if (*current == PM_PARAMETERS_ORDER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14593 *current = PM_PARAMETERS_ORDER_AFTER_OPTIONAL;
14595 }
else if (*current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14599 if (token->type == PM_TOKEN_USTAR && *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14600 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_STAR);
14602 }
else if (token->type == PM_TOKEN_UDOT_DOT_DOT && (*current >= PM_PARAMETERS_ORDER_KEYWORDS_REST && *current <= PM_PARAMETERS_ORDER_AFTER_OPTIONAL)) {
14603 pm_parser_err_token(parser, token, *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL ? PM_ERR_PARAMETER_FORWARDING_AFTER_REST : PM_ERR_PARAMETER_ORDER);
14605 }
else if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
14607 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_ORDER);
14611 if (state < *current) *current = state;
14622 if (match1(parser, PM_TOKEN_EQUAL)) {
14623 pm_parser_err_previous(parser, PM_ERR_DEF_ENDLESS_PARAMETERS);
14633 pm_binding_power_t binding_power,
14634 bool uses_parentheses,
14635 bool allows_trailing_comma,
14636 bool allows_forwarding_parameters,
14637 bool accepts_blocks_in_defaults,
14641 pm_do_loop_stack_push(parser,
false);
14644 pm_parameters_order_t order = PM_PARAMETERS_ORDER_NONE;
14647 bool parsing =
true;
14649 switch (parser->
current.type) {
14650 case PM_TOKEN_PARENTHESIS_LEFT: {
14651 update_parameter_state(parser, &parser->
current, &order);
14654 if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14655 pm_parameters_node_requireds_append(params, param);
14657 pm_parameters_node_posts_append(params, param);
14661 case PM_TOKEN_UAMPERSAND:
14662 case PM_TOKEN_AMPERSAND: {
14663 update_parameter_state(parser, &parser->
current, &order);
14664 parser_lex(parser);
14669 bool repeated =
false;
14670 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14672 repeated = pm_parser_parameter_name_check(parser, &name);
14673 pm_parser_local_add_token(parser, &name, 1);
14675 name = not_provided(parser);
14679 if (!uses_parentheses) {
14680 refute_optional_parameter(parser);
14685 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14687 if (params->
block == NULL) {
14688 pm_parameters_node_block_set(params, param);
14690 pm_parser_err_node(parser, (
pm_node_t *) param, PM_ERR_PARAMETER_BLOCK_MULTI);
14691 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14696 case PM_TOKEN_UDOT_DOT_DOT: {
14697 if (!allows_forwarding_parameters) {
14698 pm_parser_err_current(parser, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
14701 bool succeeded = update_parameter_state(parser, &parser->
current, &order);
14702 parser_lex(parser);
14704 if (!uses_parentheses) {
14705 refute_optional_parameter(parser);
14715 pm_parameters_node_posts_append(params, keyword_rest);
14716 if (succeeded) pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD);
14720 pm_parameters_node_keyword_rest_set(params, (
pm_node_t *) param);
14723 case PM_TOKEN_CLASS_VARIABLE:
14724 case PM_TOKEN_IDENTIFIER:
14725 case PM_TOKEN_CONSTANT:
14726 case PM_TOKEN_INSTANCE_VARIABLE:
14727 case PM_TOKEN_GLOBAL_VARIABLE:
14728 case PM_TOKEN_METHOD_NAME: {
14729 parser_lex(parser);
14731 case PM_TOKEN_CONSTANT:
14732 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14734 case PM_TOKEN_INSTANCE_VARIABLE:
14735 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
14737 case PM_TOKEN_GLOBAL_VARIABLE:
14738 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
14740 case PM_TOKEN_CLASS_VARIABLE:
14741 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
14743 case PM_TOKEN_METHOD_NAME:
14744 pm_parser_err_previous(parser, PM_ERR_PARAMETER_METHOD_NAME);
14749 if (parser->
current.type == PM_TOKEN_EQUAL) {
14750 update_parameter_state(parser, &parser->
current, &order);
14752 update_parameter_state(parser, &parser->
previous, &order);
14756 bool repeated = pm_parser_parameter_name_check(parser, &name);
14757 pm_parser_local_add_token(parser, &name, 1);
14759 if (match1(parser, PM_TOKEN_EQUAL)) {
14762 parser_lex(parser);
14767 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14768 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
14769 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14774 pm_node_flag_set_repeated_parameter((
pm_node_t *) param);
14776 pm_parameters_node_optionals_append(params, param);
14782 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, name, PM_ERR_PARAMETER_CIRCULAR);
14785 context_pop(parser);
14794 }
else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14797 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14799 pm_parameters_node_requireds_append(params, (
pm_node_t *) param);
14803 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14805 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14810 case PM_TOKEN_LABEL: {
14811 if (!uses_parentheses && !in_block) parser->
in_keyword_arg =
true;
14812 update_parameter_state(parser, &parser->
current, &order);
14815 parser_lex(parser);
14822 pm_parser_err(parser, local.
start, local.
end, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14823 }
else if (local.
end[-1] ==
'!' || local.
end[-1] ==
'?') {
14824 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
14827 bool repeated = pm_parser_parameter_name_check(parser, &local);
14828 pm_parser_local_add_token(parser, &local, 1);
14830 switch (parser->
current.type) {
14831 case PM_TOKEN_COMMA:
14832 case PM_TOKEN_PARENTHESIS_RIGHT:
14833 case PM_TOKEN_PIPE: {
14834 context_pop(parser);
14836 pm_node_t *param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14838 pm_node_flag_set_repeated_parameter(param);
14841 pm_parameters_node_keywords_append(params, param);
14844 case PM_TOKEN_SEMICOLON:
14845 case PM_TOKEN_NEWLINE: {
14846 context_pop(parser);
14848 if (uses_parentheses) {
14853 pm_node_t *param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14855 pm_node_flag_set_repeated_parameter(param);
14858 pm_parameters_node_keywords_append(params, param);
14864 if (token_begins_expression_p(parser->
current.type)) {
14868 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14869 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT_KW, (uint16_t) (depth + 1));
14870 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14873 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_PARAMETER_CIRCULAR);
14876 param = (
pm_node_t *) pm_optional_keyword_parameter_node_create(parser, &name, value);
14879 param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14883 pm_node_flag_set_repeated_parameter(param);
14886 context_pop(parser);
14887 pm_parameters_node_keywords_append(params, param);
14889 if (!uses_parentheses) {
14890 refute_optional_parameter(parser);
14906 case PM_TOKEN_USTAR:
14907 case PM_TOKEN_STAR: {
14908 update_parameter_state(parser, &parser->
current, &order);
14909 parser_lex(parser);
14913 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 if (!uses_parentheses) {
14925 refute_optional_parameter(parser);
14928 pm_node_t *param = (
pm_node_t *) pm_rest_parameter_node_create(parser, &
operator, &name);
14930 pm_node_flag_set_repeated_parameter(param);
14933 if (params->
rest == NULL) {
14934 pm_parameters_node_rest_set(params, param);
14936 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_SPLAT_MULTI);
14937 pm_parameters_node_posts_append(params, param);
14942 case PM_TOKEN_STAR_STAR:
14943 case PM_TOKEN_USTAR_STAR: {
14944 pm_parameters_order_t previous_order = order;
14945 update_parameter_state(parser, &parser->
current, &order);
14946 parser_lex(parser);
14951 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
14952 if (previous_order <= PM_PARAMETERS_ORDER_KEYWORDS) {
14953 pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_NO_KW);
14956 param = (
pm_node_t *) pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous);
14960 bool repeated =
false;
14961 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14963 repeated = pm_parser_parameter_name_check(parser, &name);
14964 pm_parser_local_add_token(parser, &name, 1);
14966 name = not_provided(parser);
14970 param = (
pm_node_t *) pm_keyword_rest_parameter_node_create(parser, &
operator, &name);
14972 pm_node_flag_set_repeated_parameter(param);
14976 if (!uses_parentheses) {
14977 refute_optional_parameter(parser);
14981 pm_parameters_node_keyword_rest_set(params, param);
14983 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI);
14984 pm_parameters_node_posts_append(params, param);
14991 if (allows_trailing_comma && order >= PM_PARAMETERS_ORDER_NAMED) {
14996 if (params->
rest == NULL) {
14997 pm_parameters_node_rest_set(params, param);
14999 pm_parser_err_node(parser, (
pm_node_t *) param, PM_ERR_PARAMETER_SPLAT_MULTI);
15000 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
15003 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
15014 if (!parsing)
break;
15016 bool accepted_newline =
false;
15017 if (uses_parentheses) {
15018 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
15021 if (accept1(parser, PM_TOKEN_COMMA)) {
15024 if (accepted_newline) {
15025 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
15033 pm_do_loop_stack_pop(parser);
15037 pm_node_destroy(parser, (
pm_node_t *) params);
15069token_column(
const pm_parser_t *parser,
size_t newline_index,
const pm_token_t *token,
bool break_on_non_space) {
15071 const uint8_t *end = token->start;
15075 newline_index == 0 &&
15076 parser->
start[0] == 0xef &&
15077 parser->
start[1] == 0xbb &&
15078 parser->
start[2] == 0xbf
15081 int64_t column = 0;
15082 for (; cursor < end; cursor++) {
15085 column = ((column / PM_TAB_WHITESPACE_SIZE) + 1) * PM_TAB_WHITESPACE_SIZE;
15092 if (break_on_non_space)
return -1;
15105parser_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) {
15110 size_t closing_newline_index = token_newline_index(parser);
15111 if (opening_newline_index == closing_newline_index)
return;
15116 int64_t opening_column = token_column(parser, opening_newline_index, opening_token, !if_after_else);
15117 if (!if_after_else && (opening_column == -1))
return;
15124 int64_t closing_column = token_column(parser, closing_newline_index, closing_token,
true);
15125 if ((closing_column == -1) || (opening_column == closing_column))
return;
15129 if (allow_indent && (closing_column > opening_column))
return;
15132 PM_PARSER_WARN_FORMAT(
15134 closing_token->
start,
15135 closing_token->
end,
15136 PM_WARN_INDENTATION_MISMATCH,
15137 (
int) (closing_token->
end - closing_token->
start),
15138 (
const char *) closing_token->
start,
15139 (
int) (opening_token->
end - opening_token->
start),
15140 (
const char *) opening_token->
start,
15141 ((int32_t) opening_newline_index) + parser->
start_line
15146 PM_RESCUES_BEGIN = 1,
15153} pm_rescues_type_t;
15163 while (match1(parser, PM_TOKEN_KEYWORD_RESCUE)) {
15164 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15165 parser_lex(parser);
15169 switch (parser->
current.type) {
15170 case PM_TOKEN_EQUAL_GREATER: {
15174 parser_lex(parser);
15175 pm_rescue_node_operator_set(rescue, &parser->
previous);
15177 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15178 reference = parse_target(parser, reference,
false,
false);
15180 pm_rescue_node_reference_set(rescue, reference);
15183 case PM_TOKEN_NEWLINE:
15184 case PM_TOKEN_SEMICOLON:
15185 case PM_TOKEN_KEYWORD_THEN:
15190 if (token_begins_expression_p(parser->
current.type) || match1(parser, PM_TOKEN_USTAR)) {
15195 pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED,
false, PM_ERR_RESCUE_EXPRESSION, (uint16_t) (depth + 1));
15196 pm_rescue_node_exceptions_append(rescue, expression);
15200 if (match3(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_THEN))
break;
15204 if (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
15205 pm_rescue_node_operator_set(rescue, &parser->
previous);
15207 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15208 reference = parse_target(parser, reference,
false,
false);
15210 pm_rescue_node_reference_set(rescue, reference);
15213 }
while (accept1(parser, PM_TOKEN_COMMA));
15218 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
15219 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
15223 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_RESCUE_TERM);
15227 if (!match3(parser, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_END)) {
15228 pm_accepts_block_stack_push(parser,
true);
15243 if (statements != NULL) pm_rescue_node_statements_set(rescue, statements);
15245 pm_accepts_block_stack_pop(parser);
15246 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15249 if (current == NULL) {
15250 pm_begin_node_rescue_clause_set(parent_node, rescue);
15252 pm_rescue_node_subsequent_set(current, rescue);
15261 if (current != NULL) {
15265 while (clause != NULL) {
15272 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
15273 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15274 opening_newline_index = token_newline_index(parser);
15276 else_keyword = parser->
current;
15277 opening = &else_keyword;
15279 parser_lex(parser);
15280 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15283 if (!match2(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_ENSURE)) {
15284 pm_accepts_block_stack_push(parser,
true);
15298 else_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15299 pm_accepts_block_stack_pop(parser);
15301 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15304 pm_else_node_t *else_clause = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
current);
15305 pm_begin_node_else_clause_set(parent_node, else_clause);
15309 if (current == NULL) pm_parser_err_node(parser, (
pm_node_t *) else_clause, PM_ERR_BEGIN_LONELY_ELSE);
15312 if (match1(parser, PM_TOKEN_KEYWORD_ENSURE)) {
15313 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15316 parser_lex(parser);
15317 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15320 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
15321 pm_accepts_block_stack_push(parser,
true);
15335 ensure_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15336 pm_accepts_block_stack_pop(parser);
15338 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15341 pm_ensure_node_t *ensure_clause = pm_ensure_node_create(parser, &ensure_keyword, ensure_statements, &parser->
current);
15342 pm_begin_node_ensure_clause_set(parent_node, ensure_clause);
15345 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
15346 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15347 pm_begin_node_end_keyword_set(parent_node, &parser->
current);
15350 pm_begin_node_end_keyword_set(parent_node, &end_keyword);
15360 pm_token_t begin_keyword = not_provided(parser);
15361 pm_begin_node_t *node = pm_begin_node_create(parser, &begin_keyword, statements);
15363 parse_rescues(parser, opening_newline_index, opening, node,
type, (uint16_t) (depth + 1));
15373parse_block_parameters(
15375 bool allows_trailing_comma,
15377 bool is_lambda_literal,
15378 bool accepts_blocks_in_defaults,
15382 if (!match1(parser, PM_TOKEN_SEMICOLON)) {
15383 parameters = parse_parameters(
15385 is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
15387 allows_trailing_comma,
15389 accepts_blocks_in_defaults,
15391 (uint16_t) (depth + 1)
15396 if ((opening->
type != PM_TOKEN_NOT_PROVIDED)) {
15397 accept1(parser, PM_TOKEN_NEWLINE);
15399 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
15401 switch (parser->
current.type) {
15402 case PM_TOKEN_CONSTANT:
15403 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
15404 parser_lex(parser);
15406 case PM_TOKEN_INSTANCE_VARIABLE:
15407 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
15408 parser_lex(parser);
15410 case PM_TOKEN_GLOBAL_VARIABLE:
15411 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
15412 parser_lex(parser);
15414 case PM_TOKEN_CLASS_VARIABLE:
15415 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
15416 parser_lex(parser);
15419 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_BLOCK_PARAM_LOCAL_VARIABLE);
15423 bool repeated = pm_parser_parameter_name_check(parser, &parser->
previous);
15424 pm_parser_local_add_token(parser, &parser->
previous, 1);
15427 if (repeated) pm_node_flag_set_repeated_parameter((
pm_node_t *) local);
15429 pm_block_parameters_node_append_local(block_parameters, local);
15430 }
while (accept1(parser, PM_TOKEN_COMMA));
15434 return block_parameters;
15442outer_scope_using_numbered_parameters_p(
pm_parser_t *parser) {
15444 if (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND)
return true;
15455static const char *
const pm_numbered_parameter_names[] = {
15456 "_1",
"_2",
"_3",
"_4",
"_5",
"_6",
"_7",
"_8",
"_9"
15470 if (parameters != NULL) {
15472 if (implicit_parameters->
size > 0) {
15475 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
15476 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_ORDINARY);
15477 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
15478 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_ORDINARY);
15480 assert(
false &&
"unreachable");
15489 if (implicit_parameters->
size == 0) {
15496 uint8_t numbered_parameter = 0;
15497 bool it_parameter =
false;
15499 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
15502 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
15503 if (it_parameter) {
15504 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_IT);
15505 }
else if (outer_scope_using_numbered_parameters_p(parser)) {
15506 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_OUTER_BLOCK);
15508 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK);
15510 numbered_parameter = MAX(numbered_parameter, (uint8_t) (node->
location.
start[1] -
'0'));
15512 assert(
false &&
"unreachable");
15514 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
15515 if (numbered_parameter > 0) {
15516 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_NUMBERED);
15518 it_parameter =
true;
15523 if (numbered_parameter > 0) {
15527 scope->
parameters |= PM_SCOPE_PARAMETERS_NUMBERED_INNER;
15531 return (
pm_node_t *) pm_numbered_parameters_node_create(parser, &location, numbered_parameter);
15534 if (it_parameter) {
15535 return (
pm_node_t *) pm_it_parameters_node_create(parser, opening, closing);
15545parse_block(
pm_parser_t *parser, uint16_t depth) {
15547 accept1(parser, PM_TOKEN_NEWLINE);
15549 pm_accepts_block_stack_push(parser,
true);
15550 pm_parser_scope_push(parser,
false);
15554 if (accept1(parser, PM_TOKEN_PIPE)) {
15556 if (match1(parser, PM_TOKEN_PIPE)) {
15557 block_parameters = pm_block_parameters_node_create(parser, NULL, &block_parameters_opening);
15559 parser_lex(parser);
15561 block_parameters = parse_block_parameters(parser,
true, &block_parameters_opening,
false,
true, (uint16_t) (depth + 1));
15562 accept1(parser, PM_TOKEN_NEWLINE);
15564 expect1(parser, PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM);
15567 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
15570 accept1(parser, PM_TOKEN_NEWLINE);
15573 if (opening.
type == PM_TOKEN_BRACE_LEFT) {
15574 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
15578 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE);
15580 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
15581 if (!match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE)) {
15582 pm_accepts_block_stack_push(parser,
true);
15584 pm_accepts_block_stack_pop(parser);
15587 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
15588 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
15589 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));
15593 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END);
15597 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
15600 pm_parser_scope_pop(parser);
15601 pm_accepts_block_stack_pop(parser);
15603 return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->
previous);
15612parse_arguments_list(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_block,
bool accepts_command_call, uint16_t depth) {
15613 bool found =
false;
15615 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
15619 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
15622 pm_accepts_block_stack_push(parser,
true);
15623 parse_arguments(parser, arguments, accepts_block, PM_TOKEN_PARENTHESIS_RIGHT, (uint16_t) (depth + 1));
15625 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
15631 pm_accepts_block_stack_pop(parser);
15634 }
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)) {
15636 pm_accepts_block_stack_push(parser,
false);
15641 parse_arguments(parser, arguments, accepts_block, PM_TOKEN_EOF, (uint16_t) (depth + 1));
15646 if (parser->
previous.
type == PM_TOKEN_COMMA && !match1(parser, PM_TOKEN_SEMICOLON)) {
15650 pm_accepts_block_stack_pop(parser);
15656 if (accepts_block) {
15659 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
15661 block = parse_block(parser, (uint16_t) (depth + 1));
15662 pm_arguments_validate_block(parser, arguments, block);
15663 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
15665 block = parse_block(parser, (uint16_t) (depth + 1));
15668 if (block != NULL) {
15672 pm_parser_err_node(parser, (
pm_node_t *) block, PM_ERR_ARGUMENT_BLOCK_MULTI);
15674 if (arguments->
block != NULL) {
15676 arguments->
arguments = pm_arguments_node_create(parser);
15678 pm_arguments_node_arguments_append(arguments->
arguments, arguments->
block);
15694 bool in_sclass =
false;
15696 switch (context_node->
context) {
15741 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15763 assert(
false &&
"unreachable");
15768 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15779 switch (context_node->
context) {
15853 assert(
false &&
"unreachable");
15867 return previous_block_exits;
15881 switch (PM_NODE_TYPE(block_exit)) {
15882 case PM_BREAK_NODE:
type =
"break";
break;
15883 case PM_NEXT_NODE:
type =
"next";
break;
15884 case PM_REDO_NODE:
type =
"redo";
break;
15885 default: assert(
false &&
"unreachable");
type =
"";
break;
15888 PM_PARSER_ERR_NODE_FORMAT(parser, block_exit, PM_ERR_INVALID_BLOCK_EXIT,
type);
15900 if (match2(parser, PM_TOKEN_KEYWORD_WHILE_MODIFIER, PM_TOKEN_KEYWORD_UNTIL_MODIFIER)) {
15905 }
else if (previous_block_exits != NULL) {
15917 flush_block_exits(parser, previous_block_exits);
15925 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, error_id, (uint16_t) (depth + 1));
15928 bool predicate_closed = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15930 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
15931 predicate_closed =
true;
15935 if (!predicate_closed) {
15936 pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
15939 context_pop(parser);
15944parse_conditional(
pm_parser_t *parser,
pm_context_t context,
size_t opening_newline_index,
bool if_after_else, uint16_t depth) {
15946 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
15949 pm_token_t then_keyword = not_provided(parser);
15951 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context, &then_keyword, (uint16_t) (depth + 1));
15954 if (!match3(parser, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
15955 pm_accepts_block_stack_push(parser,
true);
15956 statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15957 pm_accepts_block_stack_pop(parser);
15958 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15961 pm_token_t end_keyword = not_provided(parser);
15966 parent = (
pm_node_t *) pm_if_node_create(parser, &keyword, predicate, &then_keyword, statements, NULL, &end_keyword);
15969 parent = (
pm_node_t *) pm_unless_node_create(parser, &keyword, predicate, &then_keyword, statements);
15972 assert(
false &&
"unreachable");
15981 while (match1(parser, PM_TOKEN_KEYWORD_ELSIF)) {
15982 if (parser_end_of_line_p(parser)) {
15983 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
15986 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15988 parser_lex(parser);
15990 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER,
PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1));
15991 pm_accepts_block_stack_push(parser,
true);
15994 pm_accepts_block_stack_pop(parser);
15995 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15997 pm_node_t *elsif = (
pm_node_t *) pm_if_node_create(parser, &elsif_keyword, predicate, &then_keyword, statements, NULL, &end_keyword);
16003 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
16004 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
16005 opening_newline_index = token_newline_index(parser);
16007 parser_lex(parser);
16010 pm_accepts_block_stack_push(parser,
true);
16012 pm_accepts_block_stack_pop(parser);
16014 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
16015 parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword,
false,
false);
16016 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE);
16018 pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
previous);
16028 assert(
false &&
"unreachable");
16032 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else,
false);
16033 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM);
16040 bool recursing =
true;
16042 while (recursing) {
16043 switch (PM_NODE_TYPE(current)) {
16047 recursing = current != NULL;
16065 assert(
false &&
"unreachable");
16069 pop_block_exits(parser, previous_block_exits);
16070 pm_node_list_free(¤t_block_exits);
16079#define PM_CASE_KEYWORD PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
16080 case PM_TOKEN_KEYWORD_ALIAS: case PM_TOKEN_KEYWORD_AND: case PM_TOKEN_KEYWORD_BEGIN: case PM_TOKEN_KEYWORD_BEGIN_UPCASE: \
16081 case PM_TOKEN_KEYWORD_BREAK: case PM_TOKEN_KEYWORD_CASE: case PM_TOKEN_KEYWORD_CLASS: case PM_TOKEN_KEYWORD_DEF: \
16082 case PM_TOKEN_KEYWORD_DEFINED: case PM_TOKEN_KEYWORD_DO: case PM_TOKEN_KEYWORD_DO_LOOP: case PM_TOKEN_KEYWORD_ELSE: \
16083 case PM_TOKEN_KEYWORD_ELSIF: case PM_TOKEN_KEYWORD_END: case PM_TOKEN_KEYWORD_END_UPCASE: case PM_TOKEN_KEYWORD_ENSURE: \
16084 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD_FOR: case PM_TOKEN_KEYWORD_IF: case PM_TOKEN_KEYWORD_IN: \
16085 case PM_TOKEN_KEYWORD_MODULE: case PM_TOKEN_KEYWORD_NEXT: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_NOT: \
16086 case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_KEYWORD_REDO: case PM_TOKEN_KEYWORD_RESCUE: case PM_TOKEN_KEYWORD_RETRY: \
16087 case PM_TOKEN_KEYWORD_RETURN: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_SUPER: case PM_TOKEN_KEYWORD_THEN: \
16088 case PM_TOKEN_KEYWORD_TRUE: case PM_TOKEN_KEYWORD_UNDEF: case PM_TOKEN_KEYWORD_UNLESS: case PM_TOKEN_KEYWORD_UNTIL: \
16089 case PM_TOKEN_KEYWORD_WHEN: case PM_TOKEN_KEYWORD_WHILE: case PM_TOKEN_KEYWORD_YIELD
16095#define PM_CASE_OPERATOR PM_TOKEN_AMPERSAND: case PM_TOKEN_BACKTICK: case PM_TOKEN_BANG_EQUAL: \
16096 case PM_TOKEN_BANG_TILDE: case PM_TOKEN_BANG: case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL: \
16097 case PM_TOKEN_BRACKET_LEFT_RIGHT: case PM_TOKEN_CARET: case PM_TOKEN_EQUAL_EQUAL_EQUAL: case PM_TOKEN_EQUAL_EQUAL: \
16098 case PM_TOKEN_EQUAL_TILDE: case PM_TOKEN_GREATER_EQUAL: case PM_TOKEN_GREATER_GREATER: case PM_TOKEN_GREATER: \
16099 case PM_TOKEN_LESS_EQUAL_GREATER: case PM_TOKEN_LESS_EQUAL: case PM_TOKEN_LESS_LESS: case PM_TOKEN_LESS: \
16100 case PM_TOKEN_MINUS: case PM_TOKEN_PERCENT: case PM_TOKEN_PIPE: case PM_TOKEN_PLUS: case PM_TOKEN_SLASH: \
16101 case PM_TOKEN_STAR_STAR: case PM_TOKEN_STAR: case PM_TOKEN_TILDE: case PM_TOKEN_UAMPERSAND: case PM_TOKEN_UMINUS: \
16102 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_UPLUS: case PM_TOKEN_USTAR: case PM_TOKEN_USTAR_STAR
16109#define PM_CASE_PRIMITIVE PM_TOKEN_INTEGER: case PM_TOKEN_INTEGER_IMAGINARY: case PM_TOKEN_INTEGER_RATIONAL: \
16110 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: case PM_TOKEN_FLOAT: case PM_TOKEN_FLOAT_IMAGINARY: \
16111 case PM_TOKEN_FLOAT_RATIONAL: case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY: case PM_TOKEN_SYMBOL_BEGIN: \
16112 case PM_TOKEN_REGEXP_BEGIN: case PM_TOKEN_BACKTICK: case PM_TOKEN_PERCENT_LOWER_X: case PM_TOKEN_PERCENT_LOWER_I: \
16113 case PM_TOKEN_PERCENT_LOWER_W: case PM_TOKEN_PERCENT_UPPER_I: case PM_TOKEN_PERCENT_UPPER_W: \
16114 case PM_TOKEN_STRING_BEGIN: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_TRUE: \
16115 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
16116 case PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_MINUS_GREATER: case PM_TOKEN_HEREDOC_START: \
16117 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_CHARACTER_LITERAL
16123#define PM_CASE_PARAMETER PM_TOKEN_UAMPERSAND: case PM_TOKEN_AMPERSAND: case PM_TOKEN_UDOT_DOT_DOT: \
16124 case PM_TOKEN_IDENTIFIER: case PM_TOKEN_LABEL: case PM_TOKEN_USTAR: case PM_TOKEN_STAR: case PM_TOKEN_STAR_STAR: \
16125 case PM_TOKEN_USTAR_STAR: case PM_TOKEN_CONSTANT: case PM_TOKEN_INSTANCE_VARIABLE: case PM_TOKEN_GLOBAL_VARIABLE: \
16126 case PM_TOKEN_CLASS_VARIABLE
16132#define PM_CASE_WRITABLE PM_CLASS_VARIABLE_READ_NODE: case PM_CONSTANT_PATH_NODE: \
16133 case PM_CONSTANT_READ_NODE: case PM_GLOBAL_VARIABLE_READ_NODE: case PM_LOCAL_VARIABLE_READ_NODE: \
16134 case PM_INSTANCE_VARIABLE_READ_NODE: case PM_MULTI_TARGET_NODE: case PM_BACK_REFERENCE_READ_NODE: \
16135 case PM_NUMBERED_REFERENCE_READ_NODE: case PM_IT_LOCAL_VARIABLE_READ_NODE
16139PM_STATIC_ASSERT(__LINE__, ((
int) PM_STRING_FLAGS_FORCED_UTF8_ENCODING) == ((
int) PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING),
"Expected the flags to match.");
16145static inline pm_node_flags_t
16146parse_unescaped_encoding(
const pm_parser_t *parser) {
16151 return PM_STRING_FLAGS_FORCED_UTF8_ENCODING;
16157 return PM_STRING_FLAGS_FORCED_BINARY_ENCODING;
16168parse_string_part(
pm_parser_t *parser, uint16_t depth) {
16169 switch (parser->
current.type) {
16176 case PM_TOKEN_STRING_CONTENT: {
16181 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16183 parser_lex(parser);
16192 case PM_TOKEN_EMBEXPR_BEGIN: {
16201 lex_state_set(parser, PM_LEX_STATE_BEG);
16202 parser_lex(parser);
16207 if (!match1(parser, PM_TOKEN_EMBEXPR_END)) {
16208 pm_accepts_block_stack_push(parser,
true);
16210 pm_accepts_block_stack_pop(parser);
16214 lex_state_set(parser, state);
16216 expect1(parser, PM_TOKEN_EMBEXPR_END, PM_ERR_EMBEXPR_END);
16222 if (statements != NULL && statements->
body.
size == 1) {
16223 pm_node_flag_unset(statements->
body.
nodes[0], PM_NODE_FLAG_NEWLINE);
16226 return (
pm_node_t *) pm_embedded_statements_node_create(parser, &opening, statements, &closing);
16235 case PM_TOKEN_EMBVAR: {
16240 lex_state_set(parser, PM_LEX_STATE_BEG);
16241 parser_lex(parser);
16246 switch (parser->
current.type) {
16249 case PM_TOKEN_BACK_REFERENCE:
16250 parser_lex(parser);
16251 variable = (
pm_node_t *) pm_back_reference_read_node_create(parser, &parser->
previous);
16255 case PM_TOKEN_NUMBERED_REFERENCE:
16256 parser_lex(parser);
16257 variable = (
pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->
previous);
16261 case PM_TOKEN_GLOBAL_VARIABLE:
16262 parser_lex(parser);
16263 variable = (
pm_node_t *) pm_global_variable_read_node_create(parser, &parser->
previous);
16267 case PM_TOKEN_INSTANCE_VARIABLE:
16268 parser_lex(parser);
16269 variable = (
pm_node_t *) pm_instance_variable_read_node_create(parser, &parser->
previous);
16273 case PM_TOKEN_CLASS_VARIABLE:
16274 parser_lex(parser);
16275 variable = (
pm_node_t *) pm_class_variable_read_node_create(parser, &parser->
previous);
16281 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EMBVAR_INVALID);
16286 return (
pm_node_t *) pm_embedded_variable_node_create(parser, &
operator, variable);
16289 parser_lex(parser);
16290 pm_parser_err_previous(parser, PM_ERR_CANNOT_PARSE_STRING_PART);
16300static const uint8_t *
16301parse_operator_symbol_name(
const pm_token_t *name) {
16302 switch (name->
type) {
16303 case PM_TOKEN_TILDE:
16304 case PM_TOKEN_BANG:
16305 if (name->
end[-1] ==
'@')
return name->
end - 1;
16317 const uint8_t *end = parse_operator_symbol_name(&parser->
current);
16319 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16320 parser_lex(parser);
16323 pm_node_flag_set((
pm_node_t *) symbol, PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING);
16337 if (lex_mode->
mode != PM_LEX_STRING) {
16338 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16340 switch (parser->
current.type) {
16341 case PM_CASE_OPERATOR:
16342 return parse_operator_symbol(parser, &opening, next_state == PM_LEX_STATE_NONE ? PM_LEX_STATE_ENDFN : next_state);
16343 case PM_TOKEN_IDENTIFIER:
16344 case PM_TOKEN_CONSTANT:
16345 case PM_TOKEN_INSTANCE_VARIABLE:
16346 case PM_TOKEN_METHOD_NAME:
16347 case PM_TOKEN_CLASS_VARIABLE:
16348 case PM_TOKEN_GLOBAL_VARIABLE:
16349 case PM_TOKEN_NUMBERED_REFERENCE:
16350 case PM_TOKEN_BACK_REFERENCE:
16351 case PM_CASE_KEYWORD:
16352 parser_lex(parser);
16355 expect2(parser, PM_TOKEN_IDENTIFIER, PM_TOKEN_METHOD_NAME, PM_ERR_SYMBOL_INVALID);
16363 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16370 if (match1(parser, PM_TOKEN_STRING_END)) {
16371 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16372 parser_lex(parser);
16376 return (
pm_node_t *) pm_symbol_node_create(parser, &opening, &content, &closing);
16380 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
16384 if (part && PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16385 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16386 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16392 if (part) pm_interpolated_symbol_node_append(symbol, part);
16394 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16395 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16396 pm_interpolated_symbol_node_append(symbol, part);
16400 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16401 if (match1(parser, PM_TOKEN_EOF)) {
16402 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16404 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16407 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
16414 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16417 parser_lex(parser);
16428 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16432 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &unescaped);
16433 pm_interpolated_symbol_node_append(symbol, part);
16436 pm_interpolated_symbol_node_append(symbol, part);
16438 if (next_state != PM_LEX_STATE_NONE) {
16439 lex_state_set(parser, next_state);
16442 parser_lex(parser);
16443 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
16445 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
16450 pm_string_shared_init(&unescaped, content.
start, content.
end);
16453 if (next_state != PM_LEX_STATE_NONE) {
16454 lex_state_set(parser, next_state);
16457 if (match1(parser, PM_TOKEN_EOF)) {
16458 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_DYNAMIC);
16460 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
16463 return (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
false));
16471parse_undef_argument(
pm_parser_t *parser, uint16_t depth) {
16472 switch (parser->
current.type) {
16473 case PM_CASE_OPERATOR: {
16474 const pm_token_t opening = not_provided(parser);
16475 return parse_operator_symbol(parser, &opening, PM_LEX_STATE_NONE);
16477 case PM_CASE_KEYWORD:
16478 case PM_TOKEN_CONSTANT:
16479 case PM_TOKEN_IDENTIFIER:
16480 case PM_TOKEN_METHOD_NAME: {
16481 parser_lex(parser);
16488 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16492 case PM_TOKEN_SYMBOL_BEGIN: {
16494 parser_lex(parser);
16496 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16499 pm_parser_err_current(parser, PM_ERR_UNDEF_ARGUMENT);
16511parse_alias_argument(
pm_parser_t *parser,
bool first, uint16_t depth) {
16512 switch (parser->
current.type) {
16513 case PM_CASE_OPERATOR: {
16514 const pm_token_t opening = not_provided(parser);
16515 return parse_operator_symbol(parser, &opening, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
16517 case PM_CASE_KEYWORD:
16518 case PM_TOKEN_CONSTANT:
16519 case PM_TOKEN_IDENTIFIER:
16520 case PM_TOKEN_METHOD_NAME: {
16521 if (first) lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
16522 parser_lex(parser);
16529 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16533 case PM_TOKEN_SYMBOL_BEGIN: {
16535 parser_lex(parser);
16537 return parse_symbol(parser, &lex_mode, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16539 case PM_TOKEN_BACK_REFERENCE:
16540 parser_lex(parser);
16541 return (
pm_node_t *) pm_back_reference_read_node_create(parser, &parser->
previous);
16542 case PM_TOKEN_NUMBERED_REFERENCE:
16543 parser_lex(parser);
16544 return (
pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->
previous);
16545 case PM_TOKEN_GLOBAL_VARIABLE:
16546 parser_lex(parser);
16547 return (
pm_node_t *) pm_global_variable_read_node_create(parser, &parser->
previous);
16549 pm_parser_err_current(parser, PM_ERR_ALIAS_ARGUMENT);
16564 if (!is_numbered_param && ((depth = pm_parser_local_depth_constant_id(parser, name_id)) != -1)) {
16565 return (
pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, (uint32_t) depth,
false);
16569 if (!current_scope->
closed && !(current_scope->
parameters & PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED)) {
16570 if (is_numbered_param) {
16575 uint8_t maximum = (uint8_t) (parser->
previous.
start[1] -
'0');
16576 for (uint8_t number = 1; number <= maximum; number++) {
16577 pm_parser_local_add_constant(parser, pm_numbered_parameter_names[number - 1], 2);
16580 if (!match1(parser, PM_TOKEN_EQUAL)) {
16584 pm_node_t *node = (
pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, 0,
false);
16604 pm_node_flags_t flags = 0;
16606 if (!match1(parser, PM_TOKEN_PARENTHESIS_LEFT) && (parser->
previous.
end[-1] !=
'!') && (parser->
previous.
end[-1] !=
'?')) {
16607 pm_node_t *node = parse_variable(parser);
16608 if (node != NULL)
return node;
16609 flags |= PM_CALL_NODE_FLAGS_VARIABLE_CALL;
16613 pm_node_flag_set((
pm_node_t *)node, flags);
16624parse_method_definition_name(
pm_parser_t *parser) {
16625 switch (parser->
current.type) {
16626 case PM_CASE_KEYWORD:
16627 case PM_TOKEN_CONSTANT:
16628 case PM_TOKEN_METHOD_NAME:
16629 parser_lex(parser);
16631 case PM_TOKEN_IDENTIFIER:
16632 pm_refute_numbered_parameter(parser, parser->
current.start, parser->
current.end);
16633 parser_lex(parser);
16635 case PM_CASE_OPERATOR:
16636 lex_state_set(parser, PM_LEX_STATE_ENDFN);
16637 parser_lex(parser);
16646parse_heredoc_dedent_string(
pm_string_t *
string,
size_t common_whitespace) {
16649 pm_string_ensure_owned(
string);
16655 const uint8_t *source_cursor = (uint8_t *) string->
source;
16656 const uint8_t *source_end = source_cursor + dest_length;
16661 size_t trimmed_whitespace = 0;
16667 while ((source_cursor < source_end) && pm_char_is_inline_whitespace(*source_cursor) && trimmed_whitespace < common_whitespace) {
16668 if (*source_cursor ==
'\t') {
16669 trimmed_whitespace = (trimmed_whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
16670 if (trimmed_whitespace > common_whitespace)
break;
16672 trimmed_whitespace++;
16679 memmove((uint8_t *) string->source, source_cursor, (
size_t) (source_end - source_cursor));
16680 string->length = dest_length;
16690 bool dedent_next =
true;
16695 size_t write_index = 0;
16702 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE)) {
16703 nodes->
nodes[write_index++] = node;
16704 dedent_next =
false;
16710 parse_heredoc_dedent_string(&string_node->
unescaped, common_whitespace);
16714 pm_node_destroy(parser, node);
16716 nodes->
nodes[write_index++] = node;
16720 dedent_next =
true;
16723 nodes->
size = write_index;
16730parse_strings_empty_content(
const uint8_t *location) {
16731 return (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = location, .end = location };
16739 assert(parser->
current.type == PM_TOKEN_STRING_BEGIN);
16740 bool concating =
false;
16742 while (match1(parser, PM_TOKEN_STRING_BEGIN)) {
16748 assert(lex_mode->
mode == PM_LEX_STRING);
16750 bool label_allowed = lex_mode->
as.string.
label_allowed && accepts_label;
16753 parser_lex(parser);
16755 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16756 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16765 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16775 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16776 }
else if (!lex_interpolation) {
16782 if (match1(parser, PM_TOKEN_EOF)) {
16784 content = not_provided(parser);
16787 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_EXPECT_STRING_CONTENT);
16802 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16805 pm_token_t delimiters = not_provided(parser);
16806 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &delimiters, &content, &delimiters, &unescaped);
16807 pm_node_list_append(&parts, part);
16810 part = (
pm_node_t *) pm_string_node_create_current_string(parser, &delimiters, &parser->
current, &delimiters);
16811 pm_node_list_append(&parts, part);
16812 parser_lex(parser);
16813 }
while (match1(parser, PM_TOKEN_STRING_CONTENT));
16815 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16816 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16818 pm_node_list_free(&parts);
16819 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16820 node = (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true));
16821 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16822 }
else if (match1(parser, PM_TOKEN_EOF)) {
16823 pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
16824 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
16825 }
else if (accept1(parser, PM_TOKEN_STRING_END)) {
16826 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped);
16831 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped);
16833 }
else if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16840 parser_lex(parser);
16842 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16843 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
16844 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16850 if (!accept1(parser, PM_TOKEN_STRING_END)) {
16852 if (location > parser->
start && location[-1] ==
'\n') location--;
16853 pm_parser_err(parser, location, location, PM_ERR_STRING_LITERAL_EOF);
16858 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16859 node = (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true));
16860 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16865 pm_token_t string_opening = not_provided(parser);
16866 pm_token_t string_closing = not_provided(parser);
16868 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &string_opening, &parser->
previous, &string_closing, &unescaped);
16869 pm_node_flag_set(part, parse_unescaped_encoding(parser));
16870 pm_node_list_append(&parts, part);
16872 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16873 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16874 pm_node_list_append(&parts, part);
16878 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16879 node = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous);
16880 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16881 }
else if (match1(parser, PM_TOKEN_EOF)) {
16882 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16883 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current);
16885 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16886 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16889 pm_node_list_free(&parts);
16898 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16899 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16900 pm_node_list_append(&parts, part);
16904 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16905 node = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous);
16906 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16907 }
else if (match1(parser, PM_TOKEN_EOF)) {
16908 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16909 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current);
16911 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16912 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16915 pm_node_list_free(&parts);
16918 if (current == NULL) {
16922 if (PM_NODE_TYPE_P(node, PM_SYMBOL_NODE) || PM_NODE_TYPE_P(node, PM_INTERPOLATED_SYMBOL_NODE)) {
16933 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE) && !PM_NODE_TYPE_P(node, PM_INTERPOLATED_STRING_NODE)) {
16934 pm_parser_err_node(parser, node, PM_ERR_STRING_CONCATENATION);
16940 if (!PM_NODE_TYPE_P(current, PM_STRING_NODE) && !PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
16941 pm_parser_err_node(parser, current, PM_ERR_STRING_CONCATENATION);
16948 pm_interpolated_string_node_append(container, current);
16959#define PM_PARSE_PATTERN_SINGLE 0
16960#define PM_PARSE_PATTERN_TOP 1
16961#define PM_PARSE_PATTERN_MULTI 2
16974 if (*location->
start ==
'_')
return;
16976 if (pm_constant_id_list_includes(captures, capture)) {
16977 pm_parser_err(parser, location->
start, location->
end, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
16979 pm_constant_id_list_append(captures, capture);
16990 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
16992 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
16993 node = (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
16999 if (!match2(parser, PM_TOKEN_BRACKET_LEFT, PM_TOKEN_PARENTHESIS_LEFT)) {
17007 if (accept1(parser, PM_TOKEN_BRACKET_LEFT)) {
17009 accept1(parser, PM_TOKEN_NEWLINE);
17011 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17012 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
17013 accept1(parser, PM_TOKEN_NEWLINE);
17014 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET);
17019 parser_lex(parser);
17021 accept1(parser, PM_TOKEN_NEWLINE);
17023 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
17024 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
17025 accept1(parser, PM_TOKEN_NEWLINE);
17026 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
17035 return (
pm_node_t *) pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
17042 switch (PM_NODE_TYPE(inner)) {
17043 case PM_ARRAY_PATTERN_NODE: {
17051 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17052 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17059 case PM_FIND_PATTERN_NODE: {
17067 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17068 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17075 case PM_HASH_PATTERN_NODE: {
17083 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17084 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17098 pm_array_pattern_node_t *pattern_node = pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
17099 pm_array_pattern_node_requireds_append(pattern_node, inner);
17115 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
17117 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &identifier);
17120 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17121 pm_parser_local_add(parser, constant_id, identifier.
start, identifier.
end, 0);
17124 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&identifier));
17125 name = (
pm_node_t *) pm_local_variable_target_node_create(
17127 &PM_LOCATION_TOKEN_VALUE(&identifier),
17129 (uint32_t) (depth == -1 ? 0 : depth)
17134 return pm_splat_node_create(parser, &
operator, name);
17142 assert(parser->
current.type == PM_TOKEN_USTAR_STAR);
17143 parser_lex(parser);
17148 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
17149 return (
pm_node_t *) pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous);
17152 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
17156 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17160 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17161 value = (
pm_node_t *) pm_local_variable_target_node_create(
17163 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17165 (uint32_t) (depth == -1 ? 0 : depth)
17169 return (
pm_node_t *) pm_assoc_splat_node_create(parser, value, &
operator);
17177pm_slice_is_valid_local(
const pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
17178 ptrdiff_t length = end - start;
17179 if (length == 0)
return false;
17182 size_t width = char_is_identifier_start(parser, start, end - start);
17183 if (width == 0)
return false;
17189 if (pm_encoding_utf_8_isupper_char(start, length))
return false;
17194 const uint8_t *cursor = start + width;
17195 while ((width = char_is_identifier(parser, cursor, end - cursor))) cursor += width;
17196 return cursor == end;
17210 if (pm_slice_is_valid_local(parser, value_loc->
start, value_loc->
end)) {
17211 depth = pm_parser_local_depth_constant_id(parser, constant_id);
17213 pm_parser_err(parser, key->base.location.start, key->base.location.end, PM_ERR_PATTERN_HASH_KEY_LOCALS);
17215 if ((value_loc->
end > value_loc->
start) && ((value_loc->
end[-1] ==
'!') || (value_loc->
end[-1] ==
'?'))) {
17216 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);
17221 pm_parser_local_add(parser, constant_id, value_loc->
start, value_loc->
end, 0);
17224 parse_pattern_capture(parser, captures, constant_id, value_loc);
17229 (uint32_t) (depth == -1 ? 0 : depth)
17242 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
17255 switch (PM_NODE_TYPE(first_node)) {
17256 case PM_ASSOC_SPLAT_NODE:
17257 case PM_NO_KEYWORDS_PARAMETER_NODE:
17260 case PM_SYMBOL_NODE: {
17261 if (pm_symbol_node_label_p(first_node)) {
17262 parse_pattern_hash_key(parser, &keys, first_node);
17265 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)) {
17268 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) first_node);
17272 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17276 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, first_node, &
operator, value);
17278 pm_node_list_append(&assocs, assoc);
17287 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;
17288 pm_parser_err_node(parser, first_node, diag_id);
17292 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, first_node, &
operator, value);
17294 pm_node_list_append(&assocs, assoc);
17300 while (accept1(parser, PM_TOKEN_COMMA)) {
17302 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)) {
17304 if (rest != NULL) {
17305 pm_parser_err_token(parser, &parser->
current, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17311 if (match1(parser, PM_TOKEN_USTAR_STAR)) {
17312 pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures);
17314 if (rest == NULL) {
17317 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17318 pm_node_list_append(&assocs, assoc);
17323 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
17324 key = parse_strings(parser, NULL,
true, (uint16_t) (depth + 1));
17326 if (PM_NODE_TYPE_P(key, PM_INTERPOLATED_SYMBOL_NODE)) {
17327 pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
17328 }
else if (!pm_symbol_node_label_p(key)) {
17329 pm_parser_err_node(parser, key, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17332 expect1(parser, PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17336 parse_pattern_hash_key(parser, &keys, key);
17339 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)) {
17340 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) key);
17342 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17346 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
17348 if (rest != NULL) {
17349 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17352 pm_node_list_append(&assocs, assoc);
17359 pm_static_literals_free(&keys);
17368 switch (parser->
current.type) {
17369 case PM_TOKEN_IDENTIFIER:
17370 case PM_TOKEN_METHOD_NAME: {
17371 parser_lex(parser);
17375 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17379 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17380 return (
pm_node_t *) pm_local_variable_target_node_create(
17382 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17384 (uint32_t) (depth == -1 ? 0 : depth)
17387 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
17389 parser_lex(parser);
17391 if (accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17394 return (
pm_node_t *) pm_array_pattern_node_empty_create(parser, &opening, &parser->
previous);
17399 pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
17401 accept1(parser, PM_TOKEN_NEWLINE);
17402 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET);
17405 switch (PM_NODE_TYPE(inner)) {
17406 case PM_ARRAY_PATTERN_NODE: {
17412 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17413 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17420 case PM_FIND_PATTERN_NODE: {
17426 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17427 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17439 pm_array_pattern_node_requireds_append(node, inner);
17442 case PM_TOKEN_BRACE_LEFT: {
17448 parser_lex(parser);
17450 if (accept1(parser, PM_TOKEN_BRACE_RIGHT)) {
17453 node = pm_hash_pattern_node_empty_create(parser, &opening, &parser->
previous);
17457 switch (parser->
current.type) {
17458 case PM_TOKEN_LABEL:
17459 parser_lex(parser);
17460 first_node = (
pm_node_t *) pm_symbol_node_label_create(parser, &parser->
previous);
17462 case PM_TOKEN_USTAR_STAR:
17463 first_node = parse_pattern_keyword_rest(parser, captures);
17465 case PM_TOKEN_STRING_BEGIN:
17466 first_node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, PM_ERR_PATTERN_HASH_KEY_LABEL, (uint16_t) (depth + 1));
17470 parser_lex(parser);
17477 node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
17479 accept1(parser, PM_TOKEN_NEWLINE);
17480 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE);
17486 node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17487 node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17493 case PM_TOKEN_UDOT_DOT:
17494 case PM_TOKEN_UDOT_DOT_DOT: {
17496 parser_lex(parser);
17500 switch (parser->
current.type) {
17501 case PM_CASE_PRIMITIVE: {
17502 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
17503 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
17506 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
17507 pm_node_t *right = (
pm_node_t *) pm_missing_node_create(parser,
operator.start,
operator.end);
17508 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
17512 case PM_CASE_PRIMITIVE: {
17513 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, diag_id, (uint16_t) (depth + 1));
17516 if (pm_symbol_node_label_p(node))
return node;
17519 if (PM_NODE_TYPE(node) == PM_CALL_NODE) {
17520 pm_parser_err_node(parser, node, diag_id);
17522 pm_node_destroy(parser, node);
17527 if (accept2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
17533 switch (parser->
current.type) {
17534 case PM_CASE_PRIMITIVE: {
17535 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
17536 return (
pm_node_t *) pm_range_node_create(parser, node, &
operator, right);
17539 return (
pm_node_t *) pm_range_node_create(parser, node, &
operator, NULL);
17545 case PM_TOKEN_CARET: {
17546 parser_lex(parser);
17551 switch (parser->
current.type) {
17552 case PM_TOKEN_IDENTIFIER: {
17553 parser_lex(parser);
17556 if (variable == NULL) {
17557 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
previous, PM_ERR_NO_LOCAL_VARIABLE);
17558 variable = (
pm_node_t *) pm_local_variable_read_node_missing_create(parser, &parser->
previous, 0);
17561 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17563 case PM_TOKEN_INSTANCE_VARIABLE: {
17564 parser_lex(parser);
17567 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17569 case PM_TOKEN_CLASS_VARIABLE: {
17570 parser_lex(parser);
17573 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17575 case PM_TOKEN_GLOBAL_VARIABLE: {
17576 parser_lex(parser);
17579 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17581 case PM_TOKEN_NUMBERED_REFERENCE: {
17582 parser_lex(parser);
17585 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17587 case PM_TOKEN_BACK_REFERENCE: {
17588 parser_lex(parser);
17591 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17593 case PM_TOKEN_PARENTHESIS_LEFT: {
17598 parser_lex(parser);
17600 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN, (uint16_t) (depth + 1));
17603 accept1(parser, PM_TOKEN_NEWLINE);
17604 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
17605 return (
pm_node_t *) pm_pinned_expression_node_create(parser, expression, &
operator, &lparen, &parser->
previous);
17610 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
17611 pm_node_t *variable = (
pm_node_t *) pm_missing_node_create(parser,
operator.start,
operator.end);
17612 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17616 case PM_TOKEN_UCOLON_COLON: {
17618 parser_lex(parser);
17620 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
17623 return parse_pattern_constant_path(parser, captures, (
pm_node_t *) node, (uint16_t) (depth + 1));
17625 case PM_TOKEN_CONSTANT: {
17627 parser_lex(parser);
17630 return parse_pattern_constant_path(parser, captures, node, (uint16_t) (depth + 1));
17633 pm_parser_err_current(parser, diag_id);
17646 while ((node == NULL) || accept1(parser, PM_TOKEN_PIPE)) {
17649 switch (parser->
current.type) {
17650 case PM_TOKEN_IDENTIFIER:
17651 case PM_TOKEN_BRACKET_LEFT_ARRAY:
17652 case PM_TOKEN_BRACE_LEFT:
17653 case PM_TOKEN_CARET:
17654 case PM_TOKEN_CONSTANT:
17655 case PM_TOKEN_UCOLON_COLON:
17656 case PM_TOKEN_UDOT_DOT:
17657 case PM_TOKEN_UDOT_DOT_DOT:
17658 case PM_CASE_PRIMITIVE: {
17659 if (node == NULL) {
17660 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17662 pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
17663 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17668 case PM_TOKEN_PARENTHESIS_LEFT:
17669 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
17671 parser_lex(parser);
17673 pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
17674 accept1(parser, PM_TOKEN_NEWLINE);
17675 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
17678 if (node == NULL) {
17681 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17687 pm_parser_err_current(parser, diag_id);
17690 if (node == NULL) {
17693 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17703 while (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
17705 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_PATTERN_IDENT_AFTER_HROCKET);
17710 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17714 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17717 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17719 (uint32_t) (depth == -1 ? 0 : depth)
17722 node = (
pm_node_t *) pm_capture_pattern_node_create(parser, node, target, &
operator);
17735 bool leading_rest =
false;
17736 bool trailing_rest =
false;
17738 switch (parser->
current.type) {
17739 case PM_TOKEN_LABEL: {
17740 parser_lex(parser);
17742 node = (
pm_node_t *) parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1));
17744 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17745 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17750 case PM_TOKEN_USTAR_STAR: {
17751 node = parse_pattern_keyword_rest(parser, captures);
17752 node = (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17754 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17755 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17760 case PM_TOKEN_STRING_BEGIN: {
17763 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17765 if (pm_symbol_node_label_p(node)) {
17766 node = (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17768 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17769 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17775 node = parse_pattern_primitives(parser, captures, node, diag_id, (uint16_t) (depth + 1));
17778 case PM_TOKEN_USTAR: {
17779 if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
17780 parser_lex(parser);
17781 node = (
pm_node_t *) parse_pattern_rest(parser, captures);
17782 leading_rest =
true;
17788 node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1));
17794 if (pm_symbol_node_label_p(node)) {
17795 return (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17798 if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser, PM_TOKEN_COMMA)) {
17803 pm_node_list_append(&nodes, node);
17806 while (accept1(parser, PM_TOKEN_COMMA)) {
17808 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)) {
17810 pm_node_list_append(&nodes, node);
17811 trailing_rest =
true;
17815 if (accept1(parser, PM_TOKEN_USTAR)) {
17816 node = (
pm_node_t *) parse_pattern_rest(parser, captures);
17821 if (trailing_rest) {
17822 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
17825 trailing_rest =
true;
17827 node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
17830 pm_node_list_append(&nodes, node);
17837 if (leading_rest && PM_NODE_TYPE_P(nodes.
nodes[nodes.
size - 1], PM_SPLAT_NODE)) {
17838 node = (
pm_node_t *) pm_find_pattern_node_create(parser, &nodes);
17840 if (nodes.
size == 2) {
17841 pm_parser_err_node(parser, node, PM_ERR_PATTERN_FIND_MISSING_INNER);
17844 node = (
pm_node_t *) pm_array_pattern_node_node_list_create(parser, &nodes);
17846 if (leading_rest && trailing_rest) {
17847 pm_parser_err_node(parser, node, PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS);
17852 }
else if (leading_rest) {
17855 node = (
pm_node_t *) pm_array_pattern_node_rest_create(parser, node);
17867parse_negative_numeric(
pm_node_t *node) {
17868 switch (PM_NODE_TYPE(node)) {
17869 case PM_INTEGER_NODE: {
17875 case PM_FLOAT_NODE: {
17881 case PM_RATIONAL_NODE: {
17887 case PM_IMAGINARY_NODE:
17892 assert(
false &&
"unreachable");
17905 case PM_ERR_HASH_KEY: {
17909 case PM_ERR_HASH_VALUE:
17910 case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: {
17914 case PM_ERR_UNARY_RECEIVER: {
17919 case PM_ERR_UNARY_DISALLOWED:
17920 case PM_ERR_EXPECT_ARGUMENT: {
17925 pm_parser_err_previous(parser, diag_id);
17935#define CONTEXT_NONE 0
17936#define CONTEXT_THROUGH_ENSURE 1
17937#define CONTEXT_THROUGH_ELSE 2
17940 int context = CONTEXT_NONE;
17942 while (context_node != NULL) {
17943 switch (context_node->
context) {
17964 if (context == CONTEXT_NONE) {
17965 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_WITHOUT_RESCUE);
17966 }
else if (context == CONTEXT_THROUGH_ENSURE) {
17967 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ENSURE);
17968 }
else if (context == CONTEXT_THROUGH_ELSE) {
17969 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ELSE);
17981 context = CONTEXT_THROUGH_ELSE;
17992 context = CONTEXT_THROUGH_ENSURE;
17996 assert(
false &&
"unreachable");
18026 context_node = context_node->
prev;
18030#undef CONTEXT_ENSURE
18041 while (context_node != NULL) {
18042 switch (context_node->
context) {
18067 pm_parser_err_node(parser, node, PM_ERR_INVALID_YIELD);
18071 assert(
false &&
"unreachable");
18112 context_node = context_node->
prev;
18144parse_regular_expression_error(
const uint8_t *start,
const uint8_t *end,
const char *message,
void *data) {
18148 if (callback_data->
shared) {
18154 PM_PARSER_ERR_FORMAT(callback_data->
parser, location.
start, location.
end, PM_ERR_REGEXP_PARSE_ERROR, message);
18167 .shared = unescaped->
type == PM_STRING_SHARED
18170 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);
18177parse_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) {
18178 switch (parser->
current.type) {
18179 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
18180 parser_lex(parser);
18183 pm_accepts_block_stack_push(parser,
true);
18184 bool parsed_bare_hash =
false;
18186 while (!match2(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_EOF)) {
18187 bool accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
18191 if (accepted_newline && match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
18197 if (accept1(parser, PM_TOKEN_COMMA)) {
18200 if (accepted_newline) {
18201 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
18217 if (match1(parser, PM_TOKEN_BRACKET_RIGHT))
break;
18221 if (accept1(parser, PM_TOKEN_USTAR)) {
18225 if (match3(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_EOF)) {
18226 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
18228 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
18231 element = (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
18232 }
else if (match2(parser, PM_TOKEN_LABEL, PM_TOKEN_USTAR_STAR)) {
18233 if (parsed_bare_hash) {
18234 pm_parser_err_current(parser, PM_ERR_EXPRESSION_BARE_HASH);
18237 element = (
pm_node_t *) pm_keyword_hash_node_create(parser);
18240 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)) {
18241 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
18244 pm_static_literals_free(&hash_keys);
18245 parsed_bare_hash =
true;
18247 element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_ARRAY_EXPRESSION, (uint16_t) (depth + 1));
18249 if (pm_symbol_node_label_p(element) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
18250 if (parsed_bare_hash) {
18251 pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
18256 pm_hash_key_static_literals_add(parser, &hash_keys, element);
18259 if (parser->
previous.
type == PM_TOKEN_EQUAL_GREATER) {
18262 operator = not_provided(parser);
18265 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
18266 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, element, &
operator, value);
18267 pm_keyword_hash_node_elements_append(hash, assoc);
18270 if (accept1(parser, PM_TOKEN_COMMA) && !match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
18271 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
18274 pm_static_literals_free(&hash_keys);
18275 parsed_bare_hash =
true;
18279 pm_array_node_elements_append(array, element);
18280 if (PM_NODE_TYPE_P(element, PM_MISSING_NODE))
break;
18283 accept1(parser, PM_TOKEN_NEWLINE);
18285 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
18291 pm_array_node_close_set(array, &parser->
previous);
18292 pm_accepts_block_stack_pop(parser);
18296 case PM_TOKEN_PARENTHESIS_LEFT:
18297 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
18299 pm_node_flags_t flags = 0;
18302 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18304 parser_lex(parser);
18306 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
18307 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
18308 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
18315 if (match2(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_EOF)) {
18316 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
18318 pop_block_exits(parser, previous_block_exits);
18319 pm_node_list_free(¤t_block_exits);
18321 return (
pm_node_t *) pm_parentheses_node_create(parser, &opening, NULL, &parser->
previous, flags);
18326 pm_accepts_block_stack_push(parser,
true);
18328 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
18329 context_pop(parser);
18334 bool terminator_found =
false;
18336 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
18337 terminator_found =
true;
18338 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
18339 }
else if (accept1(parser, PM_TOKEN_NEWLINE)) {
18340 terminator_found =
true;
18343 if (terminator_found) {
18345 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
18346 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
18347 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
18356 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18357 if (opening.
type == PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
18358 lex_state_set(parser, PM_LEX_STATE_ENDARG);
18361 parser_lex(parser);
18362 pm_accepts_block_stack_pop(parser);
18364 pop_block_exits(parser, previous_block_exits);
18365 pm_node_list_free(¤t_block_exits);
18367 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) || PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
18373 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) && ((
pm_multi_target_node_t *) statement)->lparen_loc.start == NULL) {
18376 multi_target = pm_multi_target_node_create(parser);
18377 pm_multi_target_node_targets_append(parser, multi_target, statement);
18380 pm_location_t lparen_loc = PM_LOCATION_TOKEN_VALUE(&opening);
18389 if (match1(parser, PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
18390 result = parse_targets(parser, (
pm_node_t *) multi_target, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18391 accept1(parser, PM_TOKEN_NEWLINE);
18402 }
else if (binding_power != PM_BINDING_POWER_STATEMENT) {
18405 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
18406 }
else if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
18410 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
18420 pm_statements_node_body_append(parser, statements, statement,
true);
18429 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
18432 pm_statements_node_body_append(parser, statements, statement,
true);
18436 if (!terminator_found && !match1(parser, PM_TOKEN_EOF)) {
18442 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
18443 pm_statements_node_body_append(parser, statements, node,
true);
18450 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) parser->
recovering =
false;
18456 if (PM_NODE_TYPE_P(node, PM_MISSING_NODE))
break;
18460 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18461 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18462 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
break;
18463 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18465 }
else if (!match1(parser, PM_TOKEN_EOF)) {
18472 context_pop(parser);
18473 pm_accepts_block_stack_pop(parser);
18474 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
18483 if (PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
18485 pm_multi_target_node_targets_append(parser, multi_target, statement);
18487 statement = (
pm_node_t *) multi_target;
18491 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE)) {
18493 pm_token_t operator = { .
type = PM_TOKEN_EQUAL, .start = offset, .end = offset };
18499 pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
18503 pop_block_exits(parser, previous_block_exits);
18504 pm_node_list_free(¤t_block_exits);
18506 pm_void_statements_check(parser, statements,
true);
18509 case PM_TOKEN_BRACE_LEFT: {
18520 pm_accepts_block_stack_push(parser,
true);
18521 parser_lex(parser);
18525 if (!match2(parser, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_EOF)) {
18526 if (current_hash_keys != NULL) {
18527 parse_assocs(parser, current_hash_keys, (
pm_node_t *) node, (uint16_t) (depth + 1));
18530 parse_assocs(parser, &hash_keys, (
pm_node_t *) node, (uint16_t) (depth + 1));
18531 pm_static_literals_free(&hash_keys);
18534 accept1(parser, PM_TOKEN_NEWLINE);
18537 pm_accepts_block_stack_pop(parser);
18538 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM);
18539 pm_hash_node_closing_loc_set(node, &parser->
previous);
18543 case PM_TOKEN_CHARACTER_LITERAL: {
18548 .type = PM_TOKEN_STRING_BEGIN,
18549 .start = parser->
current.start,
18550 .end = parser->
current.start + 1
18553 .type = PM_TOKEN_STRING_CONTENT,
18554 .start = parser->
current.start + 1,
18560 pm_node_flag_set(node, parse_unescaped_encoding(parser));
18564 parser_lex(parser);
18568 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
18569 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18574 case PM_TOKEN_CLASS_VARIABLE: {
18575 parser_lex(parser);
18578 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18579 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18584 case PM_TOKEN_CONSTANT: {
18585 parser_lex(parser);
18591 match1(parser, PM_TOKEN_PARENTHESIS_LEFT) ||
18592 (accepts_command_call && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
18593 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
18594 match1(parser, PM_TOKEN_BRACE_LEFT)
18597 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18598 return (
pm_node_t *) pm_call_node_fcall_create(parser, &constant, &arguments);
18603 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
18606 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18611 case PM_TOKEN_UCOLON_COLON: {
18612 parser_lex(parser);
18615 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
18618 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
18619 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18624 case PM_TOKEN_UDOT_DOT:
18625 case PM_TOKEN_UDOT_DOT_DOT: {
18627 parser_lex(parser);
18629 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));
18635 if (match2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
18636 pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
18639 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
18641 case PM_TOKEN_FLOAT:
18642 parser_lex(parser);
18644 case PM_TOKEN_FLOAT_IMAGINARY:
18645 parser_lex(parser);
18646 return (
pm_node_t *) pm_float_node_imaginary_create(parser, &parser->
previous);
18647 case PM_TOKEN_FLOAT_RATIONAL:
18648 parser_lex(parser);
18650 case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY:
18651 parser_lex(parser);
18652 return (
pm_node_t *) pm_float_node_rational_imaginary_create(parser, &parser->
previous);
18653 case PM_TOKEN_NUMBERED_REFERENCE: {
18654 parser_lex(parser);
18657 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18658 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18663 case PM_TOKEN_GLOBAL_VARIABLE: {
18664 parser_lex(parser);
18667 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18668 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18673 case PM_TOKEN_BACK_REFERENCE: {
18674 parser_lex(parser);
18677 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18678 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18683 case PM_TOKEN_IDENTIFIER:
18684 case PM_TOKEN_METHOD_NAME: {
18685 parser_lex(parser);
18687 pm_node_t *node = parse_variable_call(parser);
18689 if (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
18697 if (parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1))) {
18700 pm_node_flag_unset((
pm_node_t *)call, PM_CALL_NODE_FLAGS_VARIABLE_CALL);
18707 const uint8_t *end = pm_arguments_end(&arguments);
18718 (accepts_command_call && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
18719 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
18720 match1(parser, PM_TOKEN_BRACE_LEFT)
18723 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18724 pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
18726 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
18730 parse_target_implicit_parameter(parser, node);
18736 assert(PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE));
18738 if (pm_token_is_numbered_parameter(identifier.
start, identifier.
end)) {
18739 parse_target_implicit_parameter(parser, node);
18742 pm_locals_unread(&pm_parser_scope_find(parser, cast->
depth)->
locals, cast->
name);
18746 pm_node_destroy(parser, node);
18751 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
18752 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18757 case PM_TOKEN_HEREDOC_START: {
18763 size_t common_whitespace = (size_t) -1;
18766 parser_lex(parser);
18772 if (match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18778 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18785 }
else if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) == NULL) {
18793 }
else if (PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18798 pm_node_flag_set(part, parse_unescaped_encoding(parser));
18801 cast->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
18805 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18807 cast->
base.
type = PM_X_STRING_NODE;
18810 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18811 parse_heredoc_dedent_string(&cast->
unescaped, common_whitespace);
18821 pm_node_list_append(&parts, part);
18823 while (!match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18824 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
18825 pm_node_list_append(&parts, part);
18831 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18833 cast->
parts = parts;
18836 pm_interpolated_xstring_node_closing_set(cast, &parser->
previous);
18842 pm_node_list_free(&parts);
18845 pm_interpolated_string_node_closing_set(cast, &parser->
previous);
18853 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18855 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18861 parse_heredoc_dedent(parser, nodes, common_whitespace);
18865 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
18866 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18871 case PM_TOKEN_INSTANCE_VARIABLE: {
18872 parser_lex(parser);
18875 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18876 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18881 case PM_TOKEN_INTEGER: {
18883 parser_lex(parser);
18886 case PM_TOKEN_INTEGER_IMAGINARY: {
18888 parser_lex(parser);
18889 return (
pm_node_t *) pm_integer_node_imaginary_create(parser, base, &parser->
previous);
18891 case PM_TOKEN_INTEGER_RATIONAL: {
18893 parser_lex(parser);
18894 return (
pm_node_t *) pm_integer_node_rational_create(parser, base, &parser->
previous);
18896 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: {
18898 parser_lex(parser);
18899 return (
pm_node_t *) pm_integer_node_rational_imaginary_create(parser, base, &parser->
previous);
18901 case PM_TOKEN_KEYWORD___ENCODING__:
18902 parser_lex(parser);
18903 return (
pm_node_t *) pm_source_encoding_node_create(parser, &parser->
previous);
18904 case PM_TOKEN_KEYWORD___FILE__:
18905 parser_lex(parser);
18907 case PM_TOKEN_KEYWORD___LINE__:
18908 parser_lex(parser);
18910 case PM_TOKEN_KEYWORD_ALIAS: {
18911 if (binding_power != PM_BINDING_POWER_STATEMENT) {
18912 pm_parser_err_current(parser, PM_ERR_STATEMENT_ALIAS);
18915 parser_lex(parser);
18918 pm_node_t *new_name = parse_alias_argument(parser,
true, (uint16_t) (depth + 1));
18919 pm_node_t *old_name = parse_alias_argument(parser,
false, (uint16_t) (depth + 1));
18921 switch (PM_NODE_TYPE(new_name)) {
18922 case PM_BACK_REFERENCE_READ_NODE:
18923 case PM_NUMBERED_REFERENCE_READ_NODE:
18924 case PM_GLOBAL_VARIABLE_READ_NODE: {
18925 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)) {
18926 if (PM_NODE_TYPE_P(old_name, PM_NUMBERED_REFERENCE_READ_NODE)) {
18927 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE);
18930 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18933 return (
pm_node_t *) pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name);
18935 case PM_SYMBOL_NODE:
18936 case PM_INTERPOLATED_SYMBOL_NODE: {
18937 if (!PM_NODE_TYPE_P(old_name, PM_SYMBOL_NODE) && !PM_NODE_TYPE_P(old_name, PM_INTERPOLATED_SYMBOL_NODE)) {
18938 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18943 return (
pm_node_t *) pm_alias_method_node_create(parser, &keyword, new_name, old_name);
18946 case PM_TOKEN_KEYWORD_CASE: {
18947 size_t opening_newline_index = token_newline_index(parser);
18948 parser_lex(parser);
18954 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18956 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18957 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18959 }
else if (match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_END)) {
18961 }
else if (!token_begins_expression_p(parser->
current.type)) {
18964 predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CASE_EXPRESSION_AFTER_CASE, (uint16_t) (depth + 1));
18965 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18968 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
18969 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18970 parser_lex(parser);
18972 pop_block_exits(parser, previous_block_exits);
18973 pm_node_list_free(¤t_block_exits);
18975 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18976 return (
pm_node_t *) pm_case_node_create(parser, &case_keyword, predicate, &parser->
previous);
18981 pm_token_t end_keyword = not_provided(parser);
18984 if (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18985 pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, &end_keyword);
18991 while (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18992 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18993 parser_lex(parser);
18996 pm_when_node_t *when_node = pm_when_node_create(parser, &when_keyword);
18999 if (accept1(parser, PM_TOKEN_USTAR)) {
19001 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19003 pm_splat_node_t *splat_node = pm_splat_node_create(parser, &
operator, expression);
19004 pm_when_node_conditions_append(when_node, (
pm_node_t *) splat_node);
19006 if (PM_NODE_TYPE_P(expression, PM_MISSING_NODE))
break;
19008 pm_node_t *condition = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_CASE_EXPRESSION_AFTER_WHEN, (uint16_t) (depth + 1));
19009 pm_when_node_conditions_append(when_node, condition);
19013 if (PM_NODE_TYPE_P(condition, PM_MISSING_NODE))
break;
19017 if (PM_NODE_TYPE_P(condition, PM_STRING_NODE)) {
19018 pm_node_flag_set(condition, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
19019 }
else if (PM_NODE_TYPE_P(condition, PM_SOURCE_FILE_NODE)) {
19020 pm_node_flag_set(condition, PM_NODE_FLAG_STATIC_LITERAL);
19023 pm_when_clause_static_literals_add(parser, &literals, condition);
19025 }
while (accept1(parser, PM_TOKEN_COMMA));
19027 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
19028 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
19029 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
19032 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_WHEN_DELIMITER);
19033 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
19036 if (!match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19038 if (statements != NULL) {
19039 pm_when_node_statements_set(when_node, statements);
19043 pm_case_node_condition_append(case_node, (
pm_node_t *) when_node);
19049 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
19052 pm_static_literals_free(&literals);
19055 pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate, &end_keyword);
19059 if (predicate == NULL) {
19060 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MATCH_MISSING_PREDICATE);
19066 while (match1(parser, PM_TOKEN_KEYWORD_IN)) {
19067 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
19072 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
19074 parser_lex(parser);
19079 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));
19082 pm_constant_id_list_free(&captures);
19087 if (accept1(parser, PM_TOKEN_KEYWORD_IF_MODIFIER)) {
19089 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
19090 pattern = (
pm_node_t *) pm_if_node_modifier_create(parser, pattern, &keyword, predicate);
19091 }
else if (accept1(parser, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) {
19093 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
19094 pattern = (
pm_node_t *) pm_unless_node_modifier_create(parser, pattern, &keyword, predicate);
19101 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
19102 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
19105 then_keyword = not_provided(parser);
19108 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_IN_DELIMITER);
19115 if (match3(parser, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19123 pm_node_t *condition = (
pm_node_t *) pm_in_node_create(parser, pattern, statements, &in_keyword, &then_keyword);
19124 pm_case_match_node_condition_append(case_node, condition);
19130 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
19136 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19137 if (accept1(parser, PM_TOKEN_KEYWORD_ELSE)) {
19141 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19142 else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser,
PM_CONTEXT_ELSE, (uint16_t) (depth + 1)), &parser->
current);
19144 else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->
current);
19147 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
19148 pm_case_node_else_clause_set((
pm_case_node_t *) node, else_node);
19154 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
19155 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM);
19157 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
19163 pop_block_exits(parser, previous_block_exits);
19164 pm_node_list_free(¤t_block_exits);
19168 case PM_TOKEN_KEYWORD_BEGIN: {
19169 size_t opening_newline_index = token_newline_index(parser);
19170 parser_lex(parser);
19173 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19176 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19179 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19180 pm_accepts_block_stack_push(parser,
true);
19181 begin_statements = parse_statements(parser,
PM_CONTEXT_BEGIN, (uint16_t) (depth + 1));
19182 pm_accepts_block_stack_pop(parser);
19183 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19186 pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
19187 parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
19188 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM);
19191 pm_begin_node_end_keyword_set(begin_node, &parser->
previous);
19193 pop_block_exits(parser, previous_block_exits);
19194 pm_node_list_free(¤t_block_exits);
19198 case PM_TOKEN_KEYWORD_BEGIN_UPCASE: {
19200 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19202 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19203 pm_parser_err_current(parser, PM_ERR_STATEMENT_PREEXE_BEGIN);
19206 parser_lex(parser);
19209 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_BEGIN_UPCASE_BRACE);
19213 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM);
19216 pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
19219 flush_block_exits(parser, previous_block_exits);
19220 pm_node_list_free(¤t_block_exits);
19222 return (
pm_node_t *) pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous);
19224 case PM_TOKEN_KEYWORD_BREAK:
19225 case PM_TOKEN_KEYWORD_NEXT:
19226 case PM_TOKEN_KEYWORD_RETURN: {
19227 parser_lex(parser);
19233 token_begins_expression_p(parser->
current.type) ||
19234 match2(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)
19236 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].
left;
19238 if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
19240 parse_arguments(parser, &arguments,
false, PM_TOKEN_EOF, (uint16_t) (depth + 1));
19243 if (!accepts_command_call && arguments.
arguments != NULL) {
19249 switch (keyword.
type) {
19250 case PM_TOKEN_KEYWORD_BREAK: {
19255 case PM_TOKEN_KEYWORD_NEXT: {
19260 case PM_TOKEN_KEYWORD_RETURN: {
19262 parse_return(parser, node);
19266 assert(
false &&
"unreachable");
19270 case PM_TOKEN_KEYWORD_SUPER: {
19271 parser_lex(parser);
19275 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
19280 ((arguments.
block == NULL) || PM_NODE_TYPE_P(arguments.
block, PM_BLOCK_NODE))
19282 return (
pm_node_t *) pm_forwarding_super_node_create(parser, &keyword, &arguments);
19285 return (
pm_node_t *) pm_super_node_create(parser, &keyword, &arguments);
19287 case PM_TOKEN_KEYWORD_YIELD: {
19288 parser_lex(parser);
19292 parse_arguments_list(parser, &arguments,
false, accepts_command_call, (uint16_t) (depth + 1));
19298 if (arguments.
block != NULL) {
19299 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
19300 pm_node_destroy(parser, arguments.
block);
19301 arguments.
block = NULL;
19309 case PM_TOKEN_KEYWORD_CLASS: {
19310 size_t opening_newline_index = token_newline_index(parser);
19311 parser_lex(parser);
19314 pm_do_loop_stack_push(parser,
false);
19317 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19319 if (accept1(parser, PM_TOKEN_LESS_LESS)) {
19321 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));
19323 pm_parser_scope_push(parser,
true);
19324 if (!match2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
19329 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19330 pm_accepts_block_stack_push(parser,
true);
19332 pm_accepts_block_stack_pop(parser);
19335 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
19336 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
19337 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));
19339 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
19342 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
19347 pm_parser_scope_pop(parser);
19348 pm_do_loop_stack_pop(parser);
19350 flush_block_exits(parser, previous_block_exits);
19351 pm_node_list_free(¤t_block_exits);
19353 return (
pm_node_t *) pm_singleton_class_node_create(parser, &locals, &class_keyword, &
operator, expression, statements, &parser->
previous);
19356 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_CLASS_NAME, (uint16_t) (depth + 1));
19358 if (name.
type != PM_TOKEN_CONSTANT) {
19359 pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME);
19365 if (match1(parser, PM_TOKEN_LESS)) {
19366 inheritance_operator = parser->
current;
19367 lex_state_set(parser, PM_LEX_STATE_BEG);
19370 parser_lex(parser);
19372 superclass = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CLASS_SUPERCLASS, (uint16_t) (depth + 1));
19374 inheritance_operator = not_provided(parser);
19378 pm_parser_scope_push(parser,
true);
19380 if (inheritance_operator.
type != PM_TOKEN_NOT_PROVIDED) {
19381 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CLASS_UNEXPECTED_END);
19383 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19387 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19388 pm_accepts_block_stack_push(parser,
true);
19390 pm_accepts_block_stack_pop(parser);
19393 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
19394 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
19395 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));
19397 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
19400 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
19402 if (context_def_p(parser)) {
19403 pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
19409 pm_parser_scope_pop(parser);
19410 pm_do_loop_stack_pop(parser);
19412 if (!PM_NODE_TYPE_P(constant_path, PM_CONSTANT_PATH_NODE) && !(PM_NODE_TYPE_P(constant_path, PM_CONSTANT_READ_NODE))) {
19413 pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
19416 pop_block_exits(parser, previous_block_exits);
19417 pm_node_list_free(¤t_block_exits);
19419 return (
pm_node_t *) pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, &inheritance_operator, superclass, statements, &parser->
previous);
19421 case PM_TOKEN_KEYWORD_DEF: {
19423 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19426 size_t opening_newline_index = token_newline_index(parser);
19436 parser_lex(parser);
19440 bool valid_name =
true;
19442 switch (parser->
current.type) {
19443 case PM_CASE_OPERATOR:
19444 pm_parser_scope_push(parser,
true);
19445 lex_state_set(parser, PM_LEX_STATE_ENDFN);
19446 parser_lex(parser);
19450 case PM_TOKEN_IDENTIFIER: {
19451 parser_lex(parser);
19453 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
19454 receiver = parse_variable_call(parser);
19456 pm_parser_scope_push(parser,
true);
19457 lex_state_set(parser, PM_LEX_STATE_FNAME);
19458 parser_lex(parser);
19461 name = parse_method_definition_name(parser);
19464 pm_parser_scope_push(parser,
true);
19471 case PM_TOKEN_INSTANCE_VARIABLE:
19472 case PM_TOKEN_CLASS_VARIABLE:
19473 case PM_TOKEN_GLOBAL_VARIABLE:
19474 valid_name =
false;
19476 case PM_TOKEN_CONSTANT:
19477 case PM_TOKEN_KEYWORD_NIL:
19478 case PM_TOKEN_KEYWORD_SELF:
19479 case PM_TOKEN_KEYWORD_TRUE:
19480 case PM_TOKEN_KEYWORD_FALSE:
19481 case PM_TOKEN_KEYWORD___FILE__:
19482 case PM_TOKEN_KEYWORD___LINE__:
19483 case PM_TOKEN_KEYWORD___ENCODING__: {
19484 pm_parser_scope_push(parser,
true);
19485 parser_lex(parser);
19489 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
19490 lex_state_set(parser, PM_LEX_STATE_FNAME);
19491 parser_lex(parser);
19494 switch (identifier.
type) {
19495 case PM_TOKEN_CONSTANT:
19496 receiver = (
pm_node_t *) pm_constant_read_node_create(parser, &identifier);
19498 case PM_TOKEN_INSTANCE_VARIABLE:
19499 receiver = (
pm_node_t *) pm_instance_variable_read_node_create(parser, &identifier);
19501 case PM_TOKEN_CLASS_VARIABLE:
19502 receiver = (
pm_node_t *) pm_class_variable_read_node_create(parser, &identifier);
19504 case PM_TOKEN_GLOBAL_VARIABLE:
19505 receiver = (
pm_node_t *) pm_global_variable_read_node_create(parser, &identifier);
19507 case PM_TOKEN_KEYWORD_NIL:
19508 receiver = (
pm_node_t *) pm_nil_node_create(parser, &identifier);
19510 case PM_TOKEN_KEYWORD_SELF:
19511 receiver = (
pm_node_t *) pm_self_node_create(parser, &identifier);
19513 case PM_TOKEN_KEYWORD_TRUE:
19514 receiver = (
pm_node_t *) pm_true_node_create(parser, &identifier);
19516 case PM_TOKEN_KEYWORD_FALSE:
19517 receiver = (
pm_node_t *) pm_false_node_create(parser, &identifier);
19519 case PM_TOKEN_KEYWORD___FILE__:
19520 receiver = (
pm_node_t *) pm_source_file_node_create(parser, &identifier);
19522 case PM_TOKEN_KEYWORD___LINE__:
19523 receiver = (
pm_node_t *) pm_source_line_node_create(parser, &identifier);
19525 case PM_TOKEN_KEYWORD___ENCODING__:
19526 receiver = (
pm_node_t *) pm_source_encoding_node_create(parser, &identifier);
19532 name = parse_method_definition_name(parser);
19542 case PM_TOKEN_PARENTHESIS_LEFT: {
19547 context_pop(parser);
19548 parser_lex(parser);
19551 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEF_RECEIVER, (uint16_t) (depth + 1));
19553 accept1(parser, PM_TOKEN_NEWLINE);
19554 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19557 lex_state_set(parser, PM_LEX_STATE_FNAME);
19558 expect2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON, PM_ERR_DEF_RECEIVER_TERM);
19561 receiver = (
pm_node_t *) pm_parentheses_node_create(parser, &lparen, expression, &rparen, 0);
19565 pm_parser_scope_push(parser,
true);
19567 name = parse_method_definition_name(parser);
19571 pm_parser_scope_push(parser,
true);
19572 name = parse_method_definition_name(parser);
19580 switch (parser->
current.type) {
19581 case PM_TOKEN_PARENTHESIS_LEFT: {
19582 parser_lex(parser);
19585 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19588 params = parse_parameters(parser, PM_BINDING_POWER_DEFINED,
true,
false,
true,
true,
false, (uint16_t) (depth + 1));
19591 lex_state_set(parser, PM_LEX_STATE_BEG);
19594 context_pop(parser);
19595 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19604 case PM_CASE_PARAMETER: {
19607 if (parser->
current.type == PM_TOKEN_LABEL) {
19608 lex_state_set(parser, parser->
lex_state | PM_LEX_STATE_LABEL);
19611 lparen = not_provided(parser);
19612 rparen = not_provided(parser);
19613 params = parse_parameters(parser, PM_BINDING_POWER_DEFINED,
false,
false,
true,
true,
false, (uint16_t) (depth + 1));
19615 context_pop(parser);
19619 lparen = not_provided(parser);
19620 rparen = not_provided(parser);
19623 context_pop(parser);
19632 if (accept1(parser, PM_TOKEN_EQUAL)) {
19633 if (token_is_setter_name(&name)) {
19634 pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
19639 pm_do_loop_stack_push(parser,
false);
19640 statements = (
pm_node_t *) pm_statements_node_create(parser);
19642 bool allow_command_call;
19644 allow_command_call = accepts_command_call;
19647 allow_command_call = binding_power == PM_BINDING_POWER_ASSIGNMENT || binding_power < PM_BINDING_POWER_COMPOSITION;
19650 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_DEFINED + 1, allow_command_call,
false, PM_ERR_DEF_ENDLESS, (uint16_t) (depth + 1));
19652 if (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
19656 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));
19657 context_pop(parser);
19659 statement = (
pm_node_t *) pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value);
19662 pm_statements_node_body_append(parser, (
pm_statements_node_t *) statements, statement,
false);
19663 pm_do_loop_stack_pop(parser);
19664 context_pop(parser);
19665 end_keyword = not_provided(parser);
19667 equal = not_provided(parser);
19669 if (lparen.
type == PM_TOKEN_NOT_PROVIDED) {
19670 lex_state_set(parser, PM_LEX_STATE_BEG);
19672 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_DEF_PARAMS_TERM);
19674 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19677 pm_accepts_block_stack_push(parser,
true);
19678 pm_do_loop_stack_push(parser,
false);
19680 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19681 pm_accepts_block_stack_push(parser,
true);
19683 pm_accepts_block_stack_pop(parser);
19686 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
19687 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
19688 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));
19690 parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword,
false,
false);
19693 pm_accepts_block_stack_pop(parser);
19694 pm_do_loop_stack_pop(parser);
19696 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_DEF_TERM);
19702 pm_parser_scope_pop(parser);
19709 pm_constant_id_t name_id = pm_parser_constant_id_location(parser, name.
start, parse_operator_symbol_name(&name));
19711 flush_block_exits(parser, previous_block_exits);
19712 pm_node_list_free(¤t_block_exits);
19714 return (
pm_node_t *) pm_def_node_create(
19730 case PM_TOKEN_KEYWORD_DEFINED: {
19731 parser_lex(parser);
19739 bool newline = accept1(parser, PM_TOKEN_NEWLINE);
19741 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19744 if (newline && accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19745 expression = (
pm_node_t *) pm_parentheses_node_create(parser, &lparen, NULL, &parser->
previous, 0);
19746 lparen = not_provided(parser);
19747 rparen = not_provided(parser);
19749 expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19752 rparen = not_provided(parser);
19754 accept1(parser, PM_TOKEN_NEWLINE);
19755 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19760 lparen = not_provided(parser);
19761 rparen = not_provided(parser);
19762 expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19765 context_pop(parser);
19766 return (
pm_node_t *) pm_defined_node_create(
19771 &PM_LOCATION_TOKEN_VALUE(&keyword)
19774 case PM_TOKEN_KEYWORD_END_UPCASE: {
19775 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19776 pm_parser_err_current(parser, PM_ERR_STATEMENT_POSTEXE_END);
19779 parser_lex(parser);
19782 if (context_def_p(parser)) {
19783 pm_parser_warn_token(parser, &keyword, PM_WARN_END_IN_METHOD);
19786 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_END_UPCASE_BRACE);
19790 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM);
19791 return (
pm_node_t *) pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous);
19793 case PM_TOKEN_KEYWORD_FALSE:
19794 parser_lex(parser);
19796 case PM_TOKEN_KEYWORD_FOR: {
19797 size_t opening_newline_index = token_newline_index(parser);
19798 parser_lex(parser);
19806 if (accept1(parser, PM_TOKEN_USTAR)) {
19810 if (token_begins_expression_p(parser->
current.type)) {
19811 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19814 index = (
pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
19815 }
else if (token_begins_expression_p(parser->
current.type)) {
19816 index = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
19818 pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX);
19819 index = (
pm_node_t *) pm_missing_node_create(parser, for_keyword.
start, for_keyword.
end);
19823 if (match1(parser, PM_TOKEN_COMMA)) {
19824 index = parse_targets(parser, index, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19826 index = parse_target(parser, index,
false,
false);
19829 context_pop(parser);
19830 pm_do_loop_stack_push(parser,
true);
19832 expect1(parser, PM_TOKEN_KEYWORD_IN, PM_ERR_FOR_IN);
19835 pm_node_t *collection = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_FOR_COLLECTION, (uint16_t) (depth + 1));
19836 pm_do_loop_stack_pop(parser);
19839 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19842 do_keyword = not_provided(parser);
19843 if (!match2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE)) {
19849 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19850 statements = parse_statements(parser,
PM_CONTEXT_FOR, (uint16_t) (depth + 1));
19853 parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword,
false,
false);
19854 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM);
19856 return (
pm_node_t *) pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, &do_keyword, &parser->
previous);
19858 case PM_TOKEN_KEYWORD_IF:
19859 if (parser_end_of_line_p(parser)) {
19860 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
19863 size_t opening_newline_index = token_newline_index(parser);
19864 bool if_after_else = parser->
previous.
type == PM_TOKEN_KEYWORD_ELSE;
19865 parser_lex(parser);
19867 return parse_conditional(parser,
PM_CONTEXT_IF, opening_newline_index, if_after_else, (uint16_t) (depth + 1));
19868 case PM_TOKEN_KEYWORD_UNDEF: {
19869 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19870 pm_parser_err_current(parser, PM_ERR_STATEMENT_UNDEF);
19873 parser_lex(parser);
19875 pm_node_t *name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19877 if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) {
19878 pm_node_destroy(parser, name);
19880 pm_undef_node_append(undef, name);
19882 while (match1(parser, PM_TOKEN_COMMA)) {
19883 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
19884 parser_lex(parser);
19885 name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19887 if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) {
19888 pm_node_destroy(parser, name);
19892 pm_undef_node_append(undef, name);
19898 case PM_TOKEN_KEYWORD_NOT: {
19899 parser_lex(parser);
19908 if (!accepts_command_call && !match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19909 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES)) {
19910 pm_parser_err(parser, parser->
previous.
end, parser->
previous.
end + 1, PM_ERR_EXPECT_LPAREN_AFTER_NOT_LPAREN);
19912 accept1(parser, PM_TOKEN_NEWLINE);
19913 pm_parser_err_current(parser, PM_ERR_EXPECT_LPAREN_AFTER_NOT_OTHER);
19919 accept1(parser, PM_TOKEN_NEWLINE);
19921 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19924 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19925 receiver = (
pm_node_t *) pm_parentheses_node_create(parser, &lparen, NULL, &parser->
previous, 0);
19927 arguments.
opening_loc = PM_LOCATION_TOKEN_VALUE(&lparen);
19928 receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19931 accept1(parser, PM_TOKEN_NEWLINE);
19932 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19937 receiver = parse_expression(parser, PM_BINDING_POWER_NOT,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19940 return (
pm_node_t *) pm_call_node_not_create(parser, receiver, &message, &arguments);
19942 case PM_TOKEN_KEYWORD_UNLESS: {
19943 size_t opening_newline_index = token_newline_index(parser);
19944 parser_lex(parser);
19946 return parse_conditional(parser,
PM_CONTEXT_UNLESS, opening_newline_index,
false, (uint16_t) (depth + 1));
19948 case PM_TOKEN_KEYWORD_MODULE: {
19950 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19952 size_t opening_newline_index = token_newline_index(parser);
19953 parser_lex(parser);
19956 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_MODULE_NAME, (uint16_t) (depth + 1));
19961 if (PM_NODE_TYPE_P(constant_path, PM_MISSING_NODE)) {
19962 pop_block_exits(parser, previous_block_exits);
19963 pm_node_list_free(¤t_block_exits);
19966 return (
pm_node_t *) pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing);
19969 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
19972 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
19973 constant_path = (
pm_node_t *) pm_constant_path_node_create(parser, constant_path, &double_colon, &parser->
previous);
19980 if (name.
type != PM_TOKEN_CONSTANT) {
19981 pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
19984 pm_parser_scope_push(parser,
true);
19985 accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE);
19988 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19989 pm_accepts_block_stack_push(parser,
true);
19991 pm_accepts_block_stack_pop(parser);
19994 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
19995 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
19996 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));
19998 parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword,
false,
false);
20004 pm_parser_scope_pop(parser);
20005 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM);
20007 if (context_def_p(parser)) {
20008 pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
20011 pop_block_exits(parser, previous_block_exits);
20012 pm_node_list_free(¤t_block_exits);
20014 return (
pm_node_t *) pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->
previous);
20016 case PM_TOKEN_KEYWORD_NIL:
20017 parser_lex(parser);
20019 case PM_TOKEN_KEYWORD_REDO: {
20020 parser_lex(parser);
20027 case PM_TOKEN_KEYWORD_RETRY: {
20028 parser_lex(parser);
20031 parse_retry(parser, node);
20035 case PM_TOKEN_KEYWORD_SELF:
20036 parser_lex(parser);
20038 case PM_TOKEN_KEYWORD_TRUE:
20039 parser_lex(parser);
20041 case PM_TOKEN_KEYWORD_UNTIL: {
20042 size_t opening_newline_index = token_newline_index(parser);
20045 pm_do_loop_stack_push(parser,
true);
20047 parser_lex(parser);
20049 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
20051 pm_do_loop_stack_pop(parser);
20052 context_pop(parser);
20055 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
20058 do_keyword = not_provided(parser);
20059 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
20063 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
20064 pm_accepts_block_stack_push(parser,
true);
20065 statements = parse_statements(parser,
PM_CONTEXT_UNTIL, (uint16_t) (depth + 1));
20066 pm_accepts_block_stack_pop(parser);
20067 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
20070 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
20071 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM);
20073 return (
pm_node_t *) pm_until_node_create(parser, &keyword, &do_keyword, &parser->
previous, predicate, statements, 0);
20075 case PM_TOKEN_KEYWORD_WHILE: {
20076 size_t opening_newline_index = token_newline_index(parser);
20079 pm_do_loop_stack_push(parser,
true);
20081 parser_lex(parser);
20083 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
20085 pm_do_loop_stack_pop(parser);
20086 context_pop(parser);
20089 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
20092 do_keyword = not_provided(parser);
20093 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
20097 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
20098 pm_accepts_block_stack_push(parser,
true);
20099 statements = parse_statements(parser,
PM_CONTEXT_WHILE, (uint16_t) (depth + 1));
20100 pm_accepts_block_stack_pop(parser);
20101 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
20104 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
20105 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM);
20107 return (
pm_node_t *) pm_while_node_create(parser, &keyword, &do_keyword, &parser->
previous, predicate, statements, 0);
20109 case PM_TOKEN_PERCENT_LOWER_I: {
20110 parser_lex(parser);
20114 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20115 accept1(parser, PM_TOKEN_WORDS_SEP);
20116 if (match1(parser, PM_TOKEN_STRING_END))
break;
20118 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20121 pm_array_node_elements_append(array, (
pm_node_t *) pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing));
20124 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_LOWER_ELEMENT);
20128 if (match1(parser, PM_TOKEN_EOF)) {
20129 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
20132 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_LOWER_TERM);
20134 pm_array_node_close_set(array, &closing);
20138 case PM_TOKEN_PERCENT_UPPER_I: {
20139 parser_lex(parser);
20147 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20148 switch (parser->
current.type) {
20149 case PM_TOKEN_WORDS_SEP: {
20150 if (current == NULL) {
20156 pm_array_node_elements_append(array, current);
20160 parser_lex(parser);
20163 case PM_TOKEN_STRING_CONTENT: {
20167 if (current == NULL) {
20171 current = (
pm_node_t *) pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing);
20172 parser_lex(parser);
20173 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
20178 parser_lex(parser);
20181 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20190 pm_node_t *second_string = (
pm_node_t *) pm_string_node_create_current_string(parser, &opening, &parser->
previous, &closing);
20191 parser_lex(parser);
20194 pm_interpolated_symbol_node_append(interpolated, first_string);
20195 pm_interpolated_symbol_node_append(interpolated, second_string);
20200 assert(
false &&
"unreachable");
20205 case PM_TOKEN_EMBVAR: {
20206 bool start_location_set =
false;
20207 if (current == NULL) {
20213 current = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
20214 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20223 pm_interpolated_symbol_node_append(interpolated, current);
20225 start_location_set =
true;
20232 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20234 if (!start_location_set) {
20239 case PM_TOKEN_EMBEXPR_BEGIN: {
20240 bool start_location_set =
false;
20241 if (current == NULL) {
20247 current = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
20248 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20258 pm_interpolated_symbol_node_append(interpolated, current);
20260 start_location_set =
true;
20262 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
20266 assert(
false &&
"unreachable");
20269 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20271 if (!start_location_set) {
20277 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_UPPER_ELEMENT);
20278 parser_lex(parser);
20285 pm_array_node_elements_append(array, current);
20289 if (match1(parser, PM_TOKEN_EOF)) {
20290 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_UPPER_TERM);
20293 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_UPPER_TERM);
20295 pm_array_node_close_set(array, &closing);
20299 case PM_TOKEN_PERCENT_LOWER_W: {
20300 parser_lex(parser);
20305 accept1(parser, PM_TOKEN_WORDS_SEP);
20307 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20308 accept1(parser, PM_TOKEN_WORDS_SEP);
20309 if (match1(parser, PM_TOKEN_STRING_END))
break;
20311 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20316 pm_array_node_elements_append(array,
string);
20319 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_LOWER_ELEMENT);
20323 if (match1(parser, PM_TOKEN_EOF)) {
20324 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_LOWER_TERM);
20327 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_LOWER_TERM);
20330 pm_array_node_close_set(array, &closing);
20333 case PM_TOKEN_PERCENT_UPPER_W: {
20334 parser_lex(parser);
20342 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20343 switch (parser->
current.type) {
20344 case PM_TOKEN_WORDS_SEP: {
20349 if (current == NULL) {
20356 pm_array_node_elements_append(array, current);
20360 parser_lex(parser);
20363 case PM_TOKEN_STRING_CONTENT: {
20368 pm_node_flag_set(
string, parse_unescaped_encoding(parser));
20369 parser_lex(parser);
20371 if (current == NULL) {
20377 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
20382 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20388 pm_interpolated_string_node_append(interpolated, current);
20389 pm_interpolated_string_node_append(interpolated,
string);
20392 assert(
false &&
"unreachable");
20397 case PM_TOKEN_EMBVAR: {
20398 if (current == NULL) {
20405 current = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
20406 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20414 pm_interpolated_string_node_append(interpolated, current);
20422 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20426 case PM_TOKEN_EMBEXPR_BEGIN: {
20427 if (current == NULL) {
20434 current = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
20435 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20443 pm_interpolated_string_node_append(interpolated, current);
20445 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
20450 assert(
false &&
"unreachable");
20453 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20458 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_UPPER_ELEMENT);
20459 parser_lex(parser);
20466 pm_array_node_elements_append(array, current);
20470 if (match1(parser, PM_TOKEN_EOF)) {
20471 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_UPPER_TERM);
20474 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_UPPER_TERM);
20477 pm_array_node_close_set(array, &closing);
20480 case PM_TOKEN_REGEXP_BEGIN: {
20482 parser_lex(parser);
20484 if (match1(parser, PM_TOKEN_REGEXP_END)) {
20489 .
type = PM_TOKEN_STRING_CONTENT,
20494 parser_lex(parser);
20497 pm_node_flag_set(node, PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING);
20504 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20512 parser_lex(parser);
20517 if (accept1(parser, PM_TOKEN_REGEXP_END)) {
20524 if (!match1(parser, PM_TOKEN_EQUAL_TILDE)) {
20525 parse_regular_expression_errors(parser, node);
20528 pm_node_flag_set((
pm_node_t *) node, parse_and_validate_regular_expression_encoding(parser, &unescaped, ascii_only, node->base.
flags));
20534 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20544 pm_node_flag_set(part, PM_STRING_FLAGS_FORCED_BINARY_ENCODING);
20547 pm_interpolated_regular_expression_node_append(interpolated, part);
20552 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20558 while (!match2(parser, PM_TOKEN_REGEXP_END, PM_TOKEN_EOF)) {
20559 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20560 pm_interpolated_regular_expression_node_append(interpolated, part);
20565 if (match1(parser, PM_TOKEN_EOF)) {
20566 pm_parser_err_token(parser, &opening, PM_ERR_REGEXP_TERM);
20569 expect1(parser, PM_TOKEN_REGEXP_END, PM_ERR_REGEXP_TERM);
20572 pm_interpolated_regular_expression_node_closing_set(parser, interpolated, &closing);
20575 case PM_TOKEN_BACKTICK:
20576 case PM_TOKEN_PERCENT_LOWER_X: {
20577 parser_lex(parser);
20584 if (match1(parser, PM_TOKEN_STRING_END)) {
20589 .
type = PM_TOKEN_STRING_CONTENT,
20594 parser_lex(parser);
20595 return (
pm_node_t *) pm_xstring_node_create(parser, &opening, &content, &parser->
previous);
20600 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20607 parser_lex(parser);
20609 if (match1(parser, PM_TOKEN_STRING_END)) {
20610 pm_node_t *node = (
pm_node_t *) pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
20611 pm_node_flag_set(node, parse_unescaped_encoding(parser));
20612 parser_lex(parser);
20618 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20624 pm_node_flag_set(part, parse_unescaped_encoding(parser));
20626 pm_interpolated_xstring_node_append(node, part);
20631 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20635 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20636 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20637 pm_interpolated_xstring_node_append(node, part);
20642 if (match1(parser, PM_TOKEN_EOF)) {
20643 pm_parser_err_token(parser, &opening, PM_ERR_XSTRING_TERM);
20646 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_XSTRING_TERM);
20648 pm_interpolated_xstring_node_closing_set(node, &closing);
20652 case PM_TOKEN_USTAR: {
20653 parser_lex(parser);
20658 if (binding_power != PM_BINDING_POWER_STATEMENT) {
20659 pm_parser_err_prefix(parser, diag_id);
20666 if (token_begins_expression_p(parser->
current.type)) {
20667 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
20672 if (match1(parser, PM_TOKEN_COMMA)) {
20673 return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
20675 return parse_target_validate(parser, splat,
true);
20678 case PM_TOKEN_BANG: {
20679 if (binding_power > PM_BINDING_POWER_UNARY) {
20680 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20683 parser_lex(parser);
20686 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));
20687 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"!");
20689 pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
20692 case PM_TOKEN_TILDE: {
20693 if (binding_power > PM_BINDING_POWER_UNARY) {
20694 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20696 parser_lex(parser);
20699 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20700 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"~");
20704 case PM_TOKEN_UMINUS: {
20705 if (binding_power > PM_BINDING_POWER_UNARY) {
20706 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20708 parser_lex(parser);
20711 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20712 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"-@");
20716 case PM_TOKEN_UMINUS_NUM: {
20717 parser_lex(parser);
20720 pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20722 if (accept1(parser, PM_TOKEN_STAR_STAR)) {
20724 pm_node_t *exponent = parse_expression(parser, pm_binding_powers[exponent_operator.
type].right,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
20725 node = (
pm_node_t *) pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0);
20726 node = (
pm_node_t *) pm_call_node_unary_create(parser, &
operator, node,
"-@");
20728 switch (PM_NODE_TYPE(node)) {
20729 case PM_INTEGER_NODE:
20730 case PM_FLOAT_NODE:
20731 case PM_RATIONAL_NODE:
20732 case PM_IMAGINARY_NODE:
20733 parse_negative_numeric(node);
20736 node = (
pm_node_t *) pm_call_node_unary_create(parser, &
operator, node,
"-@");
20743 case PM_TOKEN_MINUS_GREATER: {
20747 size_t opening_newline_index = token_newline_index(parser);
20748 pm_accepts_block_stack_push(parser,
true);
20749 parser_lex(parser);
20752 pm_parser_scope_push(parser,
false);
20756 switch (parser->
current.type) {
20757 case PM_TOKEN_PARENTHESIS_LEFT: {
20759 parser_lex(parser);
20761 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
20762 block_parameters = pm_block_parameters_node_create(parser, NULL, &opening);
20764 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
true, (uint16_t) (depth + 1));
20767 accept1(parser, PM_TOKEN_NEWLINE);
20768 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
20770 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
20773 case PM_CASE_PARAMETER: {
20774 pm_accepts_block_stack_push(parser,
false);
20776 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
false, (uint16_t) (depth + 1));
20777 pm_accepts_block_stack_pop(parser);
20781 block_parameters = NULL;
20790 if (accept1(parser, PM_TOKEN_LAMBDA_BEGIN)) {
20793 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
20797 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20798 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE);
20800 expect1(parser, PM_TOKEN_KEYWORD_DO, PM_ERR_LAMBDA_OPEN);
20803 if (!match3(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20804 pm_accepts_block_stack_push(parser,
true);
20806 pm_accepts_block_stack_pop(parser);
20809 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20810 assert(body == NULL || PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE));
20811 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));
20813 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20816 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END);
20820 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
20823 pm_parser_scope_pop(parser);
20824 pm_accepts_block_stack_pop(parser);
20826 return (
pm_node_t *) pm_lambda_node_create(parser, &locals, &
operator, &opening, &parser->
previous, parameters, body);
20828 case PM_TOKEN_UPLUS: {
20829 if (binding_power > PM_BINDING_POWER_UNARY) {
20830 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20832 parser_lex(parser);
20835 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20836 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"+@");
20840 case PM_TOKEN_STRING_BEGIN:
20841 return parse_strings(parser, NULL, accepts_label, (uint16_t) (depth + 1));
20842 case PM_TOKEN_SYMBOL_BEGIN: {
20844 parser_lex(parser);
20846 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_END, (uint16_t) (depth + 1));
20857 if (diag_id != PM_ERR_CANNOT_PARSE_EXPRESSION) {
20858 pm_parser_err_prefix(parser, diag_id);
20864 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT,
pm_token_type_human(parser->
current.type), context_human(recoverable));
20865 }
else if (diag_id == PM_ERR_CANNOT_PARSE_EXPRESSION) {
20871 pm_parser_err_prefix(parser, diag_id);
20889parse_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) {
20890 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));
20894 if (match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
20898 parser_lex(parser);
20900 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));
20901 context_pop(parser);
20903 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
20915 switch (PM_NODE_TYPE(node)) {
20916 case PM_BEGIN_NODE: {
20921 case PM_LOCAL_VARIABLE_WRITE_NODE: {
20923 pm_locals_read(&pm_parser_scope_find(parser, cast->
depth)->
locals, cast->
name);
20926 case PM_PARENTHESES_NODE: {
20928 if (cast->
body != NULL) parse_assignment_value_local(parser, cast->
body);
20931 case PM_STATEMENTS_NODE: {
20936 parse_assignment_value_local(parser, statement);
20958parse_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) {
20959 bool permitted =
true;
20960 if (previous_binding_power != PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_USTAR)) permitted =
false;
20962 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));
20963 if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE);
20965 parse_assignment_value_local(parser, value);
20966 bool single_value =
true;
20968 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && (PM_NODE_TYPE_P(value, PM_SPLAT_NODE) || match1(parser, PM_TOKEN_COMMA))) {
20969 single_value =
false;
20974 pm_array_node_elements_append(array, value);
20977 while (accept1(parser, PM_TOKEN_COMMA)) {
20978 pm_node_t *element = parse_starred_expression(parser, binding_power,
false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1));
20980 pm_array_node_elements_append(array, element);
20981 if (PM_NODE_TYPE_P(element, PM_MISSING_NODE))
break;
20983 parse_assignment_value_local(parser, element);
20989 if ((single_value || (binding_power == (PM_BINDING_POWER_MULTI_ASSIGNMENT + 1))) && match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
20993 parser_lex(parser);
20995 bool accepts_command_call_inner =
false;
20999 if (PM_NODE_TYPE_P(value, PM_CALL_NODE)) {
21002 accepts_command_call_inner =
true;
21006 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));
21007 context_pop(parser);
21009 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
21025 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_ARGUMENTS);
21030 if (call_node->
block != NULL) {
21031 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_BLOCK);
21033 call_node->
block = NULL;
21062static inline const uint8_t *
21063pm_named_capture_escape_hex(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
21066 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
21067 uint8_t value = escape_hexadecimal_digit(*cursor);
21070 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
21071 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(*cursor));
21075 pm_buffer_append_byte(unescaped, value);
21077 pm_buffer_append_string(unescaped,
"\\x", 2);
21083static inline const uint8_t *
21084pm_named_capture_escape_octal(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
21085 uint8_t value = (uint8_t) (*cursor -
'0');
21088 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
21089 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
21092 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
21093 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
21098 pm_buffer_append_byte(unescaped, value);
21102static inline const uint8_t *
21103pm_named_capture_escape_unicode(
pm_parser_t *parser,
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
21104 const uint8_t *start = cursor - 1;
21107 if (cursor >= end) {
21108 pm_buffer_append_string(unescaped,
"\\u", 2);
21112 if (*cursor !=
'{') {
21113 size_t length = pm_strspn_hexadecimal_digit(cursor, MIN(end - cursor, 4));
21114 uint32_t value = escape_unicode(parser, cursor, length);
21116 if (!pm_buffer_append_unicode_codepoint(unescaped, value)) {
21117 pm_buffer_append_string(unescaped, (
const char *) start, (
size_t) ((cursor + length) - start));
21120 return cursor + length;
21125 while (cursor < end && *cursor ==
' ') cursor++;
21127 if (cursor >= end)
break;
21128 if (*cursor ==
'}') {
21133 size_t length = pm_strspn_hexadecimal_digit(cursor, end - cursor);
21134 uint32_t value = escape_unicode(parser, cursor, length);
21136 (void) pm_buffer_append_unicode_codepoint(unescaped, value);
21144pm_named_capture_escape(
pm_parser_t *parser,
pm_buffer_t *unescaped,
const uint8_t *source,
const size_t length,
const uint8_t *cursor) {
21145 const uint8_t *end = source + length;
21146 pm_buffer_append_string(unescaped, (
const char *) source, (
size_t) (cursor - source));
21149 if (++cursor >= end) {
21150 pm_buffer_append_byte(unescaped,
'\\');
21156 cursor = pm_named_capture_escape_hex(unescaped, cursor, end);
21158 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
21159 cursor = pm_named_capture_escape_octal(unescaped, cursor, end);
21162 cursor = pm_named_capture_escape_unicode(parser, unescaped, cursor, end);
21165 pm_buffer_append_byte(unescaped,
'\\');
21169 const uint8_t *next_cursor = pm_memchr(cursor,
'\\', (
size_t) (end - cursor), parser->
encoding_changed, parser->
encoding);
21170 if (next_cursor == NULL)
break;
21172 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (next_cursor - cursor));
21173 cursor = next_cursor;
21176 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (end - cursor));
21184parse_regular_expression_named_capture(
const pm_string_t *capture,
void *data) {
21205 pm_named_capture_escape(parser, &unescaped, source, length, cursor);
21215 if (!pm_slice_is_valid_local(parser, source, source + length)) {
21220 if (callback_data->
shared) {
21224 name = pm_parser_constant_id_location(parser, location.
start, location.
end);
21230 void *memory =
xmalloc(length);
21231 if (memory == NULL) abort();
21233 memcpy(memory, source, length);
21234 name = pm_parser_constant_id_owned(parser, (uint8_t *) memory, length);
21239 if (name != 0 && !pm_constant_id_list_includes(names, name)) {
21240 pm_constant_id_list_append(names, name);
21243 if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
21246 if (pm_local_is_keyword((
const char *) source, length)) {
21253 pm_parser_local_add(parser, name, location.
start, location.
end, 0);
21258 if (callback_data->
match == NULL) {
21259 callback_data->
match = pm_match_write_node_create(parser, call);
21264 pm_node_t *target = (
pm_node_t *) pm_local_variable_target_node_create(parser, &location, name, depth == -1 ? 0 : (uint32_t) depth);
21265 pm_node_list_append(&callback_data->
match->
targets, target);
21281 .shared = content->
type == PM_STRING_SHARED
21288 .shared = content->
type == PM_STRING_SHARED
21291 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);
21292 pm_constant_id_list_free(&callback_data.
names);
21294 if (callback_data.
match != NULL) {
21302parse_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) {
21305 switch (token.type) {
21306 case PM_TOKEN_EQUAL: {
21307 switch (PM_NODE_TYPE(node)) {
21308 case PM_CALL_NODE: {
21314 if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21319 case PM_CASE_WRITABLE: {
21323 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
21327 parser_lex(parser);
21328 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));
21330 if (PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) && previous_binding_power != PM_BINDING_POWER_STATEMENT) {
21331 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_MULTI_WRITE);
21334 return parse_write(parser, node, &token, value);
21336 case PM_SPLAT_NODE: {
21338 pm_multi_target_node_targets_append(parser, multi_target, node);
21340 parser_lex(parser);
21341 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));
21342 return parse_write(parser, (
pm_node_t *) multi_target, &token, value);
21344 case PM_SOURCE_ENCODING_NODE:
21345 case PM_FALSE_NODE:
21346 case PM_SOURCE_FILE_NODE:
21347 case PM_SOURCE_LINE_NODE:
21350 case PM_TRUE_NODE: {
21353 parser_lex(parser);
21354 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));
21355 return parse_unwriteable_write(parser, node, &token, value);
21361 parser_lex(parser);
21362 pm_parser_err_token(parser, &token, PM_ERR_EXPRESSION_NOT_WRITABLE);
21366 case PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL: {
21367 switch (PM_NODE_TYPE(node)) {
21368 case PM_BACK_REFERENCE_READ_NODE:
21369 case PM_NUMBERED_REFERENCE_READ_NODE:
21370 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21372 case PM_GLOBAL_VARIABLE_READ_NODE: {
21373 parser_lex(parser);
21375 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));
21376 pm_node_t *result = (
pm_node_t *) pm_global_variable_and_write_node_create(parser, node, &token, value);
21378 pm_node_destroy(parser, node);
21381 case PM_CLASS_VARIABLE_READ_NODE: {
21382 parser_lex(parser);
21384 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));
21387 pm_node_destroy(parser, node);
21390 case PM_CONSTANT_PATH_NODE: {
21391 parser_lex(parser);
21393 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));
21396 return parse_shareable_constant_write(parser, write);
21398 case PM_CONSTANT_READ_NODE: {
21399 parser_lex(parser);
21401 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));
21404 pm_node_destroy(parser, node);
21405 return parse_shareable_constant_write(parser, write);
21407 case PM_INSTANCE_VARIABLE_READ_NODE: {
21408 parser_lex(parser);
21410 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));
21413 pm_node_destroy(parser, node);
21416 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21418 parser_lex(parser);
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 pm_node_t *result = (
pm_node_t *) pm_local_variable_and_write_node_create(parser, node, &token, value, name, 0);
21423 parse_target_implicit_parameter(parser, node);
21424 pm_node_destroy(parser, node);
21427 case PM_LOCAL_VARIABLE_READ_NODE: {
21430 parse_target_implicit_parameter(parser, node);
21434 parser_lex(parser);
21436 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));
21439 pm_node_destroy(parser, node);
21442 case PM_CALL_NODE: {
21448 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21450 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21453 parser_lex(parser);
21455 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));
21456 pm_node_t *result = (
pm_node_t *) pm_local_variable_and_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21458 pm_node_destroy(parser, (
pm_node_t *) cast);
21464 parser_lex(parser);
21469 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21470 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));
21471 return (
pm_node_t *) pm_index_and_write_node_create(parser, cast, &token, value);
21475 if (pm_call_node_writable_p(parser, cast)) {
21476 parse_write_name(parser, &cast->
name);
21478 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21481 parse_call_operator_write(parser, cast, &token);
21482 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));
21483 return (
pm_node_t *) pm_call_and_write_node_create(parser, cast, &token, value);
21485 case PM_MULTI_WRITE_NODE: {
21486 parser_lex(parser);
21487 pm_parser_err_token(parser, &token, PM_ERR_AMPAMPEQ_MULTI_ASSIGN);
21491 parser_lex(parser);
21496 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
21500 case PM_TOKEN_PIPE_PIPE_EQUAL: {
21501 switch (PM_NODE_TYPE(node)) {
21502 case PM_BACK_REFERENCE_READ_NODE:
21503 case PM_NUMBERED_REFERENCE_READ_NODE:
21504 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21506 case PM_GLOBAL_VARIABLE_READ_NODE: {
21507 parser_lex(parser);
21509 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));
21510 pm_node_t *result = (
pm_node_t *) pm_global_variable_or_write_node_create(parser, node, &token, value);
21512 pm_node_destroy(parser, node);
21515 case PM_CLASS_VARIABLE_READ_NODE: {
21516 parser_lex(parser);
21518 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));
21521 pm_node_destroy(parser, node);
21524 case PM_CONSTANT_PATH_NODE: {
21525 parser_lex(parser);
21527 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));
21530 return parse_shareable_constant_write(parser, write);
21532 case PM_CONSTANT_READ_NODE: {
21533 parser_lex(parser);
21535 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));
21538 pm_node_destroy(parser, node);
21539 return parse_shareable_constant_write(parser, write);
21541 case PM_INSTANCE_VARIABLE_READ_NODE: {
21542 parser_lex(parser);
21544 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));
21547 pm_node_destroy(parser, node);
21550 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21552 parser_lex(parser);
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 pm_node_t *result = (
pm_node_t *) pm_local_variable_or_write_node_create(parser, node, &token, value, name, 0);
21557 parse_target_implicit_parameter(parser, node);
21558 pm_node_destroy(parser, node);
21561 case PM_LOCAL_VARIABLE_READ_NODE: {
21564 parse_target_implicit_parameter(parser, node);
21568 parser_lex(parser);
21570 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));
21573 pm_node_destroy(parser, node);
21576 case PM_CALL_NODE: {
21582 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21584 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21587 parser_lex(parser);
21589 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));
21590 pm_node_t *result = (
pm_node_t *) pm_local_variable_or_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21592 pm_node_destroy(parser, (
pm_node_t *) cast);
21598 parser_lex(parser);
21603 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21604 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));
21605 return (
pm_node_t *) pm_index_or_write_node_create(parser, cast, &token, value);
21609 if (pm_call_node_writable_p(parser, cast)) {
21610 parse_write_name(parser, &cast->
name);
21612 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21615 parse_call_operator_write(parser, cast, &token);
21616 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));
21617 return (
pm_node_t *) pm_call_or_write_node_create(parser, cast, &token, value);
21619 case PM_MULTI_WRITE_NODE: {
21620 parser_lex(parser);
21621 pm_parser_err_token(parser, &token, PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN);
21625 parser_lex(parser);
21630 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
21634 case PM_TOKEN_AMPERSAND_EQUAL:
21635 case PM_TOKEN_CARET_EQUAL:
21636 case PM_TOKEN_GREATER_GREATER_EQUAL:
21637 case PM_TOKEN_LESS_LESS_EQUAL:
21638 case PM_TOKEN_MINUS_EQUAL:
21639 case PM_TOKEN_PERCENT_EQUAL:
21640 case PM_TOKEN_PIPE_EQUAL:
21641 case PM_TOKEN_PLUS_EQUAL:
21642 case PM_TOKEN_SLASH_EQUAL:
21643 case PM_TOKEN_STAR_EQUAL:
21644 case PM_TOKEN_STAR_STAR_EQUAL: {
21645 switch (PM_NODE_TYPE(node)) {
21646 case PM_BACK_REFERENCE_READ_NODE:
21647 case PM_NUMBERED_REFERENCE_READ_NODE:
21648 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21650 case PM_GLOBAL_VARIABLE_READ_NODE: {
21651 parser_lex(parser);
21653 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));
21654 pm_node_t *result = (
pm_node_t *) pm_global_variable_operator_write_node_create(parser, node, &token, value);
21656 pm_node_destroy(parser, node);
21659 case PM_CLASS_VARIABLE_READ_NODE: {
21660 parser_lex(parser);
21662 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_destroy(parser, node);
21668 case PM_CONSTANT_PATH_NODE: {
21669 parser_lex(parser);
21671 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));
21674 return parse_shareable_constant_write(parser, write);
21676 case PM_CONSTANT_READ_NODE: {
21677 parser_lex(parser);
21679 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));
21682 pm_node_destroy(parser, node);
21683 return parse_shareable_constant_write(parser, write);
21685 case PM_INSTANCE_VARIABLE_READ_NODE: {
21686 parser_lex(parser);
21688 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));
21691 pm_node_destroy(parser, node);
21694 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21696 parser_lex(parser);
21698 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));
21699 pm_node_t *result = (
pm_node_t *) pm_local_variable_operator_write_node_create(parser, node, &token, value, name, 0);
21701 parse_target_implicit_parameter(parser, node);
21702 pm_node_destroy(parser, node);
21705 case PM_LOCAL_VARIABLE_READ_NODE: {
21708 parse_target_implicit_parameter(parser, node);
21712 parser_lex(parser);
21714 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));
21715 pm_node_t *result = (
pm_node_t *) pm_local_variable_operator_write_node_create(parser, node, &token, value, cast->
name, cast->
depth);
21717 pm_node_destroy(parser, node);
21720 case PM_CALL_NODE: {
21721 parser_lex(parser);
21727 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21729 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21732 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));
21733 pm_node_t *result = (
pm_node_t *) pm_local_variable_operator_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21735 pm_node_destroy(parser, (
pm_node_t *) cast);
21742 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21743 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));
21744 return (
pm_node_t *) pm_index_operator_write_node_create(parser, cast, &token, value);
21748 if (pm_call_node_writable_p(parser, cast)) {
21749 parse_write_name(parser, &cast->
name);
21751 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21754 parse_call_operator_write(parser, cast, &token);
21755 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));
21756 return (
pm_node_t *) pm_call_operator_write_node_create(parser, cast, &token, value);
21758 case PM_MULTI_WRITE_NODE: {
21759 parser_lex(parser);
21760 pm_parser_err_token(parser, &token, PM_ERR_OPERATOR_MULTI_ASSIGN);
21764 parser_lex(parser);
21773 case PM_TOKEN_AMPERSAND_AMPERSAND:
21774 case PM_TOKEN_KEYWORD_AND: {
21775 parser_lex(parser);
21777 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));
21778 return (
pm_node_t *) pm_and_node_create(parser, node, &token, right);
21780 case PM_TOKEN_KEYWORD_OR:
21781 case PM_TOKEN_PIPE_PIPE: {
21782 parser_lex(parser);
21784 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));
21785 return (
pm_node_t *) pm_or_node_create(parser, node, &token, right);
21787 case PM_TOKEN_EQUAL_TILDE: {
21795 parser_lex(parser);
21796 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21799 pm_call_node_t *call = pm_call_node_binary_create(parser, node, &token, argument, 0);
21805 if (PM_NODE_TYPE_P(node, PM_INTERPOLATED_REGULAR_EXPRESSION_NODE)) {
21812 bool interpolated =
false;
21813 size_t total_length = 0;
21817 if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
21820 interpolated =
true;
21825 if (!interpolated && total_length > 0) {
21826 void *memory =
xmalloc(total_length);
21827 if (!memory) abort();
21829 uint8_t *cursor = memory;
21839 pm_string_owned_init(&owned, (uint8_t *) memory, total_length);
21841 result = parse_regular_expression_named_captures(parser, &owned, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
21844 }
else if (PM_NODE_TYPE_P(node, PM_REGULAR_EXPRESSION_NODE)) {
21848 result = parse_regular_expression_named_captures(parser, content, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
21853 case PM_TOKEN_UAMPERSAND:
21854 case PM_TOKEN_USTAR:
21855 case PM_TOKEN_USTAR_STAR:
21858 case PM_TOKEN_BANG_EQUAL:
21859 case PM_TOKEN_BANG_TILDE:
21860 case PM_TOKEN_EQUAL_EQUAL:
21861 case PM_TOKEN_EQUAL_EQUAL_EQUAL:
21862 case PM_TOKEN_LESS_EQUAL_GREATER:
21863 case PM_TOKEN_CARET:
21864 case PM_TOKEN_PIPE:
21865 case PM_TOKEN_AMPERSAND:
21866 case PM_TOKEN_GREATER_GREATER:
21867 case PM_TOKEN_LESS_LESS:
21868 case PM_TOKEN_MINUS:
21869 case PM_TOKEN_PLUS:
21870 case PM_TOKEN_PERCENT:
21871 case PM_TOKEN_SLASH:
21872 case PM_TOKEN_STAR:
21873 case PM_TOKEN_STAR_STAR: {
21874 parser_lex(parser);
21876 switch (PM_NODE_TYPE(node)) {
21877 case PM_RESCUE_MODIFIER_NODE: {
21880 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21884 case PM_AND_NODE: {
21886 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21887 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21893 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21894 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21902 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21903 return (
pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument, 0);
21905 case PM_TOKEN_GREATER:
21906 case PM_TOKEN_GREATER_EQUAL:
21907 case PM_TOKEN_LESS:
21908 case PM_TOKEN_LESS_EQUAL: {
21909 if (PM_NODE_TYPE_P(node, PM_CALL_NODE) && PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_COMPARISON)) {
21910 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_COMPARISON_AFTER_COMPARISON);
21913 parser_lex(parser);
21914 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21915 return (
pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON);
21917 case PM_TOKEN_AMPERSAND_DOT:
21918 case PM_TOKEN_DOT: {
21919 parser_lex(parser);
21924 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
21925 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21926 return (
pm_node_t *) pm_call_node_shorthand_create(parser, node, &
operator, &arguments);
21929 switch (PM_NODE_TYPE(node)) {
21930 case PM_RESCUE_MODIFIER_NODE: {
21933 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21937 case PM_AND_NODE: {
21939 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21940 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21946 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21947 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21957 switch (parser->
current.type) {
21958 case PM_CASE_OPERATOR:
21959 case PM_CASE_KEYWORD:
21960 case PM_TOKEN_CONSTANT:
21961 case PM_TOKEN_IDENTIFIER:
21962 case PM_TOKEN_METHOD_NAME: {
21963 parser_lex(parser);
21973 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21974 pm_call_node_t *call = pm_call_node_call_create(parser, node, &
operator, &message, &arguments);
21977 (previous_binding_power == PM_BINDING_POWER_STATEMENT) &&
21980 match1(parser, PM_TOKEN_COMMA)
21982 return parse_targets_validate(parser, (
pm_node_t *) call, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21987 case PM_TOKEN_DOT_DOT:
21988 case PM_TOKEN_DOT_DOT_DOT: {
21989 parser_lex(parser);
21992 if (token_begins_expression_p(parser->
current.type)) {
21993 right = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21996 return (
pm_node_t *) pm_range_node_create(parser, node, &token, right);
21998 case PM_TOKEN_KEYWORD_IF_MODIFIER: {
22000 parser_lex(parser);
22002 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
22003 return (
pm_node_t *) pm_if_node_modifier_create(parser, node, &keyword, predicate);
22005 case PM_TOKEN_KEYWORD_UNLESS_MODIFIER: {
22007 parser_lex(parser);
22009 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
22010 return (
pm_node_t *) pm_unless_node_modifier_create(parser, node, &keyword, predicate);
22012 case PM_TOKEN_KEYWORD_UNTIL_MODIFIER: {
22013 parser_lex(parser);
22015 pm_statements_node_body_append(parser, statements, node,
true);
22017 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
22018 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);
22020 case PM_TOKEN_KEYWORD_WHILE_MODIFIER: {
22021 parser_lex(parser);
22023 pm_statements_node_body_append(parser, statements, node,
true);
22025 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
22026 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);
22028 case PM_TOKEN_QUESTION_MARK: {
22031 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
22034 parser_lex(parser);
22036 pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_TRUE, (uint16_t) (depth + 1));
22048 context_pop(parser);
22049 pop_block_exits(parser, previous_block_exits);
22050 pm_node_list_free(¤t_block_exits);
22052 return (
pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
22055 accept1(parser, PM_TOKEN_NEWLINE);
22056 expect1(parser, PM_TOKEN_COLON, PM_ERR_TERNARY_COLON);
22059 pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_FALSE, (uint16_t) (depth + 1));
22061 context_pop(parser);
22062 pop_block_exits(parser, previous_block_exits);
22063 pm_node_list_free(¤t_block_exits);
22065 return (
pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
22067 case PM_TOKEN_COLON_COLON: {
22068 parser_lex(parser);
22071 switch (parser->
current.type) {
22072 case PM_TOKEN_CONSTANT: {
22073 parser_lex(parser);
22077 (parser->
current.type == PM_TOKEN_PARENTHESIS_LEFT) ||
22078 (accepts_command_call && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)))
22089 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
22090 path = (
pm_node_t *) pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
22093 path = (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
22097 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
22098 return parse_targets_validate(parser, path, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22103 case PM_CASE_OPERATOR:
22104 case PM_CASE_KEYWORD:
22105 case PM_TOKEN_IDENTIFIER:
22106 case PM_TOKEN_METHOD_NAME: {
22107 parser_lex(parser);
22113 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
22114 pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
22117 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
22118 return parse_targets_validate(parser, (
pm_node_t *) call, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22123 case PM_TOKEN_PARENTHESIS_LEFT: {
22127 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
22129 return (
pm_node_t *) pm_call_node_shorthand_create(parser, node, &delimiter, &arguments);
22132 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
22133 return (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
22137 case PM_TOKEN_KEYWORD_RESCUE_MODIFIER: {
22139 parser_lex(parser);
22140 accept1(parser, PM_TOKEN_NEWLINE);
22142 pm_node_t *value = parse_expression(parser, binding_power,
true,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
22143 context_pop(parser);
22145 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, node, &token, value);
22147 case PM_TOKEN_BRACKET_LEFT: {
22148 parser_lex(parser);
22153 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
22154 pm_accepts_block_stack_push(parser,
true);
22155 parse_arguments(parser, &arguments,
false, PM_TOKEN_BRACKET_RIGHT, (uint16_t) (depth + 1));
22156 pm_accepts_block_stack_pop(parser);
22157 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_EXPECT_RBRACKET);
22164 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
22165 pm_call_node_t *aref = pm_call_node_aref_create(parser, node, &arguments);
22166 return parse_targets_validate(parser, (
pm_node_t *) aref, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22173 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
22174 block = parse_block(parser, (uint16_t) (depth + 1));
22175 pm_arguments_validate_block(parser, &arguments, block);
22176 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
22177 block = parse_block(parser, (uint16_t) (depth + 1));
22180 if (block != NULL) {
22181 if (arguments.
block != NULL) {
22182 pm_parser_err_node(parser, (
pm_node_t *) block, PM_ERR_ARGUMENT_AFTER_BLOCK);
22184 arguments.
arguments = pm_arguments_node_create(parser);
22186 pm_arguments_node_arguments_append(arguments.
arguments, arguments.
block);
22192 return (
pm_node_t *) pm_call_node_aref_create(parser, node, &arguments);
22194 case PM_TOKEN_KEYWORD_IN: {
22200 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
22201 parser_lex(parser);
22204 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));
22207 pm_constant_id_list_free(&captures);
22209 return (
pm_node_t *) pm_match_predicate_node_create(parser, node, pattern, &
operator);
22211 case PM_TOKEN_EQUAL_GREATER: {
22217 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
22218 parser_lex(parser);
22221 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));
22224 pm_constant_id_list_free(&captures);
22226 return (
pm_node_t *) pm_match_required_node_create(parser, node, pattern, &
operator);
22229 assert(
false &&
"unreachable");
22234#undef PM_PARSE_PATTERN_SINGLE
22235#undef PM_PARSE_PATTERN_TOP
22236#undef PM_PARSE_PATTERN_MULTI
22246 (node->
block == NULL || PM_NODE_TYPE_P(node->
block, PM_BLOCK_ARGUMENT_NODE)) &&
22260parse_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) {
22262 pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
22266 pm_node_t *node = parse_expression_prefix(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
22268 switch (PM_NODE_TYPE(node)) {
22269 case PM_MISSING_NODE:
22273 case PM_PRE_EXECUTION_NODE:
22274 case PM_POST_EXECUTION_NODE:
22275 case PM_ALIAS_GLOBAL_VARIABLE_NODE:
22276 case PM_ALIAS_METHOD_NODE:
22277 case PM_MULTI_WRITE_NODE:
22278 case PM_UNDEF_NODE:
22281 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
22291 if ((pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_COMPOSITION) && pm_call_node_command_p((
pm_call_node_t *) node)) {
22295 case PM_SYMBOL_NODE:
22299 if (pm_symbol_node_label_p(node)) {
22310 pm_token_type_t current_token_type;
22313 current_token_type = parser->
current.type,
22314 current_binding_powers = pm_binding_powers[current_token_type],
22315 binding_power <= current_binding_powers.
left &&
22316 current_binding_powers.
binary
22318 node = parse_expression_infix(parser, node, binding_power, current_binding_powers.
right, accepts_command_call, (uint16_t) (depth + 1));
22326 switch (PM_NODE_TYPE(node)) {
22327 case PM_MULTI_WRITE_NODE:
22330 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
22334 case PM_CLASS_VARIABLE_WRITE_NODE:
22335 case PM_CONSTANT_PATH_WRITE_NODE:
22336 case PM_CONSTANT_WRITE_NODE:
22337 case PM_GLOBAL_VARIABLE_WRITE_NODE:
22338 case PM_INSTANCE_VARIABLE_WRITE_NODE:
22339 case PM_LOCAL_VARIABLE_WRITE_NODE:
22342 if (PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
22350 if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
22360 if (current_binding_powers.
nonassoc) {
22363 if (match1(parser, current_token_type)) {
22375 if (PM_NODE_TYPE_P(node, PM_RANGE_NODE) && ((
pm_range_node_t *) node)->right == NULL) {
22376 if (match4(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_DOT, PM_TOKEN_AMPERSAND_DOT)) {
22381 if (PM_BINDING_POWER_TERM <= pm_binding_powers[parser->
current.type].left) {
22384 }
else if (current_binding_powers.
left <= pm_binding_powers[parser->
current.type].left) {
22389 if (accepts_command_call) {
22398 switch (node->
type) {
22399 case PM_CALL_NODE: {
22413 cast->
block == NULL &&
22423 cast->
block != NULL && PM_NODE_TYPE_P(cast->
block, PM_BLOCK_NODE)
22426 accepts_command_call =
false;
22431 case PM_CONSTANT_PATH_NODE:
22434 accepts_command_call =
false;
22449 if (PM_PARSER_COMMAND_LINE_OPTION_P(parser)) {
22450 if (statements == NULL) {
22451 statements = pm_statements_node_create(parser);
22455 pm_arguments_node_arguments_append(
22457 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2))
22460 pm_statements_node_body_append(parser, statements, (
pm_node_t *) pm_call_node_fcall_synthesized_create(
22463 pm_parser_constant_id_constant(parser,
"print", 5)
22467 if (PM_PARSER_COMMAND_LINE_OPTION_N(parser)) {
22468 if (PM_PARSER_COMMAND_LINE_OPTION_A(parser)) {
22469 if (statements == NULL) {
22470 statements = pm_statements_node_create(parser);
22474 pm_arguments_node_arguments_append(
22476 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$;", 2))
22479 pm_global_variable_read_node_t *receiver = pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2));
22480 pm_call_node_t *call = pm_call_node_call_synthesized_create(parser, (
pm_node_t *) receiver,
"split", arguments);
22484 pm_parser_constant_id_constant(parser,
"$F", 2),
22488 pm_statements_node_body_prepend(statements, (
pm_node_t *) write);
22492 pm_arguments_node_arguments_append(
22494 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$/", 2))
22497 if (PM_PARSER_COMMAND_LINE_OPTION_L(parser)) {
22499 pm_keyword_hash_node_elements_append(keywords, (
pm_node_t *) pm_assoc_node_create(
22501 (
pm_node_t *) pm_symbol_node_synthesized_create(parser,
"chomp"),
22503 (
pm_node_t *) pm_true_node_synthesized_create(parser)
22506 pm_arguments_node_arguments_append(arguments, (
pm_node_t *) keywords);
22507 pm_node_flag_set((
pm_node_t *) arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS);
22511 pm_statements_node_body_append(parser, wrapped_statements, (
pm_node_t *) pm_while_node_synthesized_create(
22513 (
pm_node_t *) pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser,
"gets", 4)),
22517 statements = wrapped_statements;
22532 pm_parser_scope_push(parser,
true);
22536 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
22538 parser_lex(parser);
22545 assert(statements->
body.
size > 0);
22546 pm_void_statement_check(parser, statements->
body.
nodes[statements->
body.
size - 1]);
22551 pm_parser_scope_pop(parser);
22556 statements = wrap_statements(parser, statements);
22558 flush_block_exits(parser, previous_block_exits);
22561 pm_node_list_free(¤t_block_exits);
22566 if (statements == NULL) {
22567 statements = pm_statements_node_create(parser);
22568 pm_statements_node_location_set(statements, parser->
start, parser->
start);
22571 return (
pm_node_t *) pm_program_node_create(parser, &locals, statements);
22588pm_strnstr(
const char *big,
const char *little,
size_t big_length) {
22589 size_t little_length = strlen(little);
22591 for (
const char *big_end = big + big_length; big < big_end; big++) {
22592 if (*big == *little && memcmp(big, little, little_length) == 0)
return big;
22599#define pm_parser_warn_shebang_carriage_return(parser, start, length) ((void) 0)
22607pm_parser_warn_shebang_carriage_return(
pm_parser_t *parser,
const uint8_t *start,
size_t length) {
22608 if (length > 2 && start[length - 2] ==
'\r' && start[length - 1] ==
'\n') {
22609 pm_parser_warn(parser, start, start + length, PM_WARN_SHEBANG_CARRIAGE_RETURN);
22620 const char *switches = pm_strnstr(engine,
" -", length);
22621 if (switches == NULL)
return;
22626 (
const uint8_t *) (switches + 1),
22627 length - ((
size_t) (switches - engine)) - 1,
22631 size_t encoding_length;
22634 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22646 assert(source != NULL);
22650 .lex_state = PM_LEX_STATE_BEG,
22651 .enclosure_nesting = 0,
22652 .lambda_enclosure_nesting = -1,
22653 .brace_nesting = 0,
22654 .do_loop_stack = 0,
22655 .accepts_block_stack = 0,
22658 .stack = {{ .mode = PM_LEX_DEFAULT }},
22662 .end = source + size,
22663 .previous = { .type = PM_TOKEN_EOF, .start = source, .end = source },
22664 .current = { .type = PM_TOKEN_EOF, .start = source, .end = source },
22665 .next_start = NULL,
22666 .heredoc_end = NULL,
22667 .data_loc = { .start = NULL, .end = NULL },
22668 .comment_list = { 0 },
22669 .magic_comment_list = { 0 },
22670 .warning_list = { 0 },
22671 .error_list = { 0 },
22672 .current_scope = NULL,
22673 .current_context = NULL,
22675 .encoding_changed_callback = NULL,
22676 .encoding_comment_start = source,
22677 .lex_callback = NULL,
22679 .constant_pool = { 0 },
22680 .newline_list = { 0 },
22684 .explicit_encoding = NULL,
22686 .parsing_eval =
false,
22687 .partial_script =
false,
22688 .command_start =
true,
22689 .recovering =
false,
22690 .encoding_locked =
false,
22691 .encoding_changed =
false,
22692 .pattern_matching_newlines =
false,
22693 .in_keyword_arg =
false,
22694 .current_block_exits = NULL,
22695 .semantic_token_seen =
false,
22697 .current_regular_expression_ascii_only =
false,
22698 .warn_mismatched_indentation =
true
22715 uint32_t constant_size = ((uint32_t) size) / 95;
22716 pm_constant_pool_init(&parser->
constant_pool, constant_size < 4 ? 4 : constant_size);
22721 size_t newline_size = size / 22;
22722 pm_newline_list_init(&parser->
newline_list, source, newline_size < 4 ? 4 : newline_size);
22725 if (options != NULL) {
22734 if (encoding_length > 0) {
22736 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22758 for (
size_t scope_index = 0; scope_index < options->
scopes_count; scope_index++) {
22760 pm_parser_scope_push(parser, scope_index == 0);
22766 for (
size_t local_index = 0; local_index < scope->
locals_count; local_index++) {
22772 void *allocated =
xmalloc(length);
22773 if (allocated == NULL)
continue;
22775 memcpy(allocated, source, length);
22776 pm_parser_local_add_owned(parser, (uint8_t *) allocated, length);
22787 pm_accepts_block_stack_push(parser,
true);
22790 if (size >= 3 && source[0] == 0xef && source[1] == 0xbb && source[2] == 0xbf) {
22803 bool search_shebang = PM_PARSER_COMMAND_LINE_OPTION_X(parser);
22820 const uint8_t *newline = next_newline(parser->
start, parser->
end - parser->
start);
22821 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - parser->
start);
22823 if (length > 2 && parser->
current.end[0] ==
'#' && parser->
current.end[1] ==
'!') {
22824 const char *engine;
22826 if ((engine = pm_strnstr((
const char *) parser->
start,
"ruby", length)) != NULL) {
22827 if (newline != NULL) {
22831 pm_parser_warn_shebang_carriage_return(parser, parser->
start, length + 1);
22836 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) parser->
start)));
22839 search_shebang =
false;
22841 search_shebang =
true;
22847 if (search_shebang) {
22850 bool found_shebang =
false;
22854 const uint8_t *cursor = parser->
start;
22858 const uint8_t *newline = next_newline(cursor, parser->
end - cursor);
22860 while (newline != NULL) {
22861 pm_newline_list_append(&parser->
newline_list, newline);
22863 cursor = newline + 1;
22864 newline = next_newline(cursor, parser->
end - cursor);
22866 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - cursor);
22867 if (length > 2 && cursor[0] ==
'#' && cursor[1] ==
'!') {
22868 const char *engine;
22869 if ((engine = pm_strnstr((
const char *) cursor,
"ruby", length)) != NULL) {
22870 found_shebang =
true;
22872 if (newline != NULL) {
22873 pm_parser_warn_shebang_carriage_return(parser, cursor, length + 1);
22878 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) cursor)));
22886 if (found_shebang) {
22888 parser->
current = (
pm_token_t) { .type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
22890 pm_parser_err(parser, parser->
start, parser->
start, PM_ERR_SCRIPT_NOT_FOUND);
22917 for (node = list->
head; node != NULL; node = next) {
22929pm_magic_comment_list_free(
pm_list_t *list) {
22932 for (node = list->
head; node != NULL; node = next) {
22946 pm_diagnostic_list_free(&parser->
error_list);
22958 pm_parser_scope_pop(parser);
22962 lex_mode_pop(parser);
22971 return parse_program(parser);
22981#define LINE_SIZE 4096
22982 char line[LINE_SIZE];
22984 while (memset(line,
'\n', LINE_SIZE), stream_fgets(line, LINE_SIZE, stream) != NULL) {
22985 size_t length = LINE_SIZE;
22986 while (length > 0 && line[length - 1] ==
'\n') length--;
22988 if (length == LINE_SIZE) {
22993 pm_buffer_append_string(buffer, line, length);
22999 pm_buffer_append_string(buffer, line, length);
23007 if (strncmp(line,
"__END__", 7) == 0)
return false;
23010 if (strncmp(line,
"__END__\n", 8) == 0)
return false;
23013 if (strncmp(line,
"__END__\r\n", 9) == 0)
return false;
23019 if (stream_feof(stream)) {
23038pm_parse_stream_unterminated_heredoc_p(
pm_parser_t *parser) {
23041 for (; diagnostic != NULL; diagnostic = (
pm_diagnostic_t *) diagnostic->node.next) {
23042 if (diagnostic->diag_id == PM_ERR_HEREDOC_TERM) {
23060 bool eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof);
23066 pm_node_destroy(parser, node);
23067 eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof);
23081pm_parse_success_p(
const uint8_t *source,
size_t size,
const char *data) {
23083 pm_options_read(&options, data);
23089 pm_node_destroy(&parser, node);
23098#undef PM_CASE_KEYWORD
23099#undef PM_CASE_OPERATOR
23100#undef PM_CASE_WRITABLE
23101#undef PM_STRING_EMPTY
23102#undef PM_LOCATION_NODE_BASE_VALUE
23103#undef PM_LOCATION_NODE_VALUE
23104#undef PM_LOCATION_NULL_VALUE
23105#undef PM_LOCATION_TOKEN_VALUE
23110#ifndef PRISM_EXCLUDE_SERIALIZATION
23114 pm_buffer_append_string(buffer,
"PRISM", 5);
23118 pm_buffer_append_byte(buffer, PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS ? 1 : 0);
23126 pm_serialize_header(buffer);
23128 pm_buffer_append_byte(buffer,
'\0');
23136pm_serialize_parse(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
23138 pm_options_read(&options, data);
23145 pm_serialize_header(buffer);
23147 pm_buffer_append_byte(buffer,
'\0');
23149 pm_node_destroy(&parser, node);
23162 pm_options_read(&options, data);
23166 pm_serialize_header(buffer);
23168 pm_buffer_append_byte(buffer,
'\0');
23170 pm_node_destroy(&parser, node);
23180pm_serialize_parse_comments(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
23182 pm_options_read(&options, data);
23188 pm_serialize_header(buffer);
23190 pm_buffer_append_varsint(buffer, parser.
start_line);
23193 pm_node_destroy(&parser, node);
23207 PM_SLICE_TYPE_ERROR = -1,
23210 PM_SLICE_TYPE_NONE,
23213 PM_SLICE_TYPE_LOCAL,
23216 PM_SLICE_TYPE_CONSTANT,
23219 PM_SLICE_TYPE_METHOD_NAME
23226pm_slice_type(
const uint8_t *source,
size_t length,
const char *encoding_name) {
23228 const pm_encoding_t *encoding = pm_encoding_find((
const uint8_t *) encoding_name, (
const uint8_t *) (encoding_name + strlen(encoding_name)));
23229 if (encoding == NULL)
return PM_SLICE_TYPE_ERROR;
23232 if (length == 0)
return PM_SLICE_TYPE_NONE;
23235 if ((width = encoding->
alpha_char(source, (ptrdiff_t) length)) != 0) {
23237 }
else if (*source ==
'_') {
23240 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, (ptrdiff_t) length)) > 0)) {
23244 return PM_SLICE_TYPE_NONE;
23248 const uint8_t *end = source + length;
23249 pm_slice_type_t result = encoding->
isupper_char(source, end - source) ? PM_SLICE_TYPE_CONSTANT : PM_SLICE_TYPE_LOCAL;
23255 while (source < end) {
23256 if ((width = encoding->
alnum_char(source, end - source)) != 0) {
23259 }
else if (*source ==
'_') {
23262 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, end - source)) > 0)) {
23272 if (*source ==
'!' || *source ==
'?' || *source ==
'=') {
23274 result = PM_SLICE_TYPE_METHOD_NAME;
23278 return source == end ? result : PM_SLICE_TYPE_NONE;
23285pm_string_query_local(
const uint8_t *source,
size_t length,
const char *encoding_name) {
23286 switch (pm_slice_type(source, length, encoding_name)) {
23287 case PM_SLICE_TYPE_ERROR:
23289 case PM_SLICE_TYPE_NONE:
23290 case PM_SLICE_TYPE_CONSTANT:
23291 case PM_SLICE_TYPE_METHOD_NAME:
23293 case PM_SLICE_TYPE_LOCAL:
23297 assert(
false &&
"unreachable");
23305pm_string_query_constant(
const uint8_t *source,
size_t length,
const char *encoding_name) {
23306 switch (pm_slice_type(source, length, encoding_name)) {
23307 case PM_SLICE_TYPE_ERROR:
23309 case PM_SLICE_TYPE_NONE:
23310 case PM_SLICE_TYPE_LOCAL:
23311 case PM_SLICE_TYPE_METHOD_NAME:
23313 case PM_SLICE_TYPE_CONSTANT:
23317 assert(
false &&
"unreachable");
23325pm_string_query_method_name(
const uint8_t *source,
size_t length,
const char *encoding_name) {
23326#define B(p) ((p) ? PM_STRING_QUERY_TRUE : PM_STRING_QUERY_FALSE)
23327#define C1(c) (*source == c)
23328#define C2(s) (memcmp(source, s, 2) == 0)
23329#define C3(s) (memcmp(source, s, 3) == 0)
23331 switch (pm_slice_type(source, length, encoding_name)) {
23332 case PM_SLICE_TYPE_ERROR:
23334 case PM_SLICE_TYPE_NONE:
23336 case PM_SLICE_TYPE_LOCAL:
23338 return B((length != 2) || (source[0] !=
'_') || (source[1] ==
'0') || !pm_char_is_decimal_digit(source[1]));
23339 case PM_SLICE_TYPE_CONSTANT:
23341 case PM_SLICE_TYPE_METHOD_NAME:
23348 return B(C1(
'&') || C1(
'`') || C1(
'!') || C1(
'^') || C1(
'>') || C1(
'<') || C1(
'-') || C1(
'%') || C1(
'|') || C1(
'+') || C1(
'/') || C1(
'*') || C1(
'~'));
23350 return B(C2(
"!=") || C2(
"!~") || C2(
"[]") || C2(
"==") || C2(
"=~") || C2(
">=") || C2(
">>") || C2(
"<=") || C2(
"<<") || C2(
"**"));
23352 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.