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,
2653 .equal_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2665static inline pm_node_flags_t
2666pm_call_node_ignore_visibility_flag(const pm_node_t *receiver) {
2667 return PM_NODE_TYPE_P(receiver, PM_SELF_NODE) ? PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY : 0;
2674static pm_call_node_t *
2675pm_call_node_aref_create(pm_parser_t *parser, pm_node_t *receiver, pm_arguments_t *arguments) {
2676 pm_assert_value_expression(parser, receiver);
2678 pm_node_flags_t flags = pm_call_node_ignore_visibility_flag(receiver);
2679 if (arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_ARGUMENT_NODE)) {
2680 flags |= PM_CALL_NODE_FLAGS_INDEX;
2683 pm_call_node_t *node = pm_call_node_create(parser, flags);
2685 node->base.location.start = receiver->location.start;
2686 node->base.location.end = pm_arguments_end(arguments);
2688 node->receiver = receiver;
2689 node->message_loc.start = arguments->opening_loc.start;
2690 node->message_loc.end = arguments->closing_loc.end;
2692 node->opening_loc = arguments->opening_loc;
2693 node->arguments = arguments->arguments;
2694 node->closing_loc = arguments->closing_loc;
2695 node->block = arguments->block;
2697 node->name = pm_parser_constant_id_constant(parser, "[]", 2);
2704static pm_call_node_t *
2705pm_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) {
2706 pm_assert_value_expression(parser, receiver);
2707 pm_assert_value_expression(parser, argument);
2709 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver) | flags);
2711 node->base.location.start = MIN(receiver->location.start, argument->location.start);
2712 node->base.location.end = MAX(receiver->location.end, argument->location.end);
2714 node->receiver = receiver;
2715 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2717 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
2718 pm_arguments_node_arguments_append(arguments, argument);
2719 node->arguments = arguments;
2721 node->name = pm_parser_constant_id_token(parser, operator);
2725static const uint8_t * parse_operator_symbol_name(const pm_token_t *);
2730static pm_call_node_t *
2731pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_token_t *message, pm_arguments_t *arguments) {
2732 pm_assert_value_expression(parser, receiver);
2734 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2736 node->base.location.start = receiver->location.start;
2737 const uint8_t *end = pm_arguments_end(arguments);
2741 node->base.location.end = end;
2743 node->receiver = receiver;
2744 node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2745 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2746 node->opening_loc = arguments->opening_loc;
2747 node->arguments = arguments->arguments;
2748 node->closing_loc = arguments->closing_loc;
2749 node->block = arguments->block;
2751 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2752 pm_node_flag_set((pm_node_t *)node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2759 node->name = pm_parser_constant_id_location(parser, message->start, parse_operator_symbol_name(message));
2766static pm_call_node_t *
2767pm_call_node_call_synthesized_create(pm_parser_t *parser, pm_node_t *receiver, const char *message, pm_arguments_node_t *arguments) {
2768 pm_call_node_t *node = pm_call_node_create(parser, 0);
2769 node->base.location.start = parser->start;
2770 node->base.location.end = parser->end;
2772 node->receiver = receiver;
2773 node->call_operator_loc = (pm_location_t) { .start = NULL, .end = NULL };
2774 node->message_loc = (pm_location_t) { .start = NULL, .end = NULL };
2775 node->arguments = arguments;
2777 node->name = pm_parser_constant_id_constant(parser, message, strlen(message));
2785static pm_call_node_t *
2786pm_call_node_fcall_create(pm_parser_t *parser, pm_token_t *message, pm_arguments_t *arguments) {
2787 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2789 node->base.location.start = message->start;
2790 node->base.location.end = pm_arguments_end(arguments);
2792 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2793 node->opening_loc = arguments->opening_loc;
2794 node->arguments = arguments->arguments;
2795 node->closing_loc = arguments->closing_loc;
2796 node->block = arguments->block;
2798 node->name = pm_parser_constant_id_token(parser, message);
2806static pm_call_node_t *
2807pm_call_node_fcall_synthesized_create(pm_parser_t *parser, pm_arguments_node_t *arguments, pm_constant_id_t name) {
2808 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2810 node->base.location = PM_LOCATION_NULL_VALUE(parser);
2811 node->arguments = arguments;
2820static pm_call_node_t *
2821pm_call_node_not_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *message, pm_arguments_t *arguments) {
2822 pm_assert_value_expression(parser, receiver);
2823 if (receiver != NULL) pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
2825 pm_call_node_t *node = pm_call_node_create(parser, receiver == NULL ? 0 : pm_call_node_ignore_visibility_flag(receiver));
2827 node->base.location.start = message->start;
2828 if (arguments->closing_loc.start != NULL) {
2829 node->base.location.end = arguments->closing_loc.end;
2831 assert(receiver != NULL);
2832 node->base.location.end = receiver->location.end;
2835 node->receiver = receiver;
2836 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2837 node->opening_loc = arguments->opening_loc;
2838 node->arguments = arguments->arguments;
2839 node->closing_loc = arguments->closing_loc;
2841 node->name = pm_parser_constant_id_constant(parser, "!", 1);
2848static pm_call_node_t *
2849pm_call_node_shorthand_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_arguments_t *arguments) {
2850 pm_assert_value_expression(parser, receiver);
2852 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2854 node->base.location.start = receiver->location.start;
2855 node->base.location.end = pm_arguments_end(arguments);
2857 node->receiver = receiver;
2858 node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2859 node->opening_loc = arguments->opening_loc;
2860 node->arguments = arguments->arguments;
2861 node->closing_loc = arguments->closing_loc;
2862 node->block = arguments->block;
2864 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2865 pm_node_flag_set((pm_node_t *)node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2868 node->name = pm_parser_constant_id_constant(parser, "call", 4);
2875static pm_call_node_t *
2876pm_call_node_unary_create(pm_parser_t *parser, pm_token_t *operator, pm_node_t *receiver, const char *name) {
2877 pm_assert_value_expression(parser, receiver);
2879 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2881 node->base.location.start = operator->start;
2882 node->base.location.end = receiver->location.end;
2884 node->receiver = receiver;
2885 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2887 node->name = pm_parser_constant_id_constant(parser, name, strlen(name));
2895static pm_call_node_t *
2896pm_call_node_variable_call_create(pm_parser_t *parser, pm_token_t *message) {
2897 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2899 node->base.location = PM_LOCATION_TOKEN_VALUE(message);
2900 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2902 node->name = pm_parser_constant_id_token(parser, message);
2911pm_call_node_writable_p(const pm_parser_t *parser, const pm_call_node_t *node) {
2913 (node->message_loc.start != NULL) &&
2914 (node->message_loc.end[-1] != '!') &&
2915 (node->message_loc.end[-1] != '?') &&
2916 char_is_identifier_start(parser, node->message_loc.start, parser->end - node->message_loc.start) &&
2917 (node->opening_loc.start == NULL) &&
2918 (node->arguments == NULL) &&
2919 (node->block == NULL)
2927pm_call_write_read_name_init(pm_parser_t *parser, pm_constant_id_t *read_name, pm_constant_id_t *write_name) {
2928 pm_constant_t *write_constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *write_name);
2930 if (write_constant->length > 0) {
2931 size_t length = write_constant->length - 1;
2933 void *memory = xmalloc(length);
2934 memcpy(memory, write_constant->start, length);
2936 *read_name = pm_constant_pool_insert_owned(&parser->constant_pool, (uint8_t *) memory, length);
2938 // We can get here if the message was missing because of a syntax error.
2939 *read_name = pm_parser_constant_id_constant(parser, "", 0);
2946static pm_call_and_write_node_t *
2947pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2948 assert(target->block == NULL);
2949 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
2950 pm_call_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_and_write_node_t);
2952 *node = (pm_call_and_write_node_t) {
2954 .type = PM_CALL_AND_WRITE_NODE,
2955 .flags = target->base.flags,
2956 .node_id = PM_NODE_IDENTIFY(parser),
2958 .start = target->base.location.start,
2959 .end = value->location.end
2962 .receiver = target->receiver,
2963 .call_operator_loc = target->call_operator_loc,
2964 .message_loc = target->message_loc,
2966 .write_name = target->name,
2967 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2971 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
2973 // Here we're going to free the target, since it is no longer necessary.
2974 // However, we don't want to call `pm_node_destroy` because we want to keep
2975 // around all of its children since we just reused them.
2986pm_index_arguments_check(pm_parser_t *parser, const pm_arguments_node_t *arguments, const pm_node_t *block) {
2987 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) {
2988 if (arguments != NULL && PM_NODE_FLAG_P(arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) {
2990 PM_NODE_LIST_FOREACH(&arguments->arguments, index, node) {
2991 if (PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE)) {
2992 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_INDEX_KEYWORDS);
2998 if (block != NULL) {
2999 pm_parser_err_node(parser, block, PM_ERR_UNEXPECTED_INDEX_BLOCK);
3007static pm_index_and_write_node_t *
3008pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3009 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3010 pm_index_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_and_write_node_t);
3012 pm_index_arguments_check(parser, target->arguments, target->block);
3014 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3015 *node = (pm_index_and_write_node_t) {
3017 .type = PM_INDEX_AND_WRITE_NODE,
3018 .flags = target->base.flags,
3019 .node_id = PM_NODE_IDENTIFY(parser),
3021 .start = target->base.location.start,
3022 .end = value->location.end
3025 .receiver = target->receiver,
3026 .call_operator_loc = target->call_operator_loc,
3027 .opening_loc = target->opening_loc,
3028 .arguments = target->arguments,
3029 .closing_loc = target->closing_loc,
3030 .block = (pm_block_argument_node_t *) target->block,
3031 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3035 // Here we're going to free the target, since it is no longer necessary.
3036 // However, we don't want to call `pm_node_destroy` because we want to keep
3037 // around all of its children since we just reused them.
3046static pm_call_operator_write_node_t *
3047pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3048 assert(target->block == NULL);
3049 pm_call_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_operator_write_node_t);
3051 *node = (pm_call_operator_write_node_t) {
3053 .type = PM_CALL_OPERATOR_WRITE_NODE,
3054 .flags = target->base.flags,
3055 .node_id = PM_NODE_IDENTIFY(parser),
3057 .start = target->base.location.start,
3058 .end = value->location.end
3061 .receiver = target->receiver,
3062 .call_operator_loc = target->call_operator_loc,
3063 .message_loc = target->message_loc,
3065 .write_name = target->name,
3066 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
3067 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3071 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3073 // Here we're going to free the target, since it is no longer necessary.
3074 // However, we don't want to call `pm_node_destroy` because we want to keep
3075 // around all of its children since we just reused them.
3084static pm_index_operator_write_node_t *
3085pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3086 pm_index_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_operator_write_node_t);
3088 pm_index_arguments_check(parser, target->arguments, target->block);
3090 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3091 *node = (pm_index_operator_write_node_t) {
3093 .type = PM_INDEX_OPERATOR_WRITE_NODE,
3094 .flags = target->base.flags,
3095 .node_id = PM_NODE_IDENTIFY(parser),
3097 .start = target->base.location.start,
3098 .end = value->location.end
3101 .receiver = target->receiver,
3102 .call_operator_loc = target->call_operator_loc,
3103 .opening_loc = target->opening_loc,
3104 .arguments = target->arguments,
3105 .closing_loc = target->closing_loc,
3106 .block = (pm_block_argument_node_t *) target->block,
3107 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
3108 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3112 // Here we're going to free the target, since it is no longer necessary.
3113 // However, we don't want to call `pm_node_destroy` because we want to keep
3114 // around all of its children since we just reused them.
3123static pm_call_or_write_node_t *
3124pm_call_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3125 assert(target->block == NULL);
3126 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3127 pm_call_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_or_write_node_t);
3129 *node = (pm_call_or_write_node_t) {
3131 .type = PM_CALL_OR_WRITE_NODE,
3132 .flags = target->base.flags,
3133 .node_id = PM_NODE_IDENTIFY(parser),
3135 .start = target->base.location.start,
3136 .end = value->location.end
3139 .receiver = target->receiver,
3140 .call_operator_loc = target->call_operator_loc,
3141 .message_loc = target->message_loc,
3143 .write_name = target->name,
3144 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3148 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3150 // Here we're going to free the target, since it is no longer necessary.
3151 // However, we don't want to call `pm_node_destroy` because we want to keep
3152 // around all of its children since we just reused them.
3161static pm_index_or_write_node_t *
3162pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3163 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3164 pm_index_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_or_write_node_t);
3166 pm_index_arguments_check(parser, target->arguments, target->block);
3168 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3169 *node = (pm_index_or_write_node_t) {
3171 .type = PM_INDEX_OR_WRITE_NODE,
3172 .flags = target->base.flags,
3173 .node_id = PM_NODE_IDENTIFY(parser),
3175 .start = target->base.location.start,
3176 .end = value->location.end
3179 .receiver = target->receiver,
3180 .call_operator_loc = target->call_operator_loc,
3181 .opening_loc = target->opening_loc,
3182 .arguments = target->arguments,
3183 .closing_loc = target->closing_loc,
3184 .block = (pm_block_argument_node_t *) target->block,
3185 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3189 // Here we're going to free the target, since it is no longer necessary.
3190 // However, we don't want to call `pm_node_destroy` because we want to keep
3191 // around all of its children since we just reused them.
3201static pm_call_target_node_t *
3202pm_call_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3203 pm_call_target_node_t *node = PM_NODE_ALLOC(parser, pm_call_target_node_t);
3205 *node = (pm_call_target_node_t) {
3207 .type = PM_CALL_TARGET_NODE,
3208 .flags = target->base.flags,
3209 .node_id = PM_NODE_IDENTIFY(parser),
3210 .location = target->base.location
3212 .receiver = target->receiver,
3213 .call_operator_loc = target->call_operator_loc,
3214 .name = target->name,
3215 .message_loc = target->message_loc
3218 // Here we're going to free the target, since it is no longer necessary.
3219 // However, we don't want to call `pm_node_destroy` because we want to keep
3220 // around all of its children since we just reused them.
3230static pm_index_target_node_t *
3231pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3232 pm_index_target_node_t *node = PM_NODE_ALLOC(parser, pm_index_target_node_t);
3233 pm_node_flags_t flags = target->base.flags;
3235 pm_index_arguments_check(parser, target->arguments, target->block);
3237 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3238 *node = (pm_index_target_node_t) {
3240 .type = PM_INDEX_TARGET_NODE,
3241 .flags = flags | PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE,
3242 .node_id = PM_NODE_IDENTIFY(parser),
3243 .location = target->base.location
3245 .receiver = target->receiver,
3246 .opening_loc = target->opening_loc,
3247 .arguments = target->arguments,
3248 .closing_loc = target->closing_loc,
3249 .block = (pm_block_argument_node_t *) target->block,
3252 // Here we're going to free the target, since it is no longer necessary.
3253 // However, we don't want to call `pm_node_destroy` because we want to keep
3254 // around all of its children since we just reused them.
3263static pm_capture_pattern_node_t *
3264pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_local_variable_target_node_t *target, const pm_token_t *operator) {
3265 pm_capture_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_capture_pattern_node_t);
3267 *node = (pm_capture_pattern_node_t) {
3269 .type = PM_CAPTURE_PATTERN_NODE,
3270 .node_id = PM_NODE_IDENTIFY(parser),
3272 .start = value->location.start,
3273 .end = target->base.location.end
3278 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
3287static pm_case_node_t *
3288pm_case_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3289 pm_case_node_t *node = PM_NODE_ALLOC(parser, pm_case_node_t);
3291 *node = (pm_case_node_t) {
3293 .type = PM_CASE_NODE,
3294 .node_id = PM_NODE_IDENTIFY(parser),
3296 .start = case_keyword->start,
3297 .end = end_keyword->end
3300 .predicate = predicate,
3301 .else_clause = NULL,
3302 .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
3303 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3314pm_case_node_condition_append(pm_case_node_t *node, pm_node_t *condition) {
3315 assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
3317 pm_node_list_append(&node->conditions, condition);
3318 node->base.location.end = condition->location.end;
3325pm_case_node_else_clause_set(pm_case_node_t *node, pm_else_node_t *else_clause) {
3326 node->else_clause = else_clause;
3327 node->base.location.end = else_clause->base.location.end;
3334pm_case_node_end_keyword_loc_set(pm_case_node_t *node, const pm_token_t *end_keyword) {
3335 node->base.location.end = end_keyword->end;
3336 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
3342static pm_case_match_node_t *
3343pm_case_match_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3344 pm_case_match_node_t *node = PM_NODE_ALLOC(parser, pm_case_match_node_t);
3346 *node = (pm_case_match_node_t) {
3348 .type = PM_CASE_MATCH_NODE,
3349 .node_id = PM_NODE_IDENTIFY(parser),
3351 .start = case_keyword->start,
3352 .end = end_keyword->end
3355 .predicate = predicate,
3356 .else_clause = NULL,
3357 .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
3358 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3369pm_case_match_node_condition_append(pm_case_match_node_t *node, pm_node_t *condition) {
3370 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
3372 pm_node_list_append(&node->conditions, condition);
3373 node->base.location.end = condition->location.end;
3380pm_case_match_node_else_clause_set(pm_case_match_node_t *node, pm_else_node_t *else_clause) {
3381 node->else_clause = else_clause;
3382 node->base.location.end = else_clause->base.location.end;
3389pm_case_match_node_end_keyword_loc_set(pm_case_match_node_t *node, const pm_token_t *end_keyword) {
3390 node->base.location.end = end_keyword->end;
3391 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
3397static pm_class_node_t *
3398pm_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) {
3399 pm_class_node_t *node = PM_NODE_ALLOC(parser, pm_class_node_t);
3401 *node = (pm_class_node_t) {
3403 .type = PM_CLASS_NODE,
3404 .node_id = PM_NODE_IDENTIFY(parser),
3405 .location = { .start = class_keyword->start, .end = end_keyword->end },
3408 .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
3409 .constant_path = constant_path,
3410 .inheritance_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(inheritance_operator),
3411 .superclass = superclass,
3413 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3414 .name = pm_parser_constant_id_token(parser, name)
3423static pm_class_variable_and_write_node_t *
3424pm_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) {
3425 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3426 pm_class_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_and_write_node_t);
3428 *node = (pm_class_variable_and_write_node_t) {
3430 .type = PM_CLASS_VARIABLE_AND_WRITE_NODE,
3431 .node_id = PM_NODE_IDENTIFY(parser),
3433 .start = target->base.location.start,
3434 .end = value->location.end
3437 .name = target->name,
3438 .name_loc = target->base.location,
3439 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3449static pm_class_variable_operator_write_node_t *
3450pm_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) {
3451 pm_class_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_operator_write_node_t);
3453 *node = (pm_class_variable_operator_write_node_t) {
3455 .type = PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE,
3456 .node_id = PM_NODE_IDENTIFY(parser),
3458 .start = target->base.location.start,
3459 .end = value->location.end
3462 .name = target->name,
3463 .name_loc = target->base.location,
3464 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3466 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3475static pm_class_variable_or_write_node_t *
3476pm_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) {
3477 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3478 pm_class_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_or_write_node_t);
3480 *node = (pm_class_variable_or_write_node_t) {
3482 .type = PM_CLASS_VARIABLE_OR_WRITE_NODE,
3483 .node_id = PM_NODE_IDENTIFY(parser),
3485 .start = target->base.location.start,
3486 .end = value->location.end
3489 .name = target->name,
3490 .name_loc = target->base.location,
3491 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3501static pm_class_variable_read_node_t *
3502pm_class_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
3503 assert(token->type == PM_TOKEN_CLASS_VARIABLE);
3504 pm_class_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_read_node_t);
3506 *node = (pm_class_variable_read_node_t) {
3508 .type = PM_CLASS_VARIABLE_READ_NODE,
3509 .node_id = PM_NODE_IDENTIFY(parser),
3510 .location = PM_LOCATION_TOKEN_VALUE(token)
3512 .name = pm_parser_constant_id_token(parser, token)
3524static inline pm_node_flags_t
3525pm_implicit_array_write_flags(const pm_node_t *node, pm_node_flags_t flags) {
3526 if (PM_NODE_TYPE_P(node, PM_ARRAY_NODE) && ((const pm_array_node_t *) node)->opening_loc.start == NULL) {
3535static pm_class_variable_write_node_t *
3536pm_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) {
3537 pm_class_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_write_node_t);
3539 *node = (pm_class_variable_write_node_t) {
3541 .type = PM_CLASS_VARIABLE_WRITE_NODE,
3542 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3543 .node_id = PM_NODE_IDENTIFY(parser),
3545 .start = read_node->base.location.start,
3546 .end = value->location.end
3549 .name = read_node->name,
3550 .name_loc = PM_LOCATION_NODE_VALUE((pm_node_t *) read_node),
3551 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3561static pm_constant_path_and_write_node_t *
3562pm_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) {
3563 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3564 pm_constant_path_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_and_write_node_t);
3566 *node = (pm_constant_path_and_write_node_t) {
3568 .type = PM_CONSTANT_PATH_AND_WRITE_NODE,
3569 .node_id = PM_NODE_IDENTIFY(parser),
3571 .start = target->base.location.start,
3572 .end = value->location.end
3576 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3586static pm_constant_path_operator_write_node_t *
3587pm_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) {
3588 pm_constant_path_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_operator_write_node_t);
3590 *node = (pm_constant_path_operator_write_node_t) {
3592 .type = PM_CONSTANT_PATH_OPERATOR_WRITE_NODE,
3593 .node_id = PM_NODE_IDENTIFY(parser),
3595 .start = target->base.location.start,
3596 .end = value->location.end
3600 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3602 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3611static pm_constant_path_or_write_node_t *
3612pm_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) {
3613 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3614 pm_constant_path_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_or_write_node_t);
3616 *node = (pm_constant_path_or_write_node_t) {
3618 .type = PM_CONSTANT_PATH_OR_WRITE_NODE,
3619 .node_id = PM_NODE_IDENTIFY(parser),
3621 .start = target->base.location.start,
3622 .end = value->location.end
3626 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3636static pm_constant_path_node_t *
3637pm_constant_path_node_create(pm_parser_t *parser, pm_node_t *parent, const pm_token_t *delimiter, const pm_token_t *name_token) {
3638 pm_assert_value_expression(parser, parent);
3639 pm_constant_path_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_node_t);
3641 pm_constant_id_t name = PM_CONSTANT_ID_UNSET;
3642 if (name_token->type == PM_TOKEN_CONSTANT) {
3643 name = pm_parser_constant_id_token(parser, name_token);
3646 *node = (pm_constant_path_node_t) {
3648 .type = PM_CONSTANT_PATH_NODE,
3649 .node_id = PM_NODE_IDENTIFY(parser),
3651 .start = parent == NULL ? delimiter->start : parent->location.start,
3652 .end = name_token->end
3657 .delimiter_loc = PM_LOCATION_TOKEN_VALUE(delimiter),
3658 .name_loc = PM_LOCATION_TOKEN_VALUE(name_token)
3667static pm_constant_path_write_node_t *
3668pm_constant_path_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3669 pm_constant_path_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_write_node_t);
3671 *node = (pm_constant_path_write_node_t) {
3673 .type = PM_CONSTANT_PATH_WRITE_NODE,
3674 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3675 .node_id = PM_NODE_IDENTIFY(parser),
3677 .start = target->base.location.start,
3678 .end = value->location.end
3682 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3692static pm_constant_and_write_node_t *
3693pm_constant_and_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3694 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3695 pm_constant_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_and_write_node_t);
3697 *node = (pm_constant_and_write_node_t) {
3699 .type = PM_CONSTANT_AND_WRITE_NODE,
3700 .node_id = PM_NODE_IDENTIFY(parser),
3702 .start = target->base.location.start,
3703 .end = value->location.end
3706 .name = target->name,
3707 .name_loc = target->base.location,
3708 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3718static pm_constant_operator_write_node_t *
3719pm_constant_operator_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3720 pm_constant_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_operator_write_node_t);
3722 *node = (pm_constant_operator_write_node_t) {
3724 .type = PM_CONSTANT_OPERATOR_WRITE_NODE,
3725 .node_id = PM_NODE_IDENTIFY(parser),
3727 .start = target->base.location.start,
3728 .end = value->location.end
3731 .name = target->name,
3732 .name_loc = target->base.location,
3733 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3735 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3744static pm_constant_or_write_node_t *
3745pm_constant_or_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3746 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3747 pm_constant_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_or_write_node_t);
3749 *node = (pm_constant_or_write_node_t) {
3751 .type = PM_CONSTANT_OR_WRITE_NODE,
3752 .node_id = PM_NODE_IDENTIFY(parser),
3754 .start = target->base.location.start,
3755 .end = value->location.end
3758 .name = target->name,
3759 .name_loc = target->base.location,
3760 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3770static pm_constant_read_node_t *
3771pm_constant_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
3772 assert(name->type == PM_TOKEN_CONSTANT || name->type == PM_TOKEN_MISSING);
3773 pm_constant_read_node_t *node = PM_NODE_ALLOC(parser, pm_constant_read_node_t);
3775 *node = (pm_constant_read_node_t) {
3777 .type = PM_CONSTANT_READ_NODE,
3778 .node_id = PM_NODE_IDENTIFY(parser),
3779 .location = PM_LOCATION_TOKEN_VALUE(name)
3781 .name = pm_parser_constant_id_token(parser, name)
3790static pm_constant_write_node_t *
3791pm_constant_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3792 pm_constant_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_write_node_t);
3794 *node = (pm_constant_write_node_t) {
3796 .type = PM_CONSTANT_WRITE_NODE,
3797 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3798 .node_id = PM_NODE_IDENTIFY(parser),
3800 .start = target->base.location.start,
3801 .end = value->location.end
3804 .name = target->name,
3805 .name_loc = target->base.location,
3806 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3817pm_def_node_receiver_check(pm_parser_t *parser, const pm_node_t *node) {
3818 switch (PM_NODE_TYPE(node)) {
3819 case PM_BEGIN_NODE: {
3820 const pm_begin_node_t *cast = (pm_begin_node_t *) node;
3821 if (cast->statements != NULL) pm_def_node_receiver_check(parser, (pm_node_t *) cast->statements);
3824 case PM_PARENTHESES_NODE: {
3825 const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node;
3826 if (cast->body != NULL) pm_def_node_receiver_check(parser, cast->body);
3829 case PM_STATEMENTS_NODE: {
3830 const pm_statements_node_t *cast = (const pm_statements_node_t *) node;
3831 pm_def_node_receiver_check(parser, cast->body.nodes[cast->body.size - 1]);
3836 case PM_IMAGINARY_NODE:
3837 case PM_INTEGER_NODE:
3838 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
3839 case PM_INTERPOLATED_STRING_NODE:
3840 case PM_INTERPOLATED_SYMBOL_NODE:
3841 case PM_INTERPOLATED_X_STRING_NODE:
3842 case PM_RATIONAL_NODE:
3843 case PM_REGULAR_EXPRESSION_NODE:
3844 case PM_SOURCE_ENCODING_NODE:
3845 case PM_SOURCE_FILE_NODE:
3846 case PM_SOURCE_LINE_NODE:
3847 case PM_STRING_NODE:
3848 case PM_SYMBOL_NODE:
3849 case PM_X_STRING_NODE:
3850 pm_parser_err_node(parser, node, PM_ERR_SINGLETON_FOR_LITERALS);
3860static pm_def_node_t *
3862 pm_parser_t *parser,
3863 pm_constant_id_t name,
3864 const pm_token_t *name_loc,
3865 pm_node_t *receiver,
3866 pm_parameters_node_t *parameters,
3868 pm_constant_id_list_t *locals,
3869 const pm_token_t *def_keyword,
3870 const pm_token_t *operator,
3871 const pm_token_t *lparen,
3872 const pm_token_t *rparen,
3873 const pm_token_t *equal,
3874 const pm_token_t *end_keyword
3876 pm_def_node_t *node = PM_NODE_ALLOC(parser, pm_def_node_t);
3879 if (end_keyword->type == PM_TOKEN_NOT_PROVIDED) {
3880 end = body->location.end;
3882 end = end_keyword->end;
3885 if (receiver != NULL) {
3886 pm_def_node_receiver_check(parser, receiver);
3889 *node = (pm_def_node_t) {
3891 .type = PM_DEF_NODE,
3892 .node_id = PM_NODE_IDENTIFY(parser),
3893 .location = { .start = def_keyword->start, .end = end },
3896 .name_loc = PM_LOCATION_TOKEN_VALUE(name_loc),
3897 .receiver = receiver,
3898 .parameters = parameters,
3901 .def_keyword_loc = PM_LOCATION_TOKEN_VALUE(def_keyword),
3902 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3903 .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
3904 .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
3905 .equal_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(equal),
3906 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
3915static pm_defined_node_t *
3916pm_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) {
3917 pm_defined_node_t *node = PM_NODE_ALLOC(parser, pm_defined_node_t);
3919 *node = (pm_defined_node_t) {
3921 .type = PM_DEFINED_NODE,
3922 .node_id = PM_NODE_IDENTIFY(parser),
3924 .start = keyword_loc->start,
3925 .end = (rparen->type == PM_TOKEN_NOT_PROVIDED ? value->location.end : rparen->end)
3928 .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
3930 .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
3931 .keyword_loc = *keyword_loc
3940static pm_else_node_t *
3941pm_else_node_create(pm_parser_t *parser, const pm_token_t *else_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
3942 pm_else_node_t *node = PM_NODE_ALLOC(parser, pm_else_node_t);
3943 const uint8_t *end = NULL;
3944 if ((end_keyword->type == PM_TOKEN_NOT_PROVIDED) && (statements != NULL)) {
3945 end = statements->base.location.end;
3947 end = end_keyword->end;
3950 *node = (pm_else_node_t) {
3952 .type = PM_ELSE_NODE,
3953 .node_id = PM_NODE_IDENTIFY(parser),
3955 .start = else_keyword->start,
3959 .else_keyword_loc = PM_LOCATION_TOKEN_VALUE(else_keyword),
3960 .statements = statements,
3961 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
3970static pm_embedded_statements_node_t *
3971pm_embedded_statements_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
3972 pm_embedded_statements_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_statements_node_t);
3974 *node = (pm_embedded_statements_node_t) {
3976 .type = PM_EMBEDDED_STATEMENTS_NODE,
3977 .node_id = PM_NODE_IDENTIFY(parser),
3979 .start = opening->start,
3983 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
3984 .statements = statements,
3985 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
3994static pm_embedded_variable_node_t *
3995pm_embedded_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
3996 pm_embedded_variable_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_variable_node_t);
3998 *node = (pm_embedded_variable_node_t) {
4000 .type = PM_EMBEDDED_VARIABLE_NODE,
4001 .node_id = PM_NODE_IDENTIFY(parser),
4003 .start = operator->start,
4004 .end = variable->location.end
4007 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4008 .variable = variable
4017static pm_ensure_node_t *
4018pm_ensure_node_create(pm_parser_t *parser, const pm_token_t *ensure_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
4019 pm_ensure_node_t *node = PM_NODE_ALLOC(parser, pm_ensure_node_t);
4021 *node = (pm_ensure_node_t) {
4023 .type = PM_ENSURE_NODE,
4024 .node_id = PM_NODE_IDENTIFY(parser),
4026 .start = ensure_keyword->start,
4027 .end = end_keyword->end
4030 .ensure_keyword_loc = PM_LOCATION_TOKEN_VALUE(ensure_keyword),
4031 .statements = statements,
4032 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
4041static pm_false_node_t *
4042pm_false_node_create(pm_parser_t *parser, const pm_token_t *token) {
4043 assert(token->type == PM_TOKEN_KEYWORD_FALSE);
4044 pm_false_node_t *node = PM_NODE_ALLOC(parser, pm_false_node_t);
4046 *node = (pm_false_node_t) {{
4047 .type = PM_FALSE_NODE,
4048 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4049 .node_id = PM_NODE_IDENTIFY(parser),
4050 .location = PM_LOCATION_TOKEN_VALUE(token)
4060static pm_find_pattern_node_t *
4061pm_find_pattern_node_create(pm_parser_t *parser, pm_node_list_t *nodes) {
4062 pm_find_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_find_pattern_node_t);
4064 pm_node_t *left = nodes->nodes[0];
4065 assert(PM_NODE_TYPE_P(left, PM_SPLAT_NODE));
4066 pm_splat_node_t *left_splat_node = (pm_splat_node_t *) left;
4070 if (nodes->size == 1) {
4071 right = (pm_node_t *) pm_missing_node_create(parser, left->location.end, left->location.end);
4073 right = nodes->nodes[nodes->size - 1];
4074 assert(PM_NODE_TYPE_P(right, PM_SPLAT_NODE));
4077#if PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS
4078 // FindPatternNode#right is typed as SplatNode in this case, so replace the potential MissingNode with a SplatNode.
4079 // The resulting AST will anyway be ignored, but this file still needs to compile.
4080 pm_splat_node_t *right_splat_node = PM_NODE_TYPE_P(right, PM_SPLAT_NODE) ? (pm_splat_node_t *) right : left_splat_node;
4082 pm_node_t *right_splat_node = right;
4084 *node = (pm_find_pattern_node_t) {
4086 .type = PM_FIND_PATTERN_NODE,
4087 .node_id = PM_NODE_IDENTIFY(parser),
4089 .start = left->location.start,
4090 .end = right->location.end,
4094 .left = left_splat_node,
4095 .right = right_splat_node,
4097 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4098 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4101 // For now we're going to just copy over each pointer manually. This could be
4102 // much more efficient, as we could instead resize the node list to only point
4104 for (size_t index = 1; index < nodes->size - 1; index++) {
4105 pm_node_list_append(&node->requireds, nodes->nodes[index]);
4116pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
4117 ptrdiff_t diff = token->end - token->start;
4118 if (diff <= 0) return 0.0;
4120 // First, get a buffer of the content.
4121 size_t length = (size_t) diff;
4122 char *buffer = xmalloc(sizeof(char) * (length + 1));
4123 memcpy((void *) buffer, token->start, length);
4125 // Next, determine if we need to replace the decimal point because of
4126 // locale-specific options, and then normalize them if we have to.
4127 char decimal_point = *localeconv()->decimal_point;
4128 if (decimal_point != '.') {
4129 for (size_t index = 0; index < length; index++) {
4130 if (buffer[index] == '.') buffer[index] = decimal_point;
4134 // Next, handle underscores by removing them from the buffer.
4135 for (size_t index = 0; index < length; index++) {
4136 if (buffer[index] == '_') {
4137 memmove((void *) (buffer + index), (void *) (buffer + index + 1), length - index);
4142 // Null-terminate the buffer so that strtod cannot read off the end.
4143 buffer[length] = '\0';
4145 // Now, call strtod to parse the value. Note that CRuby has their own
4146 // version of strtod which avoids locales. We're okay using the locale-aware
4147 // version because we've already validated through the parser that the token
4148 // is in a valid format.
4151 double value = strtod(buffer, &eptr);
4153 // This should never happen, because we've already checked that the token
4154 // is in a valid format. However it's good to be safe.
4155 if ((eptr != buffer + length) || (errno != 0 && errno != ERANGE)) {
4156 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, (*token), PM_ERR_FLOAT_PARSE);
4157 xfree((void *) buffer);
4161 // If errno is set, then it should only be ERANGE. At this point we need to
4162 // check if it's infinity (it should be).
4163 if (errno == ERANGE && PRISM_ISINF(value)) {
4165 const char *ellipsis;
4171 warn_width = (int) length;
4175 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);
4176 value = (value < 0.0) ? -HUGE_VAL : HUGE_VAL;
4179 // Finally we can free the buffer and return the value.
4180 xfree((void *) buffer);
4187static pm_float_node_t *
4188pm_float_node_create(pm_parser_t *parser, const pm_token_t *token) {
4189 assert(token->type == PM_TOKEN_FLOAT);
4190 pm_float_node_t *node = PM_NODE_ALLOC(parser, pm_float_node_t);
4192 *node = (pm_float_node_t) {
4194 .type = PM_FLOAT_NODE,
4195 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4196 .node_id = PM_NODE_IDENTIFY(parser),
4197 .location = PM_LOCATION_TOKEN_VALUE(token)
4199 .value = pm_double_parse(parser, token)
4208static pm_imaginary_node_t *
4209pm_float_node_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4210 assert(token->type == PM_TOKEN_FLOAT_IMAGINARY);
4212 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4213 *node = (pm_imaginary_node_t) {
4215 .type = PM_IMAGINARY_NODE,
4216 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4217 .node_id = PM_NODE_IDENTIFY(parser),
4218 .location = PM_LOCATION_TOKEN_VALUE(token)
4220 .numeric = (pm_node_t *) pm_float_node_create(parser, &((pm_token_t) {
4221 .type = PM_TOKEN_FLOAT,
4222 .start = token->start,
4223 .end = token->end - 1
4233static pm_rational_node_t *
4234pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
4235 assert(token->type == PM_TOKEN_FLOAT_RATIONAL);
4237 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
4238 *node = (pm_rational_node_t) {
4240 .type = PM_RATIONAL_NODE,
4241 .flags = PM_INTEGER_BASE_FLAGS_DECIMAL | PM_NODE_FLAG_STATIC_LITERAL,
4242 .node_id = PM_NODE_IDENTIFY(parser),
4243 .location = PM_LOCATION_TOKEN_VALUE(token)
4246 .denominator = { 0 }
4249 const uint8_t *start = token->start;
4250 const uint8_t *end = token->end - 1; // r
4252 while (start < end && *start == '0') start++; // 0.1 -> .1
4253 while (end > start && end[-1] == '0') end--; // 1.0 -> 1.
4255 size_t length = (size_t) (end - start);
4257 node->denominator.value = 1;
4261 const uint8_t *point = memchr(start, '.', length);
4262 assert(point && "should have a decimal point");
4264 uint8_t *digits = xmalloc(length);
4265 if (digits == NULL) {
4266 fputs("[pm_float_node_rational_create] Failed to allocate memory", stderr);
4270 memcpy(digits, start, (unsigned long) (point - start));
4271 memcpy(digits + (point - start), point + 1, (unsigned long) (end - point - 1));
4272 pm_integer_parse(&node->numerator, PM_INTEGER_BASE_DEFAULT, digits, digits + length - 1);
4275 if (end - point > 1) memset(digits + 1, '0', (size_t) (end - point - 1));
4276 pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + (end - point));
4279 pm_integers_reduce(&node->numerator, &node->denominator);
4287static pm_imaginary_node_t *
4288pm_float_node_rational_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4289 assert(token->type == PM_TOKEN_FLOAT_RATIONAL_IMAGINARY);
4291 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4292 *node = (pm_imaginary_node_t) {
4294 .type = PM_IMAGINARY_NODE,
4295 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4296 .node_id = PM_NODE_IDENTIFY(parser),
4297 .location = PM_LOCATION_TOKEN_VALUE(token)
4299 .numeric = (pm_node_t *) pm_float_node_rational_create(parser, &((pm_token_t) {
4300 .type = PM_TOKEN_FLOAT_RATIONAL,
4301 .start = token->start,
4302 .end = token->end - 1
4312static pm_for_node_t *
4314 pm_parser_t *parser,
4316 pm_node_t *collection,
4317 pm_statements_node_t *statements,
4318 const pm_token_t *for_keyword,
4319 const pm_token_t *in_keyword,
4320 const pm_token_t *do_keyword,
4321 const pm_token_t *end_keyword
4323 pm_for_node_t *node = PM_NODE_ALLOC(parser, pm_for_node_t);
4325 *node = (pm_for_node_t) {
4327 .type = PM_FOR_NODE,
4328 .node_id = PM_NODE_IDENTIFY(parser),
4330 .start = for_keyword->start,
4331 .end = end_keyword->end
4335 .collection = collection,
4336 .statements = statements,
4337 .for_keyword_loc = PM_LOCATION_TOKEN_VALUE(for_keyword),
4338 .in_keyword_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
4339 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
4340 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
4349static pm_forwarding_arguments_node_t *
4350pm_forwarding_arguments_node_create(pm_parser_t *parser, const pm_token_t *token) {
4351 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4352 pm_forwarding_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_arguments_node_t);
4354 *node = (pm_forwarding_arguments_node_t) {{
4355 .type = PM_FORWARDING_ARGUMENTS_NODE,
4356 .node_id = PM_NODE_IDENTIFY(parser),
4357 .location = PM_LOCATION_TOKEN_VALUE(token)
4366static pm_forwarding_parameter_node_t *
4367pm_forwarding_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
4368 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4369 pm_forwarding_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_parameter_node_t);
4371 *node = (pm_forwarding_parameter_node_t) {{
4372 .type = PM_FORWARDING_PARAMETER_NODE,
4373 .node_id = PM_NODE_IDENTIFY(parser),
4374 .location = PM_LOCATION_TOKEN_VALUE(token)
4383static pm_forwarding_super_node_t *
4384pm_forwarding_super_node_create(pm_parser_t *parser, const pm_token_t *token, pm_arguments_t *arguments) {
4385 assert(arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_NODE));
4386 assert(token->type == PM_TOKEN_KEYWORD_SUPER);
4387 pm_forwarding_super_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_super_node_t);
4389 pm_block_node_t *block = NULL;
4390 if (arguments->block != NULL) {
4391 block = (pm_block_node_t *) arguments->block;
4394 *node = (pm_forwarding_super_node_t) {
4396 .type = PM_FORWARDING_SUPER_NODE,
4397 .node_id = PM_NODE_IDENTIFY(parser),
4399 .start = token->start,
4400 .end = block != NULL ? block->base.location.end : token->end
4413static pm_hash_pattern_node_t *
4414pm_hash_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4415 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4417 *node = (pm_hash_pattern_node_t) {
4419 .type = PM_HASH_PATTERN_NODE,
4420 .node_id = PM_NODE_IDENTIFY(parser),
4422 .start = opening->start,
4427 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4428 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
4439static pm_hash_pattern_node_t *
4440pm_hash_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *elements, pm_node_t *rest) {
4441 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4443 const uint8_t *start;
4446 if (elements->size > 0) {
4448 start = elements->nodes[0]->location.start;
4449 end = rest->location.end;
4451 start = elements->nodes[0]->location.start;
4452 end = elements->nodes[elements->size - 1]->location.end;
4455 assert(rest != NULL);
4456 start = rest->location.start;
4457 end = rest->location.end;
4460 *node = (pm_hash_pattern_node_t) {
4462 .type = PM_HASH_PATTERN_NODE,
4463 .node_id = PM_NODE_IDENTIFY(parser),
4472 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4473 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4477 PM_NODE_LIST_FOREACH(elements, index, element) {
4478 pm_node_list_append(&node->elements, element);
4487static pm_constant_id_t
4488pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
4489 switch (PM_NODE_TYPE(target)) {
4490 case PM_GLOBAL_VARIABLE_READ_NODE:
4491 return ((pm_global_variable_read_node_t *) target)->name;
4492 case PM_BACK_REFERENCE_READ_NODE:
4493 return ((pm_back_reference_read_node_t *) target)->name;
4494 case PM_NUMBERED_REFERENCE_READ_NODE:
4495 // This will only ever happen in the event of a syntax error, but we
4496 // still need to provide something for the node.
4497 return pm_parser_constant_id_location(parser, target->location.start, target->location.end);
4499 assert(false && "unreachable");
4500 return (pm_constant_id_t) -1;
4507static pm_global_variable_and_write_node_t *
4508pm_global_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4509 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4510 pm_global_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_and_write_node_t);
4512 *node = (pm_global_variable_and_write_node_t) {
4514 .type = PM_GLOBAL_VARIABLE_AND_WRITE_NODE,
4515 .node_id = PM_NODE_IDENTIFY(parser),
4517 .start = target->location.start,
4518 .end = value->location.end
4521 .name = pm_global_variable_write_name(parser, target),
4522 .name_loc = target->location,
4523 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4533static pm_global_variable_operator_write_node_t *
4534pm_global_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4535 pm_global_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_operator_write_node_t);
4537 *node = (pm_global_variable_operator_write_node_t) {
4539 .type = PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE,
4540 .node_id = PM_NODE_IDENTIFY(parser),
4542 .start = target->location.start,
4543 .end = value->location.end
4546 .name = pm_global_variable_write_name(parser, target),
4547 .name_loc = target->location,
4548 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4550 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
4559static pm_global_variable_or_write_node_t *
4560pm_global_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4561 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4562 pm_global_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_or_write_node_t);
4564 *node = (pm_global_variable_or_write_node_t) {
4566 .type = PM_GLOBAL_VARIABLE_OR_WRITE_NODE,
4567 .node_id = PM_NODE_IDENTIFY(parser),
4569 .start = target->location.start,
4570 .end = value->location.end
4573 .name = pm_global_variable_write_name(parser, target),
4574 .name_loc = target->location,
4575 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4585static pm_global_variable_read_node_t *
4586pm_global_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
4587 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4589 *node = (pm_global_variable_read_node_t) {
4591 .type = PM_GLOBAL_VARIABLE_READ_NODE,
4592 .node_id = PM_NODE_IDENTIFY(parser),
4593 .location = PM_LOCATION_TOKEN_VALUE(name),
4595 .name = pm_parser_constant_id_token(parser, name)
4604static pm_global_variable_read_node_t *
4605pm_global_variable_read_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name) {
4606 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4608 *node = (pm_global_variable_read_node_t) {
4610 .type = PM_GLOBAL_VARIABLE_READ_NODE,
4611 .node_id = PM_NODE_IDENTIFY(parser),
4612 .location = PM_LOCATION_NULL_VALUE(parser)
4623static pm_global_variable_write_node_t *
4624pm_global_variable_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4625 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4627 *node = (pm_global_variable_write_node_t) {
4629 .type = PM_GLOBAL_VARIABLE_WRITE_NODE,
4630 .node_id = PM_NODE_IDENTIFY(parser),
4631 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
4633 .start = target->location.start,
4634 .end = value->location.end
4637 .name = pm_global_variable_write_name(parser, target),
4638 .name_loc = PM_LOCATION_NODE_VALUE(target),
4639 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
4649static pm_global_variable_write_node_t *
4650pm_global_variable_write_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name, pm_node_t *value) {
4651 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4653 *node = (pm_global_variable_write_node_t) {
4655 .type = PM_GLOBAL_VARIABLE_WRITE_NODE,
4656 .node_id = PM_NODE_IDENTIFY(parser),
4657 .location = PM_LOCATION_NULL_VALUE(parser)
4660 .name_loc = PM_LOCATION_NULL_VALUE(parser),
4661 .operator_loc = PM_LOCATION_NULL_VALUE(parser),
4671static pm_hash_node_t *
4672pm_hash_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4673 assert(opening != NULL);
4674 pm_hash_node_t *node = PM_NODE_ALLOC(parser, pm_hash_node_t);
4676 *node = (pm_hash_node_t) {
4678 .type = PM_HASH_NODE,
4679 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4680 .node_id = PM_NODE_IDENTIFY(parser),
4681 .location = PM_LOCATION_TOKEN_VALUE(opening)
4683 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4684 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
4695pm_hash_node_elements_append(pm_hash_node_t *hash, pm_node_t *element) {
4696 pm_node_list_append(&hash->elements, element);
4698 bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE);
4699 if (static_literal) {
4700 pm_assoc_node_t *assoc = (pm_assoc_node_t *) element;
4701 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);
4702 static_literal = static_literal && PM_NODE_FLAG_P(assoc->key, PM_NODE_FLAG_STATIC_LITERAL);
4703 static_literal = static_literal && PM_NODE_FLAG_P(assoc, PM_NODE_FLAG_STATIC_LITERAL);
4706 if (!static_literal) {
4707 pm_node_flag_unset((pm_node_t *)hash, PM_NODE_FLAG_STATIC_LITERAL);
4712pm_hash_node_closing_loc_set(pm_hash_node_t *hash, pm_token_t *token) {
4713 hash->base.location.end = token->end;
4714 hash->closing_loc = PM_LOCATION_TOKEN_VALUE(token);
4720static pm_if_node_t *
4721pm_if_node_create(pm_parser_t *parser,
4722 const pm_token_t *if_keyword,
4723 pm_node_t *predicate,
4724 const pm_token_t *then_keyword,
4725 pm_statements_node_t *statements,
4726 pm_node_t *subsequent,
4727 const pm_token_t *end_keyword
4729 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4730 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4733 if (end_keyword->type != PM_TOKEN_NOT_PROVIDED) {
4734 end = end_keyword->end;
4735 } else if (subsequent != NULL) {
4736 end = subsequent->location.end;
4737 } else if (pm_statements_node_body_length(statements) != 0) {
4738 end = statements->base.location.end;
4740 end = predicate->location.end;
4743 *node = (pm_if_node_t) {
4746 .flags = PM_NODE_FLAG_NEWLINE,
4747 .node_id = PM_NODE_IDENTIFY(parser),
4749 .start = if_keyword->start,
4753 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4754 .predicate = predicate,
4755 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
4756 .statements = statements,
4757 .subsequent = subsequent,
4758 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
4767static pm_if_node_t *
4768pm_if_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *if_keyword, pm_node_t *predicate) {
4769 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4770 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4772 pm_statements_node_t *statements = pm_statements_node_create(parser);
4773 pm_statements_node_body_append(parser, statements, statement, true);
4775 *node = (pm_if_node_t) {
4778 .flags = PM_NODE_FLAG_NEWLINE,
4779 .node_id = PM_NODE_IDENTIFY(parser),
4781 .start = statement->location.start,
4782 .end = predicate->location.end
4785 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4786 .predicate = predicate,
4787 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4788 .statements = statements,
4790 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4799static pm_if_node_t *
4800pm_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) {
4801 pm_assert_value_expression(parser, predicate);
4802 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4804 pm_statements_node_t *if_statements = pm_statements_node_create(parser);
4805 pm_statements_node_body_append(parser, if_statements, true_expression, true);
4807 pm_statements_node_t *else_statements = pm_statements_node_create(parser);
4808 pm_statements_node_body_append(parser, else_statements, false_expression, true);
4810 pm_token_t end_keyword = not_provided(parser);
4811 pm_else_node_t *else_node = pm_else_node_create(parser, colon, else_statements, &end_keyword);
4813 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4815 *node = (pm_if_node_t) {
4818 .flags = PM_NODE_FLAG_NEWLINE,
4819 .node_id = PM_NODE_IDENTIFY(parser),
4821 .start = predicate->location.start,
4822 .end = false_expression->location.end,
4825 .if_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4826 .predicate = predicate,
4827 .then_keyword_loc = PM_LOCATION_TOKEN_VALUE(qmark),
4828 .statements = if_statements,
4829 .subsequent = (pm_node_t *) else_node,
4830 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4838pm_if_node_end_keyword_loc_set(pm_if_node_t *node, const pm_token_t *keyword) {
4839 node->base.location.end = keyword->end;
4840 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4844pm_else_node_end_keyword_loc_set(pm_else_node_t *node, const pm_token_t *keyword) {
4845 node->base.location.end = keyword->end;
4846 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4852static pm_implicit_node_t *
4853pm_implicit_node_create(pm_parser_t *parser, pm_node_t *value) {
4854 pm_implicit_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_node_t);
4856 *node = (pm_implicit_node_t) {
4858 .type = PM_IMPLICIT_NODE,
4859 .node_id = PM_NODE_IDENTIFY(parser),
4860 .location = value->location
4871static pm_implicit_rest_node_t *
4872pm_implicit_rest_node_create(pm_parser_t *parser, const pm_token_t *token) {
4873 assert(token->type == PM_TOKEN_COMMA);
4875 pm_implicit_rest_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_rest_node_t);
4877 *node = (pm_implicit_rest_node_t) {
4879 .type = PM_IMPLICIT_REST_NODE,
4880 .node_id = PM_NODE_IDENTIFY(parser),
4881 .location = PM_LOCATION_TOKEN_VALUE(token)
4891static pm_integer_node_t *
4892pm_integer_node_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4893 assert(token->type == PM_TOKEN_INTEGER);
4894 pm_integer_node_t *node = PM_NODE_ALLOC(parser, pm_integer_node_t);
4896 *node = (pm_integer_node_t) {
4898 .type = PM_INTEGER_NODE,
4899 .flags = base | PM_NODE_FLAG_STATIC_LITERAL,
4900 .node_id = PM_NODE_IDENTIFY(parser),
4901 .location = PM_LOCATION_TOKEN_VALUE(token)
4906 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4908 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4909 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4910 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4911 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4912 default: assert(false && "unreachable"); break;
4915 pm_integer_parse(&node->value, integer_base, token->start, token->end);
4923static pm_imaginary_node_t *
4924pm_integer_node_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4925 assert(token->type == PM_TOKEN_INTEGER_IMAGINARY);
4927 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4928 *node = (pm_imaginary_node_t) {
4930 .type = PM_IMAGINARY_NODE,
4931 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4932 .node_id = PM_NODE_IDENTIFY(parser),
4933 .location = PM_LOCATION_TOKEN_VALUE(token)
4935 .numeric = (pm_node_t *) pm_integer_node_create(parser, base, &((pm_token_t) {
4936 .type = PM_TOKEN_INTEGER,
4937 .start = token->start,
4938 .end = token->end - 1
4949static pm_rational_node_t *
4950pm_integer_node_rational_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4951 assert(token->type == PM_TOKEN_INTEGER_RATIONAL);
4953 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
4954 *node = (pm_rational_node_t) {
4956 .type = PM_RATIONAL_NODE,
4957 .flags = base | PM_NODE_FLAG_STATIC_LITERAL,
4958 .node_id = PM_NODE_IDENTIFY(parser),
4959 .location = PM_LOCATION_TOKEN_VALUE(token)
4962 .denominator = { .value = 1, 0 }
4965 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4967 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4968 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4969 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4970 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4971 default: assert(false && "unreachable"); break;
4974 pm_integer_parse(&node->numerator, integer_base, token->start, token->end - 1);
4983static pm_imaginary_node_t *
4984pm_integer_node_rational_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4985 assert(token->type == PM_TOKEN_INTEGER_RATIONAL_IMAGINARY);
4987 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4988 *node = (pm_imaginary_node_t) {
4990 .type = PM_IMAGINARY_NODE,
4991 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4992 .node_id = PM_NODE_IDENTIFY(parser),
4993 .location = PM_LOCATION_TOKEN_VALUE(token)
4995 .numeric = (pm_node_t *) pm_integer_node_rational_create(parser, base, &((pm_token_t) {
4996 .type = PM_TOKEN_INTEGER_RATIONAL,
4997 .start = token->start,
4998 .end = token->end - 1
5008static pm_in_node_t *
5009pm_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) {
5010 pm_in_node_t *node = PM_NODE_ALLOC(parser, pm_in_node_t);
5013 if (statements != NULL) {
5014 end = statements->base.location.end;
5015 } else if (then_keyword->type != PM_TOKEN_NOT_PROVIDED) {
5016 end = then_keyword->end;
5018 end = pattern->location.end;
5021 *node = (pm_in_node_t) {
5024 .node_id = PM_NODE_IDENTIFY(parser),
5026 .start = in_keyword->start,
5031 .statements = statements,
5032 .in_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
5033 .then_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword)
5042static pm_instance_variable_and_write_node_t *
5043pm_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) {
5044 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5045 pm_instance_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_and_write_node_t);
5047 *node = (pm_instance_variable_and_write_node_t) {
5049 .type = PM_INSTANCE_VARIABLE_AND_WRITE_NODE,
5050 .node_id = PM_NODE_IDENTIFY(parser),
5052 .start = target->base.location.start,
5053 .end = value->location.end
5056 .name = target->name,
5057 .name_loc = target->base.location,
5058 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5068static pm_instance_variable_operator_write_node_t *
5069pm_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) {
5070 pm_instance_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_operator_write_node_t);
5072 *node = (pm_instance_variable_operator_write_node_t) {
5074 .type = PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE,
5075 .node_id = PM_NODE_IDENTIFY(parser),
5077 .start = target->base.location.start,
5078 .end = value->location.end
5081 .name = target->name,
5082 .name_loc = target->base.location,
5083 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5085 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
5094static pm_instance_variable_or_write_node_t *
5095pm_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) {
5096 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5097 pm_instance_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_or_write_node_t);
5099 *node = (pm_instance_variable_or_write_node_t) {
5101 .type = PM_INSTANCE_VARIABLE_OR_WRITE_NODE,
5102 .node_id = PM_NODE_IDENTIFY(parser),
5104 .start = target->base.location.start,
5105 .end = value->location.end
5108 .name = target->name,
5109 .name_loc = target->base.location,
5110 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5120static pm_instance_variable_read_node_t *
5121pm_instance_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
5122 assert(token->type == PM_TOKEN_INSTANCE_VARIABLE);
5123 pm_instance_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_read_node_t);
5125 *node = (pm_instance_variable_read_node_t) {
5127 .type = PM_INSTANCE_VARIABLE_READ_NODE,
5128 .node_id = PM_NODE_IDENTIFY(parser),
5129 .location = PM_LOCATION_TOKEN_VALUE(token)
5131 .name = pm_parser_constant_id_token(parser, token)
5141static pm_instance_variable_write_node_t *
5142pm_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) {
5143 pm_instance_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_write_node_t);
5144 *node = (pm_instance_variable_write_node_t) {
5146 .type = PM_INSTANCE_VARIABLE_WRITE_NODE,
5147 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5148 .node_id = PM_NODE_IDENTIFY(parser),
5150 .start = read_node->base.location.start,
5151 .end = value->location.end
5154 .name = read_node->name,
5155 .name_loc = PM_LOCATION_NODE_BASE_VALUE(read_node),
5156 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
5169pm_interpolated_node_append(pm_node_t *node, pm_node_list_t *parts, pm_node_t *part) {
5170 switch (PM_NODE_TYPE(part)) {
5171 case PM_STRING_NODE:
5172 pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5174 case PM_EMBEDDED_STATEMENTS_NODE: {
5175 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5176 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5178 if (embedded == NULL) {
5179 // If there are no statements or more than one statement, then
5180 // we lose the static literal flag.
5181 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5182 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5183 // If the embedded statement is a string, then we can keep the
5184 // static literal flag and mark the string as frozen.
5185 pm_node_flag_set(embedded, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5186 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5187 // If the embedded statement is an interpolated string and it's
5188 // a static literal, then we can keep the static literal flag.
5190 // Otherwise we lose the static literal flag.
5191 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5196 case PM_EMBEDDED_VARIABLE_NODE:
5197 pm_node_flag_unset((pm_node_t *) node, PM_NODE_FLAG_STATIC_LITERAL);
5200 assert(false && "unexpected node type");
5204 pm_node_list_append(parts, part);
5210static pm_interpolated_regular_expression_node_t *
5211pm_interpolated_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening) {
5212 pm_interpolated_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_regular_expression_node_t);
5214 *node = (pm_interpolated_regular_expression_node_t) {
5216 .type = PM_INTERPOLATED_REGULAR_EXPRESSION_NODE,
5217 .flags = PM_NODE_FLAG_STATIC_LITERAL,
5218 .node_id = PM_NODE_IDENTIFY(parser),
5220 .start = opening->start,
5224 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5225 .closing_loc = PM_LOCATION_TOKEN_VALUE(opening),
5233pm_interpolated_regular_expression_node_append(pm_interpolated_regular_expression_node_t *node, pm_node_t *part) {
5234 if (node->base.location.start > part->location.start) {
5235 node->base.location.start = part->location.start;
5237 if (node->base.location.end < part->location.end) {
5238 node->base.location.end = part->location.end;
5241 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5245pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_interpolated_regular_expression_node_t *node, const pm_token_t *closing) {
5246 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
5247 node->base.location.end = closing->end;
5248 pm_node_flag_set((pm_node_t *) node, pm_regular_expression_flags_create(parser, closing));
5275pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_node_t *part) {
5276#define CLEAR_FLAGS(node) \
5277 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))
5279#define MUTABLE_FLAGS(node) \
5280 node->base.flags = (pm_node_flags_t) ((node->base.flags | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE) & ~PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN);
5282 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
5283 node->base.location.start = part->location.start;
5286 node->base.location.end = MAX(node->base.location.end, part->location.end);
5288 switch (PM_NODE_TYPE(part)) {
5289 case PM_STRING_NODE:
5290 // If inner string is not frozen, it stops being a static literal. We should *not* clear other flags,
5291 // because concatenating two frozen strings (`'foo' 'bar'`) is still frozen. This holds true for
5292 // as long as this interpolation only consists of other string literals.
5293 if (!PM_NODE_FLAG_P(part, PM_STRING_FLAGS_FROZEN)) {
5294 pm_node_flag_unset((pm_node_t *) node, PM_NODE_FLAG_STATIC_LITERAL);
5296 part->flags = (pm_node_flags_t) ((part->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5298 case PM_INTERPOLATED_STRING_NODE:
5299 if (PM_NODE_FLAG_P(part, PM_NODE_FLAG_STATIC_LITERAL)) {
5300 // If the string that we're concatenating is a static literal,
5301 // then we can keep the static literal flag for this string.
5303 // Otherwise, we lose the static literal flag here and we should
5304 // also clear the mutability flags.
5308 case PM_EMBEDDED_STATEMENTS_NODE: {
5309 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5310 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5312 if (embedded == NULL) {
5313 // If we're embedding multiple statements or no statements, then
5314 // the string is not longer a static literal.
5316 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5317 // If the embedded statement is a string, then we can make that
5318 // string as frozen and static literal, and not touch the static
5319 // literal status of this string.
5320 embedded->flags = (pm_node_flags_t) ((embedded->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5322 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5323 MUTABLE_FLAGS(node);
5325 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5326 // If the embedded statement is an interpolated string, but that
5327 // string is marked as static literal, then we can keep our
5328 // static literal status for this string.
5329 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5330 MUTABLE_FLAGS(node);
5333 // In all other cases, we lose the static literal flag here and
5340 case PM_EMBEDDED_VARIABLE_NODE:
5341 // Embedded variables clear static literal, which means we also
5342 // should clear the mutability flags.
5345 case PM_X_STRING_NODE:
5346 case PM_INTERPOLATED_X_STRING_NODE:
5347 // If this is an x string, then this is a syntax error. But we want
5348 // to handle it here so that we don't fail the assertion.
5352 assert(false && "unexpected node type");
5356 pm_node_list_append(&node->parts, part);
5365static pm_interpolated_string_node_t *
5366pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5367 pm_interpolated_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_string_node_t);
5368 pm_node_flags_t flags = PM_NODE_FLAG_STATIC_LITERAL;
5370 switch (parser->frozen_string_literal) {
5371 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
5372 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE;
5374 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
5375 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN;
5379 *node = (pm_interpolated_string_node_t) {
5381 .type = PM_INTERPOLATED_STRING_NODE,
5383 .node_id = PM_NODE_IDENTIFY(parser),
5385 .start = opening->start,
5386 .end = closing->end,
5389 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5390 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5394 if (parts != NULL) {
5396 PM_NODE_LIST_FOREACH(parts, index, part) {
5397 pm_interpolated_string_node_append(node, part);
5408pm_interpolated_string_node_closing_set(pm_interpolated_string_node_t *node, const pm_token_t *closing) {
5409 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5410 node->base.location.end = closing->end;
5414pm_interpolated_symbol_node_append(pm_interpolated_symbol_node_t *node, pm_node_t *part) {
5415 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
5416 node->base.location.start = part->location.start;
5419 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5420 node->base.location.end = MAX(node->base.location.end, part->location.end);
5424pm_interpolated_symbol_node_closing_loc_set(pm_interpolated_symbol_node_t *node, const pm_token_t *closing) {
5425 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5426 node->base.location.end = closing->end;
5432static pm_interpolated_symbol_node_t *
5433pm_interpolated_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5434 pm_interpolated_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_symbol_node_t);
5436 *node = (pm_interpolated_symbol_node_t) {
5438 .type = PM_INTERPOLATED_SYMBOL_NODE,
5439 .flags = PM_NODE_FLAG_STATIC_LITERAL,
5440 .node_id = PM_NODE_IDENTIFY(parser),
5442 .start = opening->start,
5443 .end = closing->end,
5446 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5447 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5451 if (parts != NULL) {
5453 PM_NODE_LIST_FOREACH(parts, index, part) {
5454 pm_interpolated_symbol_node_append(node, part);
5464static pm_interpolated_x_string_node_t *
5465pm_interpolated_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5466 pm_interpolated_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_x_string_node_t);
5468 *node = (pm_interpolated_x_string_node_t) {
5470 .type = PM_INTERPOLATED_X_STRING_NODE,
5471 .node_id = PM_NODE_IDENTIFY(parser),
5473 .start = opening->start,
5477 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5478 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5486pm_interpolated_xstring_node_append(pm_interpolated_x_string_node_t *node, pm_node_t *part) {
5487 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5488 node->base.location.end = part->location.end;
5492pm_interpolated_xstring_node_closing_set(pm_interpolated_x_string_node_t *node, const pm_token_t *closing) {
5493 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5494 node->base.location.end = closing->end;
5500static pm_it_local_variable_read_node_t *
5501pm_it_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5502 pm_it_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_it_local_variable_read_node_t);
5504 *node = (pm_it_local_variable_read_node_t) {
5506 .type = PM_IT_LOCAL_VARIABLE_READ_NODE,
5507 .node_id = PM_NODE_IDENTIFY(parser),
5508 .location = PM_LOCATION_TOKEN_VALUE(name)
5518static pm_it_parameters_node_t *
5519pm_it_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5520 pm_it_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_it_parameters_node_t);
5522 *node = (pm_it_parameters_node_t) {
5524 .type = PM_IT_PARAMETERS_NODE,
5525 .node_id = PM_NODE_IDENTIFY(parser),
5527 .start = opening->start,
5539static pm_keyword_hash_node_t *
5540pm_keyword_hash_node_create(pm_parser_t *parser) {
5541 pm_keyword_hash_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_hash_node_t);
5543 *node = (pm_keyword_hash_node_t) {
5545 .type = PM_KEYWORD_HASH_NODE,
5546 .flags = PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS,
5547 .node_id = PM_NODE_IDENTIFY(parser),
5548 .location = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
5560pm_keyword_hash_node_elements_append(pm_keyword_hash_node_t *hash, pm_node_t *element) {
5561 // If the element being added is not an AssocNode or does not have a symbol
5562 // key, then we want to turn the SYMBOL_KEYS flag off.
5563 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE) || !PM_NODE_TYPE_P(((pm_assoc_node_t *) element)->key, PM_SYMBOL_NODE)) {
5564 pm_node_flag_unset((pm_node_t *)hash, PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS);
5567 pm_node_list_append(&hash->elements, element);
5568 if (hash->base.location.start == NULL) {
5569 hash->base.location.start = element->location.start;
5571 hash->base.location.end = element->location.end;
5577static pm_required_keyword_parameter_node_t *
5578pm_required_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name) {
5579 pm_required_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_keyword_parameter_node_t);
5581 *node = (pm_required_keyword_parameter_node_t) {
5583 .type = PM_REQUIRED_KEYWORD_PARAMETER_NODE,
5584 .node_id = PM_NODE_IDENTIFY(parser),
5586 .start = name->start,
5590 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5591 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5600static pm_optional_keyword_parameter_node_t *
5601pm_optional_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, pm_node_t *value) {
5602 pm_optional_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_keyword_parameter_node_t);
5604 *node = (pm_optional_keyword_parameter_node_t) {
5606 .type = PM_OPTIONAL_KEYWORD_PARAMETER_NODE,
5607 .node_id = PM_NODE_IDENTIFY(parser),
5609 .start = name->start,
5610 .end = value->location.end
5613 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5614 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5624static pm_keyword_rest_parameter_node_t *
5625pm_keyword_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
5626 pm_keyword_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_rest_parameter_node_t);
5628 *node = (pm_keyword_rest_parameter_node_t) {
5630 .type = PM_KEYWORD_REST_PARAMETER_NODE,
5631 .node_id = PM_NODE_IDENTIFY(parser),
5633 .start = operator->start,
5634 .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
5637 .name = pm_parser_optional_constant_id_token(parser, name),
5638 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
5639 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5648static pm_lambda_node_t *
5649pm_lambda_node_create(
5650 pm_parser_t *parser,
5651 pm_constant_id_list_t *locals,
5652 const pm_token_t *operator,
5653 const pm_token_t *opening,
5654 const pm_token_t *closing,
5655 pm_node_t *parameters,
5658 pm_lambda_node_t *node = PM_NODE_ALLOC(parser, pm_lambda_node_t);
5660 *node = (pm_lambda_node_t) {
5662 .type = PM_LAMBDA_NODE,
5663 .node_id = PM_NODE_IDENTIFY(parser),
5665 .start = operator->start,
5670 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5671 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5672 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
5673 .parameters = parameters,
5683static pm_local_variable_and_write_node_t *
5684pm_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) {
5685 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));
5686 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5687 pm_local_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_and_write_node_t);
5689 *node = (pm_local_variable_and_write_node_t) {
5691 .type = PM_LOCAL_VARIABLE_AND_WRITE_NODE,
5692 .node_id = PM_NODE_IDENTIFY(parser),
5694 .start = target->location.start,
5695 .end = value->location.end
5698 .name_loc = target->location,
5699 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5711static pm_local_variable_operator_write_node_t *
5712pm_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) {
5713 pm_local_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_operator_write_node_t);
5715 *node = (pm_local_variable_operator_write_node_t) {
5717 .type = PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE,
5718 .node_id = PM_NODE_IDENTIFY(parser),
5720 .start = target->location.start,
5721 .end = value->location.end
5724 .name_loc = target->location,
5725 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5728 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
5738static pm_local_variable_or_write_node_t *
5739pm_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) {
5740 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));
5741 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5742 pm_local_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_or_write_node_t);
5744 *node = (pm_local_variable_or_write_node_t) {
5746 .type = PM_LOCAL_VARIABLE_OR_WRITE_NODE,
5747 .node_id = PM_NODE_IDENTIFY(parser),
5749 .start = target->location.start,
5750 .end = value->location.end
5753 .name_loc = target->location,
5754 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5766static pm_local_variable_read_node_t *
5767pm_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) {
5768 if (!missing) pm_locals_read(&pm_parser_scope_find(parser, depth)->locals, name_id);
5770 pm_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_read_node_t);
5772 *node = (pm_local_variable_read_node_t) {
5774 .type = PM_LOCAL_VARIABLE_READ_NODE,
5775 .node_id = PM_NODE_IDENTIFY(parser),
5776 .location = PM_LOCATION_TOKEN_VALUE(name)
5788static pm_local_variable_read_node_t *
5789pm_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5790 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5791 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, false);
5798static pm_local_variable_read_node_t *
5799pm_local_variable_read_node_missing_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5800 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5801 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, true);
5807static pm_local_variable_write_node_t *
5808pm_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) {
5809 pm_local_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_write_node_t);
5811 *node = (pm_local_variable_write_node_t) {
5813 .type = PM_LOCAL_VARIABLE_WRITE_NODE,
5814 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5815 .node_id = PM_NODE_IDENTIFY(parser),
5817 .start = name_loc->start,
5818 .end = value->location.end
5824 .name_loc = *name_loc,
5825 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator)
5835pm_token_is_it(const uint8_t *start, const uint8_t *end) {
5836 return (end - start == 2) && (start[0] == 'i') && (start[1] == 't');
5844pm_token_is_numbered_parameter(const uint8_t *start, const uint8_t *end) {
5845 return (end - start == 2) && (start[0] == '_') && (start[1] != '0') && (pm_char_is_decimal_digit(start[1]));
5853pm_refute_numbered_parameter(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
5854 if (pm_token_is_numbered_parameter(start, end)) {
5855 PM_PARSER_ERR_FORMAT(parser, start, end, PM_ERR_PARAMETER_NUMBERED_RESERVED, start);
5863static pm_local_variable_target_node_t *
5864pm_local_variable_target_node_create(pm_parser_t *parser, const pm_location_t *location, pm_constant_id_t name, uint32_t depth) {
5865 pm_refute_numbered_parameter(parser, location->start, location->end);
5866 pm_local_variable_target_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_target_node_t);
5868 *node = (pm_local_variable_target_node_t) {
5870 .type = PM_LOCAL_VARIABLE_TARGET_NODE,
5871 .node_id = PM_NODE_IDENTIFY(parser),
5872 .location = *location
5884static pm_match_predicate_node_t *
5885pm_match_predicate_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5886 pm_assert_value_expression(parser, value);
5888 pm_match_predicate_node_t *node = PM_NODE_ALLOC(parser, pm_match_predicate_node_t);
5890 *node = (pm_match_predicate_node_t) {
5892 .type = PM_MATCH_PREDICATE_NODE,
5893 .node_id = PM_NODE_IDENTIFY(parser),
5895 .start = value->location.start,
5896 .end = pattern->location.end
5901 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5910static pm_match_required_node_t *
5911pm_match_required_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5912 pm_assert_value_expression(parser, value);
5914 pm_match_required_node_t *node = PM_NODE_ALLOC(parser, pm_match_required_node_t);
5916 *node = (pm_match_required_node_t) {
5918 .type = PM_MATCH_REQUIRED_NODE,
5919 .node_id = PM_NODE_IDENTIFY(parser),
5921 .start = value->location.start,
5922 .end = pattern->location.end
5927 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5936static pm_match_write_node_t *
5937pm_match_write_node_create(pm_parser_t *parser, pm_call_node_t *call) {
5938 pm_match_write_node_t *node = PM_NODE_ALLOC(parser, pm_match_write_node_t);
5940 *node = (pm_match_write_node_t) {
5942 .type = PM_MATCH_WRITE_NODE,
5943 .node_id = PM_NODE_IDENTIFY(parser),
5944 .location = call->base.location
5956static pm_module_node_t *
5957pm_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) {
5958 pm_module_node_t *node = PM_NODE_ALLOC(parser, pm_module_node_t);
5960 *node = (pm_module_node_t) {
5962 .type = PM_MODULE_NODE,
5963 .node_id = PM_NODE_IDENTIFY(parser),
5965 .start = module_keyword->start,
5966 .end = end_keyword->end
5969 .locals = (locals == NULL ? ((pm_constant_id_list_t) { .ids = NULL, .size = 0, .capacity = 0 }) : *locals),
5970 .module_keyword_loc = PM_LOCATION_TOKEN_VALUE(module_keyword),
5971 .constant_path = constant_path,
5973 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
5974 .name = pm_parser_constant_id_token(parser, name)
5983static pm_multi_target_node_t *
5984pm_multi_target_node_create(pm_parser_t *parser) {
5985 pm_multi_target_node_t *node = PM_NODE_ALLOC(parser, pm_multi_target_node_t);
5987 *node = (pm_multi_target_node_t) {
5989 .type = PM_MULTI_TARGET_NODE,
5990 .node_id = PM_NODE_IDENTIFY(parser),
5991 .location = { .start = NULL, .end = NULL }
5996 .lparen_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
5997 .rparen_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
6007pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t *node, pm_node_t *target) {
6008 if (PM_NODE_TYPE_P(target, PM_SPLAT_NODE)) {
6009 if (node->rest == NULL) {
6010 node->rest = target;
6012 pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
6013 pm_node_list_append(&node->rights, target);
6015 } else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
6016 if (node->rest == NULL) {
6017 node->rest = target;
6019 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
6020 pm_node_list_append(&node->rights, target);
6022 } else if (node->rest == NULL) {
6023 pm_node_list_append(&node->lefts, target);
6025 pm_node_list_append(&node->rights, target);
6028 if (node->base.location.start == NULL || (node->base.location.start > target->location.start)) {
6029 node->base.location.start = target->location.start;
6032 if (node->base.location.end == NULL || (node->base.location.end < target->location.end)) {
6033 node->base.location.end = target->location.end;
6041pm_multi_target_node_opening_set(pm_multi_target_node_t *node, const pm_token_t *lparen) {
6042 node->base.location.start = lparen->start;
6043 node->lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen);
6050pm_multi_target_node_closing_set(pm_multi_target_node_t *node, const pm_token_t *rparen) {
6051 node->base.location.end = rparen->end;
6052 node->rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen);
6058static pm_multi_write_node_t *
6059pm_multi_write_node_create(pm_parser_t *parser, pm_multi_target_node_t *target, const pm_token_t *operator, pm_node_t *value) {
6060 pm_multi_write_node_t *node = PM_NODE_ALLOC(parser, pm_multi_write_node_t);
6062 *node = (pm_multi_write_node_t) {
6064 .type = PM_MULTI_WRITE_NODE,
6065 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
6066 .node_id = PM_NODE_IDENTIFY(parser),
6068 .start = target->base.location.start,
6069 .end = value->location.end
6072 .lefts = target->lefts,
6073 .rest = target->rest,
6074 .rights = target->rights,
6075 .lparen_loc = target->lparen_loc,
6076 .rparen_loc = target->rparen_loc,
6077 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6081 // Explicitly do not call pm_node_destroy here because we want to keep
6082 // around all of the information within the MultiWriteNode node.
6091static pm_next_node_t *
6092pm_next_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6093 assert(keyword->type == PM_TOKEN_KEYWORD_NEXT);
6094 pm_next_node_t *node = PM_NODE_ALLOC(parser, pm_next_node_t);
6096 *node = (pm_next_node_t) {
6098 .type = PM_NEXT_NODE,
6099 .node_id = PM_NODE_IDENTIFY(parser),
6101 .start = keyword->start,
6102 .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
6105 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6106 .arguments = arguments
6115static pm_nil_node_t *
6116pm_nil_node_create(pm_parser_t *parser, const pm_token_t *token) {
6117 assert(token->type == PM_TOKEN_KEYWORD_NIL);
6118 pm_nil_node_t *node = PM_NODE_ALLOC(parser, pm_nil_node_t);
6120 *node = (pm_nil_node_t) {{
6121 .type = PM_NIL_NODE,
6122 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6123 .node_id = PM_NODE_IDENTIFY(parser),
6124 .location = PM_LOCATION_TOKEN_VALUE(token)
6133static pm_no_keywords_parameter_node_t *
6134pm_no_keywords_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
6135 assert(operator->type == PM_TOKEN_USTAR_STAR || operator->type == PM_TOKEN_STAR_STAR);
6136 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
6137 pm_no_keywords_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_no_keywords_parameter_node_t);
6139 *node = (pm_no_keywords_parameter_node_t) {
6141 .type = PM_NO_KEYWORDS_PARAMETER_NODE,
6142 .node_id = PM_NODE_IDENTIFY(parser),
6144 .start = operator->start,
6148 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6149 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
6158static pm_numbered_parameters_node_t *
6159pm_numbered_parameters_node_create(pm_parser_t *parser, const pm_location_t *location, uint8_t maximum) {
6160 pm_numbered_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_parameters_node_t);
6162 *node = (pm_numbered_parameters_node_t) {
6164 .type = PM_NUMBERED_PARAMETERS_NODE,
6165 .node_id = PM_NODE_IDENTIFY(parser),
6166 .location = *location
6178#define NTH_REF_MAX ((uint32_t) (INT_MAX >> 1))
6187pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *token) {
6188 const uint8_t *start = token->start + 1;
6189 const uint8_t *end = token->end;
6191 ptrdiff_t diff = end - start;
6193#if PTRDIFF_MAX > SIZE_MAX
6194 assert(diff < (ptrdiff_t) SIZE_MAX);
6196 size_t length = (size_t) diff;
6198 char *digits = xcalloc(length + 1, sizeof(char));
6199 memcpy(digits, start, length);
6200 digits[length] = '\0';
6204 unsigned long value = strtoul(digits, &endptr, 10);
6206 if ((digits == endptr) || (*endptr != '\0')) {
6207 pm_parser_err(parser, start, end, PM_ERR_INVALID_NUMBER_DECIMAL);
6213 if ((errno == ERANGE) || (value > NTH_REF_MAX)) {
6214 PM_PARSER_WARN_FORMAT(parser, start, end, PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start);
6218 return (uint32_t) value;
6226static pm_numbered_reference_read_node_t *
6227pm_numbered_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
6228 assert(name->type == PM_TOKEN_NUMBERED_REFERENCE);
6229 pm_numbered_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_reference_read_node_t);
6231 *node = (pm_numbered_reference_read_node_t) {
6233 .type = PM_NUMBERED_REFERENCE_READ_NODE,
6234 .node_id = PM_NODE_IDENTIFY(parser),
6235 .location = PM_LOCATION_TOKEN_VALUE(name),
6237 .number = pm_numbered_reference_read_node_number(parser, name)
6246static pm_optional_parameter_node_t *
6247pm_optional_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator, pm_node_t *value) {
6248 pm_optional_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_parameter_node_t);
6250 *node = (pm_optional_parameter_node_t) {
6252 .type = PM_OPTIONAL_PARAMETER_NODE,
6253 .node_id = PM_NODE_IDENTIFY(parser),
6255 .start = name->start,
6256 .end = value->location.end
6259 .name = pm_parser_constant_id_token(parser, name),
6260 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
6261 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6271static pm_or_node_t *
6272pm_or_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
6273 pm_assert_value_expression(parser, left);
6275 pm_or_node_t *node = PM_NODE_ALLOC(parser, pm_or_node_t);
6277 *node = (pm_or_node_t) {
6280 .node_id = PM_NODE_IDENTIFY(parser),
6282 .start = left->location.start,
6283 .end = right->location.end
6288 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6297static pm_parameters_node_t *
6298pm_parameters_node_create(pm_parser_t *parser) {
6299 pm_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_parameters_node_t);
6301 *node = (pm_parameters_node_t) {
6303 .type = PM_PARAMETERS_NODE,
6304 .node_id = PM_NODE_IDENTIFY(parser),
6305 .location = PM_LOCATION_TOKEN_VALUE(&parser->current)
6308 .keyword_rest = NULL,
6323pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param) {
6324 if (params->base.location.start == NULL) {
6325 params->base.location.start = param->location.start;
6327 params->base.location.start = params->base.location.start < param->location.start ? params->base.location.start : param->location.start;
6330 if (params->base.location.end == NULL) {
6331 params->base.location.end = param->location.end;
6333 params->base.location.end = params->base.location.end > param->location.end ? params->base.location.end : param->location.end;
6341pm_parameters_node_requireds_append(pm_parameters_node_t *params, pm_node_t *param) {
6342 pm_parameters_node_location_set(params, param);
6343 pm_node_list_append(¶ms->requireds, param);
6350pm_parameters_node_optionals_append(pm_parameters_node_t *params, pm_optional_parameter_node_t *param) {
6351 pm_parameters_node_location_set(params, (pm_node_t *) param);
6352 pm_node_list_append(¶ms->optionals, (pm_node_t *) param);
6359pm_parameters_node_posts_append(pm_parameters_node_t *params, pm_node_t *param) {
6360 pm_parameters_node_location_set(params, param);
6361 pm_node_list_append(¶ms->posts, param);
6368pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6369 pm_parameters_node_location_set(params, param);
6370 params->rest = param;
6377pm_parameters_node_keywords_append(pm_parameters_node_t *params, pm_node_t *param) {
6378 pm_parameters_node_location_set(params, param);
6379 pm_node_list_append(¶ms->keywords, param);
6386pm_parameters_node_keyword_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6387 assert(params->keyword_rest == NULL);
6388 pm_parameters_node_location_set(params, param);
6389 params->keyword_rest = param;
6396pm_parameters_node_block_set(pm_parameters_node_t *params, pm_block_parameter_node_t *param) {
6397 assert(params->block == NULL);
6398 pm_parameters_node_location_set(params, (pm_node_t *) param);
6399 params->block = param;
6405static pm_program_node_t *
6406pm_program_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, pm_statements_node_t *statements) {
6407 pm_program_node_t *node = PM_NODE_ALLOC(parser, pm_program_node_t);
6409 *node = (pm_program_node_t) {
6411 .type = PM_PROGRAM_NODE,
6412 .node_id = PM_NODE_IDENTIFY(parser),
6414 .start = statements == NULL ? parser->start : statements->base.location.start,
6415 .end = statements == NULL ? parser->end : statements->base.location.end
6419 .statements = statements
6428static pm_parentheses_node_t *
6429pm_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) {
6430 pm_parentheses_node_t *node = PM_NODE_ALLOC(parser, pm_parentheses_node_t);
6432 *node = (pm_parentheses_node_t) {
6434 .type = PM_PARENTHESES_NODE,
6436 .node_id = PM_NODE_IDENTIFY(parser),
6438 .start = opening->start,
6443 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6444 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6453static pm_pinned_expression_node_t *
6454pm_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) {
6455 pm_pinned_expression_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_expression_node_t);
6457 *node = (pm_pinned_expression_node_t) {
6459 .type = PM_PINNED_EXPRESSION_NODE,
6460 .node_id = PM_NODE_IDENTIFY(parser),
6462 .start = operator->start,
6466 .expression = expression,
6467 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6468 .lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen),
6469 .rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen)
6478static pm_pinned_variable_node_t *
6479pm_pinned_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
6480 pm_pinned_variable_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_variable_node_t);
6482 *node = (pm_pinned_variable_node_t) {
6484 .type = PM_PINNED_VARIABLE_NODE,
6485 .node_id = PM_NODE_IDENTIFY(parser),
6487 .start = operator->start,
6488 .end = variable->location.end
6491 .variable = variable,
6492 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6501static pm_post_execution_node_t *
6502pm_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) {
6503 pm_post_execution_node_t *node = PM_NODE_ALLOC(parser, pm_post_execution_node_t);
6505 *node = (pm_post_execution_node_t) {
6507 .type = PM_POST_EXECUTION_NODE,
6508 .node_id = PM_NODE_IDENTIFY(parser),
6510 .start = keyword->start,
6514 .statements = statements,
6515 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6516 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6517 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6526static pm_pre_execution_node_t *
6527pm_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) {
6528 pm_pre_execution_node_t *node = PM_NODE_ALLOC(parser, pm_pre_execution_node_t);
6530 *node = (pm_pre_execution_node_t) {
6532 .type = PM_PRE_EXECUTION_NODE,
6533 .node_id = PM_NODE_IDENTIFY(parser),
6535 .start = keyword->start,
6539 .statements = statements,
6540 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6541 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6542 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6551static pm_range_node_t *
6552pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
6553 pm_assert_value_expression(parser, left);
6554 pm_assert_value_expression(parser, right);
6556 pm_range_node_t *node = PM_NODE_ALLOC(parser, pm_range_node_t);
6557 pm_node_flags_t flags = 0;
6559 // Indicate that this node is an exclusive range if the operator is `...`.
6560 if (operator->type == PM_TOKEN_DOT_DOT_DOT || operator->type == PM_TOKEN_UDOT_DOT_DOT) {
6561 flags |= PM_RANGE_FLAGS_EXCLUDE_END;
6564 // Indicate that this node is a static literal (i.e., can be compiled with
6565 // a putobject in CRuby) if the left and right are implicit nil, explicit
6566 // nil, or integers.
6568 (left == NULL || PM_NODE_TYPE_P(left, PM_NIL_NODE) || PM_NODE_TYPE_P(left, PM_INTEGER_NODE)) &&
6569 (right == NULL || PM_NODE_TYPE_P(right, PM_NIL_NODE) || PM_NODE_TYPE_P(right, PM_INTEGER_NODE))
6571 flags |= PM_NODE_FLAG_STATIC_LITERAL;
6574 *node = (pm_range_node_t) {
6576 .type = PM_RANGE_NODE,
6578 .node_id = PM_NODE_IDENTIFY(parser),
6580 .start = (left == NULL ? operator->start : left->location.start),
6581 .end = (right == NULL ? operator->end : right->location.end)
6586 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6595static pm_redo_node_t *
6596pm_redo_node_create(pm_parser_t *parser, const pm_token_t *token) {
6597 assert(token->type == PM_TOKEN_KEYWORD_REDO);
6598 pm_redo_node_t *node = PM_NODE_ALLOC(parser, pm_redo_node_t);
6600 *node = (pm_redo_node_t) {{
6601 .type = PM_REDO_NODE,
6602 .node_id = PM_NODE_IDENTIFY(parser),
6603 .location = PM_LOCATION_TOKEN_VALUE(token)
6613static pm_regular_expression_node_t *
6614pm_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) {
6615 pm_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_regular_expression_node_t);
6617 *node = (pm_regular_expression_node_t) {
6619 .type = PM_REGULAR_EXPRESSION_NODE,
6620 .flags = pm_regular_expression_flags_create(parser, closing) | PM_NODE_FLAG_STATIC_LITERAL,
6621 .node_id = PM_NODE_IDENTIFY(parser),
6623 .start = MIN(opening->start, closing->start),
6624 .end = MAX(opening->end, closing->end)
6627 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6628 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
6629 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
6630 .unescaped = *unescaped
6639static inline pm_regular_expression_node_t *
6640pm_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6641 return pm_regular_expression_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6647static pm_required_parameter_node_t *
6648pm_required_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
6649 pm_required_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_parameter_node_t);
6651 *node = (pm_required_parameter_node_t) {
6653 .type = PM_REQUIRED_PARAMETER_NODE,
6654 .node_id = PM_NODE_IDENTIFY(parser),
6655 .location = PM_LOCATION_TOKEN_VALUE(token)
6657 .name = pm_parser_constant_id_token(parser, token)
6666static pm_rescue_modifier_node_t *
6667pm_rescue_modifier_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *keyword, pm_node_t *rescue_expression) {
6668 pm_rescue_modifier_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_modifier_node_t);
6670 *node = (pm_rescue_modifier_node_t) {
6672 .type = PM_RESCUE_MODIFIER_NODE,
6673 .node_id = PM_NODE_IDENTIFY(parser),
6675 .start = expression->location.start,
6676 .end = rescue_expression->location.end
6679 .expression = expression,
6680 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6681 .rescue_expression = rescue_expression
6690static pm_rescue_node_t *
6691pm_rescue_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
6692 pm_rescue_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_node_t);
6694 *node = (pm_rescue_node_t) {
6696 .type = PM_RESCUE_NODE,
6697 .node_id = PM_NODE_IDENTIFY(parser),
6698 .location = PM_LOCATION_TOKEN_VALUE(keyword)
6700 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6701 .operator_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
6702 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
6713pm_rescue_node_operator_set(pm_rescue_node_t *node, const pm_token_t *operator) {
6714 node->operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
6721pm_rescue_node_reference_set(pm_rescue_node_t *node, pm_node_t *reference) {
6722 node->reference = reference;
6723 node->base.location.end = reference->location.end;
6730pm_rescue_node_statements_set(pm_rescue_node_t *node, pm_statements_node_t *statements) {
6731 node->statements = statements;
6732 if (pm_statements_node_body_length(statements) > 0) {
6733 node->base.location.end = statements->base.location.end;
6741pm_rescue_node_subsequent_set(pm_rescue_node_t *node, pm_rescue_node_t *subsequent) {
6742 node->subsequent = subsequent;
6743 node->base.location.end = subsequent->base.location.end;
6750pm_rescue_node_exceptions_append(pm_rescue_node_t *node, pm_node_t *exception) {
6751 pm_node_list_append(&node->exceptions, exception);
6752 node->base.location.end = exception->location.end;
6758static pm_rest_parameter_node_t *
6759pm_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
6760 pm_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_rest_parameter_node_t);
6762 *node = (pm_rest_parameter_node_t) {
6764 .type = PM_REST_PARAMETER_NODE,
6765 .node_id = PM_NODE_IDENTIFY(parser),
6767 .start = operator->start,
6768 .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
6771 .name = pm_parser_optional_constant_id_token(parser, name),
6772 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
6773 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6782static pm_retry_node_t *
6783pm_retry_node_create(pm_parser_t *parser, const pm_token_t *token) {
6784 assert(token->type == PM_TOKEN_KEYWORD_RETRY);
6785 pm_retry_node_t *node = PM_NODE_ALLOC(parser, pm_retry_node_t);
6787 *node = (pm_retry_node_t) {{
6788 .type = PM_RETRY_NODE,
6789 .node_id = PM_NODE_IDENTIFY(parser),
6790 .location = PM_LOCATION_TOKEN_VALUE(token)
6799static pm_return_node_t *
6800pm_return_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6801 pm_return_node_t *node = PM_NODE_ALLOC(parser, pm_return_node_t);
6803 *node = (pm_return_node_t) {
6805 .type = PM_RETURN_NODE,
6806 .node_id = PM_NODE_IDENTIFY(parser),
6808 .start = keyword->start,
6809 .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
6812 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6813 .arguments = arguments
6822static pm_self_node_t *
6823pm_self_node_create(pm_parser_t *parser, const pm_token_t *token) {
6824 assert(token->type == PM_TOKEN_KEYWORD_SELF);
6825 pm_self_node_t *node = PM_NODE_ALLOC(parser, pm_self_node_t);
6827 *node = (pm_self_node_t) {{
6828 .type = PM_SELF_NODE,
6829 .node_id = PM_NODE_IDENTIFY(parser),
6830 .location = PM_LOCATION_TOKEN_VALUE(token)
6839static pm_shareable_constant_node_t *
6840pm_shareable_constant_node_create(pm_parser_t *parser, pm_node_t *write, pm_shareable_constant_value_t value) {
6841 pm_shareable_constant_node_t *node = PM_NODE_ALLOC(parser, pm_shareable_constant_node_t);
6843 *node = (pm_shareable_constant_node_t) {
6845 .type = PM_SHAREABLE_CONSTANT_NODE,
6846 .flags = (pm_node_flags_t) value,
6847 .node_id = PM_NODE_IDENTIFY(parser),
6848 .location = PM_LOCATION_NODE_VALUE(write)
6859static pm_singleton_class_node_t *
6860pm_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) {
6861 pm_singleton_class_node_t *node = PM_NODE_ALLOC(parser, pm_singleton_class_node_t);
6863 *node = (pm_singleton_class_node_t) {
6865 .type = PM_SINGLETON_CLASS_NODE,
6866 .node_id = PM_NODE_IDENTIFY(parser),
6868 .start = class_keyword->start,
6869 .end = end_keyword->end
6873 .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
6874 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6875 .expression = expression,
6877 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
6886static pm_source_encoding_node_t *
6887pm_source_encoding_node_create(pm_parser_t *parser, const pm_token_t *token) {
6888 assert(token->type == PM_TOKEN_KEYWORD___ENCODING__);
6889 pm_source_encoding_node_t *node = PM_NODE_ALLOC(parser, pm_source_encoding_node_t);
6891 *node = (pm_source_encoding_node_t) {{
6892 .type = PM_SOURCE_ENCODING_NODE,
6893 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6894 .node_id = PM_NODE_IDENTIFY(parser),
6895 .location = PM_LOCATION_TOKEN_VALUE(token)
6904static pm_source_file_node_t*
6905pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword) {
6906 pm_source_file_node_t *node = PM_NODE_ALLOC(parser, pm_source_file_node_t);
6907 assert(file_keyword->type == PM_TOKEN_KEYWORD___FILE__);
6909 pm_node_flags_t flags = 0;
6911 switch (parser->frozen_string_literal) {
6912 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6913 flags |= PM_STRING_FLAGS_MUTABLE;
6915 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6916 flags |= PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6920 *node = (pm_source_file_node_t) {
6922 .type = PM_SOURCE_FILE_NODE,
6924 .node_id = PM_NODE_IDENTIFY(parser),
6925 .location = PM_LOCATION_TOKEN_VALUE(file_keyword),
6927 .filepath = parser->filepath
6936static pm_source_line_node_t *
6937pm_source_line_node_create(pm_parser_t *parser, const pm_token_t *token) {
6938 assert(token->type == PM_TOKEN_KEYWORD___LINE__);
6939 pm_source_line_node_t *node = PM_NODE_ALLOC(parser, pm_source_line_node_t);
6941 *node = (pm_source_line_node_t) {{
6942 .type = PM_SOURCE_LINE_NODE,
6943 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6944 .node_id = PM_NODE_IDENTIFY(parser),
6945 .location = PM_LOCATION_TOKEN_VALUE(token)
6954static pm_splat_node_t *
6955pm_splat_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
6956 pm_splat_node_t *node = PM_NODE_ALLOC(parser, pm_splat_node_t);
6958 *node = (pm_splat_node_t) {
6960 .type = PM_SPLAT_NODE,
6961 .node_id = PM_NODE_IDENTIFY(parser),
6963 .start = operator->start,
6964 .end = (expression == NULL ? operator->end : expression->location.end)
6967 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6968 .expression = expression
6977static pm_statements_node_t *
6978pm_statements_node_create(pm_parser_t *parser) {
6979 pm_statements_node_t *node = PM_NODE_ALLOC(parser, pm_statements_node_t);
6981 *node = (pm_statements_node_t) {
6983 .type = PM_STATEMENTS_NODE,
6984 .node_id = PM_NODE_IDENTIFY(parser),
6985 .location = PM_LOCATION_NULL_VALUE(parser)
6997pm_statements_node_body_length(pm_statements_node_t *node) {
6998 return node && node->body.size;
7005pm_statements_node_location_set(pm_statements_node_t *node, const uint8_t *start, const uint8_t *end) {
7006 node->base.location = (pm_location_t) { .start = start, .end = end };
7014pm_statements_node_body_update(pm_statements_node_t *node, pm_node_t *statement) {
7015 if (pm_statements_node_body_length(node) == 0 || statement->location.start < node->base.location.start) {
7016 node->base.location.start = statement->location.start;
7019 if (statement->location.end > node->base.location.end) {
7020 node->base.location.end = statement->location.end;
7028pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline) {
7029 pm_statements_node_body_update(node, statement);
7031 if (node->body.size > 0) {
7032 const pm_node_t *previous = node->body.nodes[node->body.size - 1];
7034 switch (PM_NODE_TYPE(previous)) {
7039 case PM_RETURN_NODE:
7040 pm_parser_warn_node(parser, statement, PM_WARN_UNREACHABLE_STATEMENT);
7047 pm_node_list_append(&node->body, statement);
7048 if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
7055pm_statements_node_body_prepend(pm_statements_node_t *node, pm_node_t *statement) {
7056 pm_statements_node_body_update(node, statement);
7057 pm_node_list_prepend(&node->body, statement);
7058 pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
7064static inline pm_string_node_t *
7065pm_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) {
7066 pm_string_node_t *node = PM_NODE_ALLOC(parser, pm_string_node_t);
7067 pm_node_flags_t flags = 0;
7069 switch (parser->frozen_string_literal) {
7070 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
7071 flags = PM_STRING_FLAGS_MUTABLE;
7073 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
7074 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
7078 *node = (pm_string_node_t) {
7080 .type = PM_STRING_NODE,
7082 .node_id = PM_NODE_IDENTIFY(parser),
7084 .start = (opening->type == PM_TOKEN_NOT_PROVIDED ? content->start : opening->start),
7085 .end = (closing->type == PM_TOKEN_NOT_PROVIDED ? content->end : closing->end)
7088 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7089 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
7090 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7091 .unescaped = *string
7100static pm_string_node_t *
7101pm_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7102 return pm_string_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7109static pm_string_node_t *
7110pm_string_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7111 pm_string_node_t *node = pm_string_node_create_unescaped(parser, opening, content, closing, &parser->current_string);
7112 parser->current_string = PM_STRING_EMPTY;
7119static pm_super_node_t *
7120pm_super_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_t *arguments) {
7121 assert(keyword->type == PM_TOKEN_KEYWORD_SUPER);
7122 pm_super_node_t *node = PM_NODE_ALLOC(parser, pm_super_node_t);
7124 const uint8_t *end = pm_arguments_end(arguments);
7126 assert(false && "unreachable");
7129 *node = (pm_super_node_t) {
7131 .type = PM_SUPER_NODE,
7132 .node_id = PM_NODE_IDENTIFY(parser),
7134 .start = keyword->start,
7138 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7139 .lparen_loc = arguments->opening_loc,
7140 .arguments = arguments->arguments,
7141 .rparen_loc = arguments->closing_loc,
7142 .block = arguments->block
7153pm_ascii_only_p(const pm_string_t *contents) {
7154 const size_t length = pm_string_length(contents);
7155 const uint8_t *source = pm_string_source(contents);
7157 for (size_t index = 0; index < length; index++) {
7158 if (source[index] & 0x80) return false;
7168parse_symbol_encoding_validate_utf8(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
7169 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
7170 size_t width = pm_encoding_utf_8_char_width(cursor, end - cursor);
7173 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
7186parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
7187 const pm_encoding_t *encoding = parser->encoding;
7189 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
7190 size_t width = encoding->char_width(cursor, end - cursor);
7193 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
7210static inline pm_node_flags_t
7211parse_symbol_encoding(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents, bool validate) {
7212 if (parser->explicit_encoding != NULL) {
7213 // A Symbol may optionally have its encoding explicitly set. This will
7214 // happen if an escape sequence results in a non-ASCII code point.
7215 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7216 if (validate) parse_symbol_encoding_validate_utf8(parser, location, contents);
7217 return PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING;
7218 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7219 return PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING;
7220 } else if (validate) {
7221 parse_symbol_encoding_validate_other(parser, location, contents);
7223 } else if (pm_ascii_only_p(contents)) {
7224 // Ruby stipulates that all source files must use an ASCII-compatible
7225 // encoding. Thus, all symbols appearing in source are eligible for
7226 // "downgrading" to US-ASCII.
7227 return PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING;
7228 } else if (validate) {
7229 parse_symbol_encoding_validate_other(parser, location, contents);
7235static pm_node_flags_t
7236parse_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) {
7237 assert ((modifier == 'n' && modifier_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) ||
7238 (modifier == 'u' && modifier_encoding == PM_ENCODING_UTF_8_ENTRY) ||
7239 (modifier == 'e' && modifier_encoding == PM_ENCODING_EUC_JP_ENTRY) ||
7240 (modifier == 's' && modifier_encoding == PM_ENCODING_WINDOWS_31J_ENTRY));
7242 // There's special validation logic used if a string does not contain any character escape sequences.
7243 if (parser->explicit_encoding == NULL) {
7244 // If an ASCII-only string without character escapes is used with an encoding modifier, then resulting Regexp
7245 // has the modifier encoding, unless the ASCII-8BIT modifier is used, in which case the Regexp "downgrades" to
7246 // the US-ASCII encoding.
7248 return modifier == 'n' ? PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING : flags;
7251 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7253 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
7255 } else if (parser->encoding != modifier_encoding) {
7256 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_ENCODING_OPTION_MISMATCH, modifier, parser->encoding->name);
7258 if (modifier == 'n' && !ascii_only) {
7259 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));
7266 // 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.
7267 bool mixed_encoding = false;
7269 if (mixed_encoding) {
7270 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 != 'n' && parser->explicit_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) {
7272 // 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.
7273 bool valid_string_in_modifier_encoding = true;
7275 if (!valid_string_in_modifier_encoding) {
7276 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
7278 } else if (modifier != 'u' && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7279 // 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.
7280 if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
7281 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));
7285 // We've determined the encoding would naturally be EUC-JP and there is no need to force the encoding to anything else.
7295static pm_node_flags_t
7296parse_and_validate_regular_expression_encoding(pm_parser_t *parser, const pm_string_t *source, bool ascii_only, pm_node_flags_t flags) {
7297 // 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.
7298 bool valid_unicode_range = true;
7299 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY && !valid_unicode_range) {
7300 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));
7304 // US-ASCII strings do not admit multi-byte character literals. However, character escape sequences corresponding
7305 // to multi-byte characters are allowed.
7306 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY && parser->explicit_encoding == NULL && !ascii_only) {
7307 // CRuby will continue processing even though a SyntaxError has already been detected. It may result in the
7308 // following error message appearing twice. We do the same for compatibility.
7309 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
7320 if (flags & PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT) {
7321 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'n', PM_ENCODING_ASCII_8BIT_ENTRY);
7324 if (flags & PM_REGULAR_EXPRESSION_FLAGS_UTF_8) {
7325 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'u', PM_ENCODING_UTF_8_ENTRY);
7328 if (flags & PM_REGULAR_EXPRESSION_FLAGS_EUC_JP) {
7329 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'e', PM_ENCODING_EUC_JP_ENTRY);
7332 if (flags & PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J) {
7333 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 's', PM_ENCODING_WINDOWS_31J_ENTRY);
7336 // At this point no encoding modifiers will be present on the regular expression as they would have already
7337 // been processed. Ruby stipulates that all source files must use an ASCII-compatible encoding. Thus, all
7338 // regular expressions without an encoding modifier appearing in source are eligible for "downgrading" to US-ASCII.
7340 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING;
7343 // A Regexp may optionally have its encoding explicitly set via a character escape sequence in the source string
7344 // or by specifying a modifier.
7346 // NB: an explicitly set encoding is ignored by Ruby if the Regexp consists of only US ASCII code points.
7347 if (parser->explicit_encoding != NULL) {
7348 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7349 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING;
7350 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7351 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING;
7362static pm_symbol_node_t *
7363pm_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) {
7364 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7366 *node = (pm_symbol_node_t) {
7368 .type = PM_SYMBOL_NODE,
7369 .flags = PM_NODE_FLAG_STATIC_LITERAL | flags,
7370 .node_id = PM_NODE_IDENTIFY(parser),
7372 .start = (opening->type == PM_TOKEN_NOT_PROVIDED ? value->start : opening->start),
7373 .end = (closing->type == PM_TOKEN_NOT_PROVIDED ? value->end : closing->end)
7376 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7377 .value_loc = PM_LOCATION_TOKEN_VALUE(value),
7378 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7379 .unescaped = *unescaped
7388static inline pm_symbol_node_t *
7389pm_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
7390 return pm_symbol_node_create_unescaped(parser, opening, value, closing, &PM_STRING_EMPTY, 0);
7396static pm_symbol_node_t *
7397pm_symbol_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
7398 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));
7399 parser->current_string = PM_STRING_EMPTY;
7406static pm_symbol_node_t *
7407pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
7408 pm_symbol_node_t *node;
7410 switch (token->type) {
7411 case PM_TOKEN_LABEL: {
7412 pm_token_t opening = not_provided(parser);
7413 pm_token_t closing = { .type = PM_TOKEN_LABEL_END, .start = token->end - 1, .end = token->end };
7415 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end - 1 };
7416 node = pm_symbol_node_create(parser, &opening, &label, &closing);
7418 assert((label.end - label.start) >= 0);
7419 pm_string_shared_init(&node->unescaped, label.start, label.end);
7420 pm_node_flag_set((pm_node_t *) node, parse_symbol_encoding(parser, &label, &node->unescaped, false));
7424 case PM_TOKEN_MISSING: {
7425 pm_token_t opening = not_provided(parser);
7426 pm_token_t closing = not_provided(parser);
7428 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end };
7429 node = pm_symbol_node_create(parser, &opening, &label, &closing);
7433 assert(false && "unreachable");
7444static pm_symbol_node_t *
7445pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
7446 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7448 *node = (pm_symbol_node_t) {
7450 .type = PM_SYMBOL_NODE,
7451 .flags = PM_NODE_FLAG_STATIC_LITERAL | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING,
7452 .node_id = PM_NODE_IDENTIFY(parser),
7453 .location = PM_LOCATION_NULL_VALUE(parser)
7455 .value_loc = PM_LOCATION_NULL_VALUE(parser),
7459 pm_string_constant_init(&node->unescaped, content, strlen(content));
7467pm_symbol_node_label_p(pm_node_t *node) {
7468 const uint8_t *end = NULL;
7470 switch (PM_NODE_TYPE(node)) {
7471 case PM_SYMBOL_NODE:
7472 end = ((pm_symbol_node_t *) node)->closing_loc.end;
7474 case PM_INTERPOLATED_SYMBOL_NODE:
7475 end = ((pm_interpolated_symbol_node_t *) node)->closing_loc.end;
7481 return (end != NULL) && (end[-1] == ':');
7487static pm_symbol_node_t *
7488pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const pm_token_t *opening, const pm_token_t *closing) {
7489 pm_symbol_node_t *new_node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7491 *new_node = (pm_symbol_node_t) {
7493 .type = PM_SYMBOL_NODE,
7494 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7495 .node_id = PM_NODE_IDENTIFY(parser),
7497 .start = opening->start,
7501 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7502 .value_loc = node->content_loc,
7503 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7504 .unescaped = node->unescaped
7507 pm_token_t content = { .type = PM_TOKEN_IDENTIFIER, .start = node->content_loc.start, .end = node->content_loc.end };
7508 pm_node_flag_set((pm_node_t *) new_node, parse_symbol_encoding(parser, &content, &node->unescaped, true));
7510 // We are explicitly _not_ using pm_node_destroy here because we don't want
7511 // to trash the unescaped string. We could instead copy the string if we
7512 // know that it is owned, but we're taking the fast path for now.
7521static pm_string_node_t *
7522pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
7523 pm_string_node_t *new_node = PM_NODE_ALLOC(parser, pm_string_node_t);
7524 pm_node_flags_t flags = 0;
7526 switch (parser->frozen_string_literal) {
7527 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
7528 flags = PM_STRING_FLAGS_MUTABLE;
7530 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
7531 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
7535 *new_node = (pm_string_node_t) {
7537 .type = PM_STRING_NODE,
7539 .node_id = PM_NODE_IDENTIFY(parser),
7540 .location = node->base.location
7542 .opening_loc = node->opening_loc,
7543 .content_loc = node->value_loc,
7544 .closing_loc = node->closing_loc,
7545 .unescaped = node->unescaped
7548 // We are explicitly _not_ using pm_node_destroy here because we don't want
7549 // to trash the unescaped string. We could instead copy the string if we
7550 // know that it is owned, but we're taking the fast path for now.
7559static pm_true_node_t *
7560pm_true_node_create(pm_parser_t *parser, const pm_token_t *token) {
7561 assert(token->type == PM_TOKEN_KEYWORD_TRUE);
7562 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
7564 *node = (pm_true_node_t) {{
7565 .type = PM_TRUE_NODE,
7566 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7567 .node_id = PM_NODE_IDENTIFY(parser),
7568 .location = PM_LOCATION_TOKEN_VALUE(token)
7577static pm_true_node_t *
7578pm_true_node_synthesized_create(pm_parser_t *parser) {
7579 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
7581 *node = (pm_true_node_t) {{
7582 .type = PM_TRUE_NODE,
7583 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7584 .node_id = PM_NODE_IDENTIFY(parser),
7585 .location = { .start = parser->start, .end = parser->end }
7594static pm_undef_node_t *
7595pm_undef_node_create(pm_parser_t *parser, const pm_token_t *token) {
7596 assert(token->type == PM_TOKEN_KEYWORD_UNDEF);
7597 pm_undef_node_t *node = PM_NODE_ALLOC(parser, pm_undef_node_t);
7599 *node = (pm_undef_node_t) {
7601 .type = PM_UNDEF_NODE,
7602 .node_id = PM_NODE_IDENTIFY(parser),
7603 .location = PM_LOCATION_TOKEN_VALUE(token),
7605 .keyword_loc = PM_LOCATION_TOKEN_VALUE(token),
7616pm_undef_node_append(pm_undef_node_t *node, pm_node_t *name) {
7617 node->base.location.end = name->location.end;
7618 pm_node_list_append(&node->names, name);
7624static pm_unless_node_t *
7625pm_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) {
7626 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7627 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
7630 if (statements != NULL) {
7631 end = statements->base.location.end;
7633 end = predicate->location.end;
7636 *node = (pm_unless_node_t) {
7638 .type = PM_UNLESS_NODE,
7639 .flags = PM_NODE_FLAG_NEWLINE,
7640 .node_id = PM_NODE_IDENTIFY(parser),
7642 .start = keyword->start,
7646 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7647 .predicate = predicate,
7648 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
7649 .statements = statements,
7650 .else_clause = NULL,
7651 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
7660static pm_unless_node_t *
7661pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *unless_keyword, pm_node_t *predicate) {
7662 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7663 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
7665 pm_statements_node_t *statements = pm_statements_node_create(parser);
7666 pm_statements_node_body_append(parser, statements, statement, true);
7668 *node = (pm_unless_node_t) {
7670 .type = PM_UNLESS_NODE,
7671 .flags = PM_NODE_FLAG_NEWLINE,
7672 .node_id = PM_NODE_IDENTIFY(parser),
7674 .start = statement->location.start,
7675 .end = predicate->location.end
7678 .keyword_loc = PM_LOCATION_TOKEN_VALUE(unless_keyword),
7679 .predicate = predicate,
7680 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7681 .statements = statements,
7682 .else_clause = NULL,
7683 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
7690pm_unless_node_end_keyword_loc_set(pm_unless_node_t *node, const pm_token_t *end_keyword) {
7691 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
7692 node->base.location.end = end_keyword->end;
7701pm_loop_modifier_block_exits(pm_parser_t *parser, pm_statements_node_t *statements) {
7702 assert(parser->current_block_exits != NULL);
7704 // All of the block exits that we want to remove should be within the
7705 // statements, and since we are modifying the statements, we shouldn't have
7706 // to check the end location.
7707 const uint8_t *start = statements->base.location.start;
7709 for (size_t index = parser->current_block_exits->size; index > 0; index--) {
7710 pm_node_t *block_exit = parser->current_block_exits->nodes[index - 1];
7711 if (block_exit->location.start < start) break;
7713 // Implicitly remove from the list by lowering the size.
7714 parser->current_block_exits->size--;
7721static pm_until_node_t *
7722pm_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) {
7723 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
7724 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7726 *node = (pm_until_node_t) {
7728 .type = PM_UNTIL_NODE,
7730 .node_id = PM_NODE_IDENTIFY(parser),
7732 .start = keyword->start,
7733 .end = closing->end,
7736 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7737 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
7738 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7739 .predicate = predicate,
7740 .statements = statements
7749static pm_until_node_t *
7750pm_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) {
7751 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
7752 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7753 pm_loop_modifier_block_exits(parser, statements);
7755 *node = (pm_until_node_t) {
7757 .type = PM_UNTIL_NODE,
7759 .node_id = PM_NODE_IDENTIFY(parser),
7761 .start = statements->base.location.start,
7762 .end = predicate->location.end,
7765 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7766 .do_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7767 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7768 .predicate = predicate,
7769 .statements = statements
7778static pm_when_node_t *
7779pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
7780 pm_when_node_t *node = PM_NODE_ALLOC(parser, pm_when_node_t);
7782 *node = (pm_when_node_t) {
7784 .type = PM_WHEN_NODE,
7785 .node_id = PM_NODE_IDENTIFY(parser),
7787 .start = keyword->start,
7791 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7793 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7804pm_when_node_conditions_append(pm_when_node_t *node, pm_node_t *condition) {
7805 node->base.location.end = condition->location.end;
7806 pm_node_list_append(&node->conditions, condition);
7813pm_when_node_then_keyword_loc_set(pm_when_node_t *node, const pm_token_t *then_keyword) {
7814 node->base.location.end = then_keyword->end;
7815 node->then_keyword_loc = PM_LOCATION_TOKEN_VALUE(then_keyword);
7822pm_when_node_statements_set(pm_when_node_t *node, pm_statements_node_t *statements) {
7823 if (statements->base.location.end > node->base.location.end) {
7824 node->base.location.end = statements->base.location.end;
7827 node->statements = statements;
7833static pm_while_node_t *
7834pm_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) {
7835 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7836 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7838 *node = (pm_while_node_t) {
7840 .type = PM_WHILE_NODE,
7842 .node_id = PM_NODE_IDENTIFY(parser),
7844 .start = keyword->start,
7848 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7849 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
7850 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7851 .predicate = predicate,
7852 .statements = statements
7861static pm_while_node_t *
7862pm_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) {
7863 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7864 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7865 pm_loop_modifier_block_exits(parser, statements);
7867 *node = (pm_while_node_t) {
7869 .type = PM_WHILE_NODE,
7871 .node_id = PM_NODE_IDENTIFY(parser),
7873 .start = statements->base.location.start,
7874 .end = predicate->location.end
7877 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7878 .do_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7879 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7880 .predicate = predicate,
7881 .statements = statements
7890static pm_while_node_t *
7891pm_while_node_synthesized_create(pm_parser_t *parser, pm_node_t *predicate, pm_statements_node_t *statements) {
7892 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7894 *node = (pm_while_node_t) {
7896 .type = PM_WHILE_NODE,
7897 .node_id = PM_NODE_IDENTIFY(parser),
7898 .location = PM_LOCATION_NULL_VALUE(parser)
7900 .keyword_loc = PM_LOCATION_NULL_VALUE(parser),
7901 .do_keyword_loc = PM_LOCATION_NULL_VALUE(parser),
7902 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
7903 .predicate = predicate,
7904 .statements = statements
7914static pm_x_string_node_t *
7915pm_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) {
7916 pm_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_x_string_node_t);
7918 *node = (pm_x_string_node_t) {
7920 .type = PM_X_STRING_NODE,
7921 .flags = PM_STRING_FLAGS_FROZEN,
7922 .node_id = PM_NODE_IDENTIFY(parser),
7924 .start = opening->start,
7928 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
7929 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
7930 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
7931 .unescaped = *unescaped
7940static inline pm_x_string_node_t *
7941pm_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7942 return pm_xstring_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7948static pm_yield_node_t *
7949pm_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) {
7950 pm_yield_node_t *node = PM_NODE_ALLOC(parser, pm_yield_node_t);
7953 if (rparen_loc->start != NULL) {
7954 end = rparen_loc->end;
7955 } else if (arguments != NULL) {
7956 end = arguments->base.location.end;
7957 } else if (lparen_loc->start != NULL) {
7958 end = lparen_loc->end;
7963 *node = (pm_yield_node_t) {
7965 .type = PM_YIELD_NODE,
7966 .node_id = PM_NODE_IDENTIFY(parser),
7968 .start = keyword->start,
7972 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7973 .lparen_loc = *lparen_loc,
7974 .arguments = arguments,
7975 .rparen_loc = *rparen_loc
7982#undef PM_NODE_IDENTIFY
7989pm_parser_local_depth_constant_id(pm_parser_t *parser, pm_constant_id_t constant_id) {
7990 pm_scope_t *scope = parser->current_scope;
7993 while (scope != NULL) {
7994 if (pm_locals_find(&scope->locals, constant_id) != UINT32_MAX) return depth;
7995 if (scope->closed) break;
7997 scope = scope->previous;
8010pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
8011 return pm_parser_local_depth_constant_id(parser, pm_parser_constant_id_token(parser, token));
8018pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id, const uint8_t *start, const uint8_t *end, uint32_t reads) {
8019 pm_locals_write(&parser->current_scope->locals, constant_id, start, end, reads);
8025static pm_constant_id_t
8026pm_parser_local_add_location(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, uint32_t reads) {
8027 pm_constant_id_t constant_id = pm_parser_constant_id_location(parser, start, end);
8028 if (constant_id != 0) pm_parser_local_add(parser, constant_id, start, end, reads);
8035static inline pm_constant_id_t
8036pm_parser_local_add_token(pm_parser_t *parser, pm_token_t *token, uint32_t reads) {
8037 return pm_parser_local_add_location(parser, token->start, token->end, reads);
8043static pm_constant_id_t
8044pm_parser_local_add_owned(pm_parser_t *parser, uint8_t *start, size_t length) {
8045 pm_constant_id_t constant_id = pm_parser_constant_id_owned(parser, start, length);
8046 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
8053static pm_constant_id_t
8054pm_parser_local_add_constant(pm_parser_t *parser, const char *start, size_t length) {
8055 pm_constant_id_t constant_id = pm_parser_constant_id_constant(parser, start, length);
8056 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
8068pm_parser_parameter_name_check(pm_parser_t *parser, const pm_token_t *name) {
8069 // We want to check whether the parameter name is a numbered parameter or
8071 pm_refute_numbered_parameter(parser, name->start, name->end);
8073 // Otherwise we'll fetch the constant id for the parameter name and check
8074 // whether it's already in the current scope.
8075 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, name);
8077 if (pm_locals_find(&parser->current_scope->locals, constant_id) != UINT32_MAX) {
8078 // Add an error if the parameter doesn't start with _ and has been seen before
8079 if ((name->start < name->end) && (*name->start != '_')) {
8080 pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NAME_DUPLICATED);
8091pm_parser_scope_pop(pm_parser_t *parser) {
8092 pm_scope_t *scope = parser->current_scope;
8093 parser->current_scope = scope->previous;
8094 pm_locals_free(&scope->locals);
8095 pm_node_list_free(&scope->implicit_parameters);
8099/******************************************************************************/
8101/******************************************************************************/
8107pm_state_stack_push(pm_state_stack_t *stack, bool value) {
8108 *stack = (*stack << 1) | (value & 1);
8115pm_state_stack_pop(pm_state_stack_t *stack) {
8123pm_state_stack_p(const pm_state_stack_t *stack) {
8128pm_accepts_block_stack_push(pm_parser_t *parser, bool value) {
8129 // Use the negation of the value to prevent stack overflow.
8130 pm_state_stack_push(&parser->accepts_block_stack, !value);
8134pm_accepts_block_stack_pop(pm_parser_t *parser) {
8135 pm_state_stack_pop(&parser->accepts_block_stack);
8139pm_accepts_block_stack_p(pm_parser_t *parser) {
8140 return !pm_state_stack_p(&parser->accepts_block_stack);
8144pm_do_loop_stack_push(pm_parser_t *parser, bool value) {
8145 pm_state_stack_push(&parser->do_loop_stack, value);
8149pm_do_loop_stack_pop(pm_parser_t *parser) {
8150 pm_state_stack_pop(&parser->do_loop_stack);
8154pm_do_loop_stack_p(pm_parser_t *parser) {
8155 return pm_state_stack_p(&parser->do_loop_stack);
8158/******************************************************************************/
8159/* Lexer check helpers */
8160/******************************************************************************/
8166static inline uint8_t
8167peek_at(const pm_parser_t *parser, const uint8_t *cursor) {
8168 if (cursor < parser->end) {
8180static inline uint8_t
8181peek_offset(pm_parser_t *parser, ptrdiff_t offset) {
8182 return peek_at(parser, parser->current.end + offset);
8189static inline uint8_t
8190peek(const pm_parser_t *parser) {
8191 return peek_at(parser, parser->current.end);
8199match(pm_parser_t *parser, uint8_t value) {
8200 if (peek(parser) == value) {
8201 parser->current.end++;
8212match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
8213 if (peek_at(parser, cursor) == '\n') {
8216 if (peek_at(parser, cursor) == '\r' && peek_at(parser, cursor + 1) == '\n') {
8228match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
8229 return match_eol_at(parser, parser->current.end + offset);
8238match_eol(pm_parser_t *parser) {
8239 return match_eol_at(parser, parser->current.end);
8245static inline const uint8_t *
8246next_newline(const uint8_t *cursor, ptrdiff_t length) {
8247 assert(length >= 0);
8249 // Note that it's okay for us to use memchr here to look for \n because none
8250 // of the encodings that we support have \n as a component of a multi-byte
8252 return memchr(cursor, '\n', (size_t) length);
8259ambiguous_operator_p(const pm_parser_t *parser, bool space_seen) {
8260 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));
8268parser_lex_magic_comment_encoding_value(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
8269 const pm_encoding_t *encoding = pm_encoding_find(start, end);
8271 if (encoding != NULL) {
8272 if (parser->encoding != encoding) {
8273 parser->encoding = encoding;
8274 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
8277 parser->encoding_changed = (encoding != PM_ENCODING_UTF_8_ENTRY);
8289parser_lex_magic_comment_encoding(pm_parser_t *parser) {
8290 const uint8_t *cursor = parser->current.start + 1;
8291 const uint8_t *end = parser->current.end;
8293 bool separator = false;
8295 if (end - cursor <= 6) return;
8296 switch (cursor[6]) {
8297 case 'C': case 'c': cursor += 6; continue;
8298 case 'O': case 'o': cursor += 5; continue;
8299 case 'D': case 'd': cursor += 4; continue;
8300 case 'I': case 'i': cursor += 3; continue;
8301 case 'N': case 'n': cursor += 2; continue;
8302 case 'G': case 'g': cursor += 1; continue;
8309 if (pm_char_is_whitespace(*cursor)) break;
8312 if (pm_strncasecmp(cursor - 6, (const uint8_t *) "coding", 6) == 0) break;
8318 if (++cursor >= end) return;
8319 } while (pm_char_is_whitespace(*cursor));
8321 if (separator) break;
8322 if (*cursor != '=' && *cursor != ':') return;
8328 const uint8_t *value_start = cursor;
8329 while ((*cursor == '-' || *cursor == '_' || parser->encoding->alnum_char(cursor, 1)) && ++cursor < end);
8331 if (!parser_lex_magic_comment_encoding_value(parser, value_start, cursor)) {
8332 // If we were unable to parse the encoding value, then we've got an
8333 // issue because we didn't understand the encoding that the user was
8334 // trying to use. In this case we'll keep using the default encoding but
8335 // add an error to the parser to indicate an unsuccessful parse.
8336 pm_parser_err(parser, value_start, cursor, PM_ERR_INVALID_ENCODING_MAGIC_COMMENT);
8341 PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE,
8342 PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE,
8343 PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID
8344} pm_magic_comment_boolean_value_t;
8350static pm_magic_comment_boolean_value_t
8351parser_lex_magic_comment_boolean_value(const uint8_t *value_start, uint32_t value_length) {
8352 if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "true", 4) == 0) {
8353 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE;
8354 } else if (value_length == 5 && pm_strncasecmp(value_start, (const uint8_t *) "false", 5) == 0) {
8355 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE;
8357 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID;
8362pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
8363 return b == '\'' || b == '"' || b == ':' || b == ';';
8371static inline const uint8_t *
8372parser_lex_magic_comment_emacs_marker(
pm_parser_t *parser,
const uint8_t *cursor,
const uint8_t *end) {
8373 while ((cursor + 3 <= end) && (cursor = pm_memchr(cursor,
'-', (
size_t) (end - cursor), parser->
encoding_changed, parser->
encoding)) != NULL) {
8374 if (cursor + 3 <= end && cursor[1] ==
'*' && cursor[2] ==
'-') {
8393parser_lex_magic_comment(
pm_parser_t *parser,
bool semantic_token_seen) {
8396 const uint8_t *start = parser->
current.start + 1;
8397 const uint8_t *end = parser->
current.end;
8398 if (end - start <= 7)
return false;
8400 const uint8_t *cursor;
8401 bool indicator =
false;
8403 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
8406 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
8417 while (cursor < end) {
8418 while (cursor < end && (pm_char_is_magic_comment_key_delimiter(*cursor) || pm_char_is_whitespace(*cursor))) cursor++;
8420 const uint8_t *key_start = cursor;
8421 while (cursor < end && (!pm_char_is_magic_comment_key_delimiter(*cursor) && !pm_char_is_whitespace(*cursor))) cursor++;
8423 const uint8_t *key_end = cursor;
8424 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
8425 if (cursor == end)
break;
8427 if (*cursor ==
':') {
8430 if (!indicator)
return false;
8434 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
8435 if (cursor == end)
break;
8437 const uint8_t *value_start;
8438 const uint8_t *value_end;
8440 if (*cursor ==
'"') {
8441 value_start = ++cursor;
8442 for (; cursor < end && *cursor !=
'"'; cursor++) {
8443 if (*cursor ==
'\\' && (cursor + 1 < end)) cursor++;
8446 if (*cursor ==
'"') cursor++;
8448 value_start = cursor;
8449 while (cursor < end && *cursor !=
'"' && *cursor !=
';' && !pm_char_is_whitespace(*cursor)) cursor++;
8454 while (cursor < end && (*cursor ==
';' || pm_char_is_whitespace(*cursor))) cursor++;
8456 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
8457 if (cursor != end)
return false;
8463 const size_t key_length = (size_t) (key_end - key_start);
8467 pm_string_shared_init(&key, key_start, key_end);
8469 uint8_t *buffer =
xmalloc(key_length);
8470 if (buffer == NULL)
break;
8472 memcpy(buffer, key_start, key_length);
8473 buffer[dash - key_start] =
'_';
8475 while ((dash = pm_memchr(dash + 1,
'-', (
size_t) (key_end - dash - 1), parser->
encoding_changed, parser->
encoding)) != NULL) {
8476 buffer[dash - key_start] =
'_';
8479 pm_string_owned_init(&key, buffer, key_length);
8485 uint32_t value_length = (uint32_t) (value_end - value_start);
8491 (key_length == 8 && pm_strncasecmp(key_source, (
const uint8_t *)
"encoding", 8) == 0) ||
8492 (key_length == 6 && pm_strncasecmp(key_source, (
const uint8_t *)
"coding", 6) == 0)
8494 result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
8498 if (key_length == 11) {
8499 if (pm_strncasecmp(key_source, (
const uint8_t *)
"warn_indent", 11) == 0) {
8500 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
8501 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
8502 PM_PARSER_WARN_TOKEN_FORMAT(
8505 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8507 (
const char *) key_source,
8509 (
const char *) value_start
8512 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
8515 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
8520 }
else if (key_length == 21) {
8521 if (pm_strncasecmp(key_source, (
const uint8_t *)
"frozen_string_literal", 21) == 0) {
8524 if (semantic_token_seen) {
8525 pm_parser_warn_token(parser, &parser->
current, PM_WARN_IGNORED_FROZEN_STRING_LITERAL);
8527 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
8528 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
8529 PM_PARSER_WARN_TOKEN_FORMAT(
8532 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8534 (
const char *) key_source,
8536 (
const char *) value_start
8539 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
8542 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
8548 }
else if (key_length == 24) {
8549 if (pm_strncasecmp(key_source, (
const uint8_t *)
"shareable_constant_value", 24) == 0) {
8550 const uint8_t *cursor = parser->
current.start;
8551 while ((cursor > parser->
start) && ((cursor[-1] ==
' ') || (cursor[-1] ==
'\t'))) cursor--;
8553 if (!((cursor == parser->
start) || (cursor[-1] ==
'\n'))) {
8554 pm_parser_warn_token(parser, &parser->
current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
8555 }
else if (value_length == 4 && pm_strncasecmp(value_start, (
const uint8_t *)
"none", 4) == 0) {
8556 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
8557 }
else if (value_length == 7 && pm_strncasecmp(value_start, (
const uint8_t *)
"literal", 7) == 0) {
8558 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
8559 }
else if (value_length == 23 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_everything", 23) == 0) {
8560 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING);
8561 }
else if (value_length == 17 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_copy", 17) == 0) {
8562 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY);
8564 PM_PARSER_WARN_TOKEN_FORMAT(
8567 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8569 (
const char *) key_source,
8571 (
const char *) value_start
8599static const uint32_t context_terminators[] = {
8601 [
PM_CONTEXT_BEGIN] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
8604 [
PM_CONTEXT_BEGIN_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
8606 [
PM_CONTEXT_BLOCK_KEYWORDS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
8609 [
PM_CONTEXT_BLOCK_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
8610 [
PM_CONTEXT_CASE_WHEN] = (1U << PM_TOKEN_KEYWORD_WHEN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
8611 [
PM_CONTEXT_CASE_IN] = (1U << PM_TOKEN_KEYWORD_IN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
8612 [
PM_CONTEXT_CLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
8615 [
PM_CONTEXT_CLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
8616 [
PM_CONTEXT_DEF] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
8619 [
PM_CONTEXT_DEF_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
8624 [
PM_CONTEXT_ELSIF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
8628 [
PM_CONTEXT_IF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
8630 [
PM_CONTEXT_LAMBDA_DO_END] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
8633 [
PM_CONTEXT_LAMBDA_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
8636 [
PM_CONTEXT_MODULE] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
8639 [
PM_CONTEXT_MODULE_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
8643 [
PM_CONTEXT_PREDICATE] = (1U << PM_TOKEN_KEYWORD_THEN) | (1U << PM_TOKEN_NEWLINE) | (1U << PM_TOKEN_SEMICOLON),
8646 [
PM_CONTEXT_SCLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
8649 [
PM_CONTEXT_SCLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
8651 [
PM_CONTEXT_UNLESS] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
8658 return token->type < 32 && (context_terminators[context] & (1U << token->type));
8669 while (context_node != NULL) {
8670 if (context_terminator(context_node->
context, token))
return context_node->
context;
8671 context_node = context_node->
prev;
8680 if (context_node == NULL)
return false;
8705 while (context_node != NULL) {
8706 if (context_node->
context == context)
return true;
8707 context_node = context_node->
prev;
8717 while (context_node != NULL) {
8718 switch (context_node->
context) {
8739 context_node = context_node->
prev;
8754 assert(
false &&
"unreachable");
8811 assert(
false &&
"unreachable");
8820pm_strspn_number_validate(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const uint8_t *invalid) {
8821 if (invalid != NULL) {
8822 pm_diagnostic_id_t diag_id = (invalid == (
string + length - 1)) ? PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING : PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER;
8823 pm_parser_err(parser, invalid, invalid + 1, diag_id);
8828pm_strspn_binary_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8829 const uint8_t *invalid = NULL;
8830 size_t length = pm_strspn_binary_number(
string, parser->
end -
string, &invalid);
8831 pm_strspn_number_validate(parser,
string, length, invalid);
8836pm_strspn_octal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8837 const uint8_t *invalid = NULL;
8838 size_t length = pm_strspn_octal_number(
string, parser->
end -
string, &invalid);
8839 pm_strspn_number_validate(parser,
string, length, invalid);
8844pm_strspn_decimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8845 const uint8_t *invalid = NULL;
8846 size_t length = pm_strspn_decimal_number(
string, parser->
end -
string, &invalid);
8847 pm_strspn_number_validate(parser,
string, length, invalid);
8852pm_strspn_hexadecimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8853 const uint8_t *invalid = NULL;
8854 size_t length = pm_strspn_hexadecimal_number(
string, parser->
end -
string, &invalid);
8855 pm_strspn_number_validate(parser,
string, length, invalid);
8859static pm_token_type_t
8860lex_optional_float_suffix(
pm_parser_t *parser,
bool* seen_e) {
8861 pm_token_type_t
type = PM_TOKEN_INTEGER;
8865 if (peek(parser) ==
'.') {
8866 if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8868 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8869 type = PM_TOKEN_FLOAT;
8879 if ((peek(parser) ==
'e') || (peek(parser) ==
'E')) {
8880 if ((peek_offset(parser, 1) ==
'+') || (peek_offset(parser, 1) ==
'-')) {
8883 if (pm_char_is_decimal_digit(peek(parser))) {
8885 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8887 pm_parser_err_current(parser, PM_ERR_INVALID_FLOAT_EXPONENT);
8889 }
else if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8891 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8897 type = PM_TOKEN_FLOAT;
8903static pm_token_type_t
8904lex_numeric_prefix(
pm_parser_t *parser,
bool* seen_e) {
8905 pm_token_type_t
type = PM_TOKEN_INTEGER;
8908 if (peek_offset(parser, -1) ==
'0') {
8909 switch (*parser->
current.end) {
8914 if (pm_char_is_decimal_digit(peek(parser))) {
8915 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8918 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_DECIMAL);
8927 if (pm_char_is_binary_digit(peek(parser))) {
8928 parser->
current.end += pm_strspn_binary_number_validate(parser, parser->
current.end);
8931 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
8941 if (pm_char_is_octal_digit(peek(parser))) {
8942 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8945 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
8961 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8969 if (pm_char_is_hexadecimal_digit(peek(parser))) {
8970 parser->
current.end += pm_strspn_hexadecimal_number_validate(parser, parser->
current.end);
8973 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
8976 parser->
integer_base = PM_INTEGER_BASE_FLAGS_HEXADECIMAL;
8981 type = lex_optional_float_suffix(parser, seen_e);
8988 type = lex_optional_float_suffix(parser, seen_e);
8995 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8998 type = lex_optional_float_suffix(parser, seen_e);
9004 if (peek_offset(parser, 0) ==
'.' && pm_char_is_decimal_digit(peek_offset(parser, 1))) {
9005 const uint8_t *fraction_start = parser->
current.end;
9006 const uint8_t *fraction_end = parser->
current.end + 2;
9007 fraction_end += pm_strspn_decimal_digit(fraction_end, parser->
end - fraction_end);
9008 pm_parser_err(parser, fraction_start, fraction_end, PM_ERR_INVALID_NUMBER_FRACTION);
9014static pm_token_type_t
9016 pm_token_type_t
type = PM_TOKEN_INTEGER;
9020 bool seen_e =
false;
9021 type = lex_numeric_prefix(parser, &seen_e);
9023 const uint8_t *end = parser->
current.end;
9024 pm_token_type_t suffix_type =
type;
9026 if (
type == PM_TOKEN_INTEGER) {
9027 if (match(parser,
'r')) {
9028 suffix_type = PM_TOKEN_INTEGER_RATIONAL;
9030 if (match(parser,
'i')) {
9031 suffix_type = PM_TOKEN_INTEGER_RATIONAL_IMAGINARY;
9033 }
else if (match(parser,
'i')) {
9034 suffix_type = PM_TOKEN_INTEGER_IMAGINARY;
9037 if (!seen_e && match(parser,
'r')) {
9038 suffix_type = PM_TOKEN_FLOAT_RATIONAL;
9040 if (match(parser,
'i')) {
9041 suffix_type = PM_TOKEN_FLOAT_RATIONAL_IMAGINARY;
9043 }
else if (match(parser,
'i')) {
9044 suffix_type = PM_TOKEN_FLOAT_IMAGINARY;
9048 const uint8_t b = peek(parser);
9049 if (b !=
'\0' && (b >= 0x80 || ((b >=
'a' && b <=
'z') || (b >=
'A' && b <=
'Z')) || b ==
'_')) {
9059static pm_token_type_t
9062 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
9063 return PM_TOKEN_GLOBAL_VARIABLE;
9068 bool allow_multiple =
true;
9070 switch (*parser->
current.end) {
9088 return PM_TOKEN_GLOBAL_VARIABLE;
9095 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_BACK_REFERENCE;
9101 if ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0) {
9104 }
while ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0);
9108 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
current, diag_id);
9111 return PM_TOKEN_GLOBAL_VARIABLE;
9124 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_NUMBERED_REFERENCE;
9128 allow_multiple =
false;
9133 if ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0) {
9136 }
while (allow_multiple && (width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0);
9137 }
else if (pm_char_is_whitespace(peek(parser))) {
9140 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
9146 PM_PARSER_ERR_FORMAT(parser, parser->
current.start, end, diag_id, (
int) (end - parser->
current.start), (
const char *) parser->
current.start);
9149 return PM_TOKEN_GLOBAL_VARIABLE;
9166static inline pm_token_type_t
9167lex_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) {
9168 if (memcmp(current_start, value, vlen) == 0) {
9171 if (parser->
lex_state & PM_LEX_STATE_FNAME) {
9172 lex_state_set(parser, PM_LEX_STATE_ENDFN);
9174 lex_state_set(parser, state);
9175 if (state == PM_LEX_STATE_BEG) {
9179 if ((modifier_type != PM_TOKEN_EOF) && !(last_state & (PM_LEX_STATE_BEG | PM_LEX_STATE_LABELED | PM_LEX_STATE_CLASS))) {
9180 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
9181 return modifier_type;
9188 return PM_TOKEN_EOF;
9191static pm_token_type_t
9192lex_identifier(
pm_parser_t *parser,
bool previous_command_start) {
9195 const uint8_t *end = parser->
end;
9196 const uint8_t *current_start = parser->
current.start;
9197 const uint8_t *current_end = parser->
current.end;
9200 if (encoding_changed) {
9201 while ((width = char_is_identifier(parser, current_end, end - current_end)) > 0) {
9202 current_end += width;
9205 while ((width = char_is_identifier_utf8(current_end, end - current_end)) > 0) {
9206 current_end += width;
9209 parser->
current.end = current_end;
9213 width = (size_t) (current_end - current_start);
9215 if (current_end < end) {
9216 if (((current_end + 1 >= end) || (current_end[1] !=
'=')) && (match(parser,
'!') || match(parser,
'?'))) {
9222 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
9223 (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')
9227 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
9228 (void) match(parser,
':');
9229 return PM_TOKEN_LABEL;
9232 if (parser->
lex_state != PM_LEX_STATE_DOT) {
9233 if (width == 8 && (lex_keyword(parser, current_start,
"defined?", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_DEFINED, PM_TOKEN_EOF) != PM_TOKEN_EOF)) {
9234 return PM_TOKEN_KEYWORD_DEFINED;
9238 return PM_TOKEN_METHOD_NAME;
9241 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,
'=')) {
9244 return PM_TOKEN_IDENTIFIER;
9248 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
9249 peek(parser) ==
':' && peek_offset(parser, 1) !=
':'
9253 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
9254 (void) match(parser,
':');
9255 return PM_TOKEN_LABEL;
9259 if (parser->
lex_state != PM_LEX_STATE_DOT) {
9260 pm_token_type_t
type;
9263 if (lex_keyword(parser, current_start,
"do", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_DO, PM_TOKEN_EOF) != PM_TOKEN_EOF) {
9264 if (pm_do_loop_stack_p(parser)) {
9265 return PM_TOKEN_KEYWORD_DO_LOOP;
9267 return PM_TOKEN_KEYWORD_DO;
9270 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;
9271 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;
9272 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;
9275 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;
9276 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;
9277 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;
9278 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;
9279 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;
9280 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;
9281 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;
9284 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;
9285 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;
9286 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;
9287 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;
9288 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;
9289 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;
9290 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;
9291 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;
9294 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;
9295 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;
9296 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;
9297 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;
9298 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;
9299 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;
9300 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;
9301 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;
9302 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;
9303 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;
9304 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;
9305 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;
9306 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;
9309 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;
9310 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;
9311 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;
9312 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;
9313 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;
9316 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;
9317 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;
9320 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;
9325 if (encoding_changed) {
9326 return parser->
encoding->
isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
9328 return pm_encoding_utf_8_isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
9354static pm_token_type_t
9355lex_interpolation(
pm_parser_t *parser,
const uint8_t *pound) {
9358 if (pound + 1 >= parser->
end) {
9359 parser->
current.end = pound + 1;
9360 return PM_TOKEN_STRING_CONTENT;
9369 if (pound + 2 >= parser->
end) {
9370 parser->
current.end = pound + 1;
9371 return PM_TOKEN_STRING_CONTENT;
9376 const uint8_t *variable = pound + 2;
9377 if (*variable ==
'@' && pound + 3 < parser->
end) variable++;
9379 if (char_is_identifier_start(parser, variable, parser->
end - variable)) {
9383 if (pound > parser->
current.start) {
9385 return PM_TOKEN_STRING_CONTENT;
9390 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
9391 parser->
current.end = pound + 1;
9392 return PM_TOKEN_EMBVAR;
9398 parser->
current.end = pound + 1;
9399 return PM_TOKEN_NOT_PROVIDED;
9404 if (pound + 2 >= parser->
end) {
9405 parser->
current.end = pound + 1;
9406 return PM_TOKEN_STRING_CONTENT;
9412 const uint8_t *check = pound + 2;
9414 if (pound[2] ==
'-') {
9415 if (pound + 3 >= parser->
end) {
9416 parser->
current.end = pound + 2;
9417 return PM_TOKEN_STRING_CONTENT;
9428 char_is_identifier_start(parser, check, parser->
end - check) ||
9429 (pound[2] !=
'-' && (pm_char_is_decimal_digit(pound[2]) || char_is_global_name_punctuation(pound[2])))
9434 if (pound > parser->
current.start) {
9436 return PM_TOKEN_STRING_CONTENT;
9441 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
9442 parser->
current.end = pound + 1;
9443 return PM_TOKEN_EMBVAR;
9448 parser->
current.end = pound + 1;
9449 return PM_TOKEN_NOT_PROVIDED;
9454 if (pound > parser->
current.start) {
9456 return PM_TOKEN_STRING_CONTENT;
9463 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBEXPR });
9464 parser->
current.end = pound + 2;
9466 pm_do_loop_stack_push(parser,
false);
9467 return PM_TOKEN_EMBEXPR_BEGIN;
9472 parser->
current.end = pound + 1;
9473 return PM_TOKEN_NOT_PROVIDED;
9477static const uint8_t PM_ESCAPE_FLAG_NONE = 0x0;
9478static const uint8_t PM_ESCAPE_FLAG_CONTROL = 0x1;
9479static const uint8_t PM_ESCAPE_FLAG_META = 0x2;
9480static const uint8_t PM_ESCAPE_FLAG_SINGLE = 0x4;
9481static const uint8_t PM_ESCAPE_FLAG_REGEXP = 0x8;
9486static const bool ascii_printable_chars[] = {
9487 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
9488 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9489 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9490 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9491 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9492 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
9493 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9494 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
9498char_is_ascii_printable(
const uint8_t b) {
9499 return (b < 0x80) && ascii_printable_chars[b];
9506static inline uint8_t
9507escape_hexadecimal_digit(
const uint8_t value) {
9508 return (uint8_t) ((value <=
'9') ? (value -
'0') : (value & 0x7) + 9);
9516static inline uint32_t
9517escape_unicode(
pm_parser_t *parser,
const uint8_t *
string,
size_t length) {
9519 for (
size_t index = 0; index < length; index++) {
9520 if (index != 0) value <<= 4;
9521 value |= escape_hexadecimal_digit(
string[index]);
9526 if (value >= 0xD800 && value <= 0xDFFF) {
9527 pm_parser_err(parser,
string,
string + length, PM_ERR_ESCAPE_INVALID_UNICODE);
9537static inline uint8_t
9538escape_byte(uint8_t value,
const uint8_t flags) {
9539 if (flags & PM_ESCAPE_FLAG_CONTROL) value &= 0x9f;
9540 if (flags & PM_ESCAPE_FLAG_META) value |= 0x80;
9548escape_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) {
9552 if (value >= 0x80 || flags & PM_ESCAPE_FLAG_SINGLE) {
9560 if (!pm_buffer_append_unicode_codepoint(buffer, value)) {
9561 pm_parser_err(parser, start, end, PM_ERR_ESCAPE_INVALID_UNICODE);
9562 pm_buffer_append_byte(buffer, 0xEF);
9563 pm_buffer_append_byte(buffer, 0xBF);
9564 pm_buffer_append_byte(buffer, 0xBD);
9576 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_MIXED_ENCODING, parser->
encoding->
name);
9582 pm_buffer_append_byte(buffer,
byte);
9602 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9603 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X",
byte);
9606 escape_write_byte_encoded(parser, buffer,
byte);
9618 width = pm_encoding_utf_8_char_width(parser->
current.end, parser->
end - parser->
current.end);
9622 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(*parser->
current.end++, flags));
9623 }
else if (width > 1) {
9625 pm_buffer_t *b = (flags & PM_ESCAPE_FLAG_REGEXP) ? regular_expression_buffer : buffer;
9626 pm_buffer_append_bytes(b, parser->
current.end, width);
9632 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9642escape_read_warn(
pm_parser_t *parser, uint8_t flags, uint8_t flag,
const char *
type) {
9643#define FLAG(value) ((value & PM_ESCAPE_FLAG_CONTROL) ? "\\C-" : (value & PM_ESCAPE_FLAG_META) ? "\\M-" : "")
9645 PM_PARSER_WARN_TOKEN_FORMAT(
9648 PM_WARN_INVALID_CHARACTER,
9662 uint8_t peeked = peek(parser);
9666 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\\', flags));
9671 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\'', flags));
9676 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\a', flags));
9681 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\b', flags));
9686 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\033', flags));
9691 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\f', flags));
9696 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\n', flags));
9701 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\r', flags));
9706 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
' ', flags));
9711 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\t', flags));
9716 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\v', flags));
9719 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': {
9720 uint8_t value = (uint8_t) (*parser->
current.end -
'0');
9723 if (pm_char_is_octal_digit(peek(parser))) {
9724 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
9727 if (pm_char_is_octal_digit(peek(parser))) {
9728 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
9733 value = escape_byte(value, flags);
9734 escape_write_byte(parser, buffer, regular_expression_buffer, flags, value);
9738 const uint8_t *start = parser->
current.end - 1;
9741 uint8_t
byte = peek(parser);
9743 if (pm_char_is_hexadecimal_digit(
byte)) {
9744 uint8_t value = escape_hexadecimal_digit(
byte);
9747 byte = peek(parser);
9748 if (pm_char_is_hexadecimal_digit(
byte)) {
9749 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(
byte));
9753 value = escape_byte(value, flags);
9754 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9755 if (flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) {
9756 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X", value);
9758 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9762 escape_write_byte_encoded(parser, buffer, value);
9764 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
9770 const uint8_t *start = parser->
current.end - 1;
9774 const uint8_t *start = parser->
current.end - 2;
9775 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9776 }
else if (peek(parser) ==
'{') {
9777 const uint8_t *unicode_codepoints_start = parser->
current.end - 2;
9782 if ((whitespace = pm_strspn_inline_whitespace(parser->
current.end, parser->
end - parser->
current.end)) > 0) {
9783 parser->
current.end += whitespace;
9784 }
else if (peek(parser) ==
'\\' && peek_offset(parser, 1) ==
'n') {
9795 const uint8_t *extra_codepoints_start = NULL;
9796 int codepoints_count = 0;
9799 const uint8_t *unicode_start = parser->
current.end;
9800 size_t hexadecimal_length = pm_strspn_hexadecimal_digit(parser->
current.end, parser->
end - parser->
current.end);
9802 if (hexadecimal_length > 6) {
9804 pm_parser_err(parser, unicode_start, unicode_start + hexadecimal_length, PM_ERR_ESCAPE_INVALID_UNICODE_LONG);
9805 }
else if (hexadecimal_length == 0) {
9808 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9812 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9814 pm_parser_err(parser, parser->
current.end, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE);
9815 pm_parser_err(parser, parser->
current.end, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9821 parser->
current.end += hexadecimal_length;
9823 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count == 2) {
9824 extra_codepoints_start = unicode_start;
9827 uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length);
9828 escape_write_unicode(parser, buffer, flags, unicode_start, parser->
current.end, value);
9835 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count > 1) {
9836 pm_parser_err(parser, extra_codepoints_start, parser->
current.end - 1, PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL);
9840 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_LIST, (
int) (parser->
current.end - start), start);
9841 }
else if (peek(parser) ==
'}') {
9844 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9848 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9850 pm_parser_err(parser, unicode_codepoints_start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9854 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9855 pm_buffer_append_bytes(regular_expression_buffer, unicode_codepoints_start, (
size_t) (parser->
current.end - unicode_codepoints_start));
9858 size_t length = pm_strspn_hexadecimal_digit(parser->
current.end, MIN(parser->
end - parser->
current.end, 4));
9861 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9862 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9864 const uint8_t *start = parser->
current.end - 2;
9865 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9867 }
else if (length == 4) {
9868 uint32_t value = escape_unicode(parser, parser->
current.end, 4);
9870 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9871 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end + 4 - start));
9874 escape_write_unicode(parser, buffer, flags, start, parser->
current.end + 4, value);
9877 parser->
current.end += length;
9879 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9883 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9885 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_UNICODE);
9894 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9895 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9899 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9903 uint8_t peeked = peek(parser);
9907 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9913 if (match(parser,
'u') || match(parser,
'U')) {
9914 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9918 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9922 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9923 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9927 escape_read_warn(parser, flags, 0,
"\\t");
9928 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9931 if (!char_is_ascii_printable(peeked)) {
9932 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9937 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9944 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9945 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9948 if (peek(parser) !=
'-') {
9950 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9956 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9960 uint8_t peeked = peek(parser);
9964 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9970 if (match(parser,
'u') || match(parser,
'U')) {
9971 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9975 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9979 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9980 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9984 escape_read_warn(parser, flags, 0,
"\\t");
9985 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9988 if (!char_is_ascii_printable(peeked)) {
9990 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9995 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
10002 if (flags & PM_ESCAPE_FLAG_META) {
10003 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META_REPEAT);
10006 if (peek(parser) !=
'-') {
10008 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
10014 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
10018 uint8_t peeked = peek(parser);
10023 if (match(parser,
'u') || match(parser,
'U')) {
10024 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
10028 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_META);
10032 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_META,
"\\s");
10033 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10037 escape_read_warn(parser, flags & ((uint8_t) ~PM_ESCAPE_FLAG_CONTROL), PM_ESCAPE_FLAG_META,
"\\t");
10038 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10041 if (!char_is_ascii_printable(peeked)) {
10043 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
10048 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10053 if (peek_offset(parser, 1) ==
'\n') {
10055 escape_write_byte_encoded(parser, buffer, escape_byte(
'\n', flags));
10061 if ((flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) && !char_is_ascii_printable(peeked)) {
10063 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
10067 escape_write_escape_encoded(parser, buffer, regular_expression_buffer, flags);
10069 pm_parser_err_current(parser, PM_ERR_INVALID_ESCAPE_CHARACTER);
10101static pm_token_type_t
10103 if (lex_state_end_p(parser)) {
10104 lex_state_set(parser, PM_LEX_STATE_BEG);
10105 return PM_TOKEN_QUESTION_MARK;
10109 pm_parser_err_current(parser, PM_ERR_INCOMPLETE_QUESTION_MARK);
10111 return PM_TOKEN_CHARACTER_LITERAL;
10114 if (pm_char_is_whitespace(*parser->
current.end)) {
10115 lex_state_set(parser, PM_LEX_STATE_BEG);
10116 return PM_TOKEN_QUESTION_MARK;
10119 lex_state_set(parser, PM_LEX_STATE_BEG);
10121 if (match(parser,
'\\')) {
10122 lex_state_set(parser, PM_LEX_STATE_END);
10125 pm_buffer_init_capacity(&buffer, 3);
10127 escape_read(parser, &buffer, NULL, PM_ESCAPE_FLAG_SINGLE);
10130 return PM_TOKEN_CHARACTER_LITERAL;
10139 (parser->
current.end + encoding_width >= parser->
end) ||
10140 !char_is_identifier(parser, parser->
current.end + encoding_width, parser->
end - (parser->
current.end + encoding_width))
10143 lex_state_set(parser, PM_LEX_STATE_END);
10144 parser->
current.end += encoding_width;
10146 return PM_TOKEN_CHARACTER_LITERAL;
10150 return PM_TOKEN_QUESTION_MARK;
10157static pm_token_type_t
10159 pm_token_type_t
type = match(parser,
'@') ? PM_TOKEN_CLASS_VARIABLE : PM_TOKEN_INSTANCE_VARIABLE;
10160 const uint8_t *end = parser->
end;
10163 if ((width = char_is_identifier_start(parser, parser->
current.end, end - parser->
current.end)) > 0) {
10164 parser->
current.end += width;
10166 while ((width = char_is_identifier(parser, parser->
current.end, end - parser->
current.end)) > 0) {
10167 parser->
current.end += width;
10169 }
else if (parser->
current.end < end && pm_char_is_decimal_digit(*parser->
current.end)) {
10170 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE;
10172 diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS_3_3 : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE_3_3;
10176 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, diag_id, (
int) ((parser->
current.end + width) - parser->
current.start), (
const char *) parser->
current.start);
10178 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_CLASS_VARIABLE_BARE : PM_ERR_INSTANCE_VARIABLE_BARE;
10179 pm_parser_err_token(parser, &parser->
current, diag_id);
10185 lex_mode_pop(parser);
10207 if (comment == NULL)
return NULL;
10222static pm_token_type_t
10225 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10227 if (newline == NULL) {
10230 pm_newline_list_append(&parser->
newline_list, newline);
10231 parser->
current.end = newline + 1;
10234 parser->
current.type = PM_TOKEN_EMBDOC_BEGIN;
10235 parser_lex_callback(parser);
10238 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_EMBDOC);
10239 if (comment == NULL)
return PM_TOKEN_EOF;
10243 while (parser->
current.end + 4 <= parser->
end) {
10249 (memcmp(parser->
current.end,
"=end", 4) == 0) &&
10252 pm_char_is_whitespace(parser->
current.end[4]) ||
10253 (parser->
current.end[4] ==
'\0') ||
10254 (parser->
current.end[4] ==
'\004') ||
10255 (parser->
current.end[4] ==
'\032')
10258 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10260 if (newline == NULL) {
10263 pm_newline_list_append(&parser->
newline_list, newline);
10264 parser->
current.end = newline + 1;
10267 parser->
current.type = PM_TOKEN_EMBDOC_END;
10268 parser_lex_callback(parser);
10273 return PM_TOKEN_EMBDOC_END;
10278 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10280 if (newline == NULL) {
10283 pm_newline_list_append(&parser->
newline_list, newline);
10284 parser->
current.end = newline + 1;
10287 parser->
current.type = PM_TOKEN_EMBDOC_LINE;
10288 parser_lex_callback(parser);
10291 pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
10296 return PM_TOKEN_EOF;
10306 parser->
current.type = PM_TOKEN_IGNORED_NEWLINE;
10307 parser_lex_callback(parser);
10331 const uint8_t *cursor = parser->
current.end;
10333 while (cursor < parser->end && *cursor !=
'\n' && *cursor !=
'#') {
10334 if (!pm_char_is_inline_whitespace(*cursor++))
return false;
10397 pm_buffer_append_byte(&token_buffer->
buffer,
byte);
10408static inline size_t
10414 width = pm_encoding_utf_8_char_width(parser->
current.end, parser->
end - parser->
current.end);
10419 return (width == 0 ? 1 : width);
10427 size_t width = parser_char_width(parser);
10428 pm_buffer_append_bytes(&token_buffer->
buffer, parser->
current.end, width);
10429 parser->
current.end += width;
10434 size_t width = parser_char_width(parser);
10435 pm_buffer_append_bytes(&token_buffer->
base.
buffer, parser->
current.end, width);
10437 parser->
current.end += width;
10441pm_slice_ascii_only_p(
const uint8_t *value,
size_t length) {
10442 for (
size_t index = 0; index < length; index++) {
10443 if (value[index] & 0x80)
return false;
10478 if (token_buffer->
cursor == NULL) {
10481 pm_buffer_append_bytes(&token_buffer->
buffer, token_buffer->
cursor, (
size_t) (parser->
current.end - token_buffer->
cursor));
10482 pm_token_buffer_copy(parser, token_buffer);
10494 pm_regexp_token_buffer_copy(parser, token_buffer);
10498#define PM_TOKEN_BUFFER_DEFAULT_SIZE 16
10510 const uint8_t *start;
10511 if (token_buffer->
cursor == NULL) {
10512 pm_buffer_init_capacity(&token_buffer->
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10513 start = parser->
current.start;
10515 start = token_buffer->
cursor;
10518 const uint8_t *end = parser->
current.end - 1;
10519 assert(end >= start);
10520 pm_buffer_append_bytes(&token_buffer->
buffer, start, (
size_t) (end - start));
10522 token_buffer->
cursor = end;
10527 const uint8_t *start;
10529 pm_buffer_init_capacity(&token_buffer->
base.
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10530 pm_buffer_init_capacity(&token_buffer->
regexp_buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10531 start = parser->
current.start;
10536 const uint8_t *end = parser->
current.end - 1;
10537 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, (
size_t) (end - start));
10538 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, (
size_t) (end - start));
10543#undef PM_TOKEN_BUFFER_DEFAULT_SIZE
10549static inline size_t
10551 size_t whitespace = 0;
10554 case PM_HEREDOC_INDENT_NONE:
10559 case PM_HEREDOC_INDENT_DASH:
10561 *cursor += pm_strspn_inline_whitespace(*cursor, parser->
end - *cursor);
10563 case PM_HEREDOC_INDENT_TILDE:
10566 while (*cursor < parser->end && pm_char_is_inline_whitespace(**cursor)) {
10567 if (**cursor ==
'\t') {
10568 whitespace = (whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
10587 size_t eol_length = match_eol(parser);
10594 parser_flush_heredoc_end(parser);
10600 uint8_t delimiter = *parser->
current.end;
10604 if (eol_length == 2) {
10605 delimiter = *(parser->
current.end + 1);
10608 parser->
current.end += eol_length;
10612 return *parser->
current.end++;
10619#define LEX(token_type) parser->current.type = token_type; parser_lex_callback(parser); return
10638 bool lexed_comment =
false;
10646 case PM_LEX_DEFAULT:
10647 case PM_LEX_EMBEXPR:
10648 case PM_LEX_EMBVAR:
10664 bool space_seen =
false;
10668 bool chomping =
true;
10669 while (parser->
current.end < parser->
end && chomping) {
10670 switch (*parser->
current.end) {
10679 if (match_eol_offset(parser, 1)) {
10682 pm_parser_warn(parser, parser->
current.end, parser->
current.end + 1, PM_WARN_UNEXPECTED_CARRIAGE_RETURN);
10688 size_t eol_length = match_eol_offset(parser, 1);
10694 parser->
current.end += eol_length + 1;
10698 }
else if (pm_char_is_inline_whitespace(*parser->
current.end)) {
10731 switch (*parser->
current.end++) {
10739 const uint8_t *ending = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10740 parser->
current.end = ending == NULL ? parser->
end : ending;
10745 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_INLINE);
10748 if (ending) parser->
current.end++;
10749 parser->
current.type = PM_TOKEN_COMMENT;
10750 parser_lex_callback(parser);
10762 parser_lex_magic_comment_encoding(parser);
10766 lexed_comment =
true;
10772 size_t eol_length = match_eol_at(parser, parser->
current.end - 1);
10784 if (!lexed_comment) {
10785 parser->
current.end += eol_length - 1;
10794 parser_flush_heredoc_end(parser);
10799 switch (lex_state_ignored_p(parser)) {
10800 case PM_IGNORED_NEWLINE_NONE:
10802 case PM_IGNORED_NEWLINE_PATTERN:
10804 if (!lexed_comment) parser_lex_ignored_newline(parser);
10805 lex_state_set(parser, PM_LEX_STATE_BEG);
10807 parser->
current.type = PM_TOKEN_NEWLINE;
10811 case PM_IGNORED_NEWLINE_ALL:
10812 if (!lexed_comment) parser_lex_ignored_newline(parser);
10813 lexed_comment =
false;
10814 goto lex_next_token;
10822 next_content += pm_strspn_inline_whitespace(next_content, parser->
end - next_content);
10824 if (next_content < parser->end) {
10830 if (next_content[0] ==
'#') {
10832 const uint8_t *following = next_newline(next_content, parser->
end - next_content);
10834 while (following && (following + 1 < parser->
end)) {
10836 following += pm_strspn_inline_whitespace(following, parser->
end - following);
10840 if (peek_at(parser, following) !=
'#')
break;
10844 following = next_newline(following, parser->
end - following);
10849 if (lex_state_ignored_p(parser)) {
10850 if (!lexed_comment) parser_lex_ignored_newline(parser);
10851 lexed_comment =
false;
10852 goto lex_next_token;
10858 (peek_at(parser, following) ==
'.') ||
10859 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'.')
10861 if (!lexed_comment) parser_lex_ignored_newline(parser);
10862 lexed_comment =
false;
10863 goto lex_next_token;
10873 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'&') ||
10874 (peek_at(parser, following) ==
'|' && peek_at(parser, following + 1) ==
'|') ||
10875 (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))) ||
10876 (peek_at(parser, following) ==
'o' && peek_at(parser, following + 1) ==
'r' && !char_is_identifier(parser, following + 2, parser->
end - (following + 2)))
10879 if (!lexed_comment) parser_lex_ignored_newline(parser);
10880 lexed_comment =
false;
10881 goto lex_next_token;
10887 if (next_content[0] ==
'.') {
10891 if (peek_at(parser, next_content + 1) ==
'.') {
10892 if (!lexed_comment) parser_lex_ignored_newline(parser);
10893 lex_state_set(parser, PM_LEX_STATE_BEG);
10895 parser->
current.type = PM_TOKEN_NEWLINE;
10899 if (!lexed_comment) parser_lex_ignored_newline(parser);
10900 lex_state_set(parser, PM_LEX_STATE_DOT);
10901 parser->
current.start = next_content;
10902 parser->
current.end = next_content + 1;
10909 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'.') {
10910 if (!lexed_comment) parser_lex_ignored_newline(parser);
10911 lex_state_set(parser, PM_LEX_STATE_DOT);
10912 parser->
current.start = next_content;
10913 parser->
current.end = next_content + 2;
10915 LEX(PM_TOKEN_AMPERSAND_DOT);
10921 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'&') {
10922 if (!lexed_comment) parser_lex_ignored_newline(parser);
10923 lex_state_set(parser, PM_LEX_STATE_BEG);
10924 parser->
current.start = next_content;
10925 parser->
current.end = next_content + 2;
10927 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
10932 if (peek_at(parser, next_content) ==
'|' && peek_at(parser, next_content + 1) ==
'|') {
10933 if (!lexed_comment) parser_lex_ignored_newline(parser);
10934 lex_state_set(parser, PM_LEX_STATE_BEG);
10935 parser->
current.start = next_content;
10936 parser->
current.end = next_content + 2;
10938 LEX(PM_TOKEN_PIPE_PIPE);
10944 peek_at(parser, next_content) ==
'a' &&
10945 peek_at(parser, next_content + 1) ==
'n' &&
10946 peek_at(parser, next_content + 2) ==
'd' &&
10947 !char_is_identifier(parser, next_content + 3, parser->
end - (next_content + 3))
10949 if (!lexed_comment) parser_lex_ignored_newline(parser);
10950 lex_state_set(parser, PM_LEX_STATE_BEG);
10951 parser->
current.start = next_content;
10952 parser->
current.end = next_content + 3;
10955 LEX(PM_TOKEN_KEYWORD_AND);
10961 peek_at(parser, next_content) ==
'o' &&
10962 peek_at(parser, next_content + 1) ==
'r' &&
10963 !char_is_identifier(parser, next_content + 2, parser->
end - (next_content + 2))
10965 if (!lexed_comment) parser_lex_ignored_newline(parser);
10966 lex_state_set(parser, PM_LEX_STATE_BEG);
10967 parser->
current.start = next_content;
10968 parser->
current.end = next_content + 2;
10971 LEX(PM_TOKEN_KEYWORD_OR);
10978 lex_state_set(parser, PM_LEX_STATE_BEG);
10980 parser->
current.type = PM_TOKEN_NEWLINE;
10981 if (!lexed_comment) parser_lex_callback(parser);
10991 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10992 LEX(PM_TOKEN_COMMA);
10996 pm_token_type_t
type = PM_TOKEN_PARENTHESIS_LEFT;
10998 if (space_seen && (lex_state_arg_p(parser) || parser->
lex_state == (PM_LEX_STATE_END | PM_LEX_STATE_LABEL))) {
10999 type = PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES;
11003 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
11004 pm_do_loop_stack_push(parser,
false);
11011 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11012 pm_do_loop_stack_pop(parser);
11013 LEX(PM_TOKEN_PARENTHESIS_RIGHT);
11017 lex_state_set(parser, PM_LEX_STATE_BEG);
11019 LEX(PM_TOKEN_SEMICOLON);
11024 pm_token_type_t
type = PM_TOKEN_BRACKET_LEFT;
11026 if (lex_state_operator_p(parser)) {
11027 if (match(parser,
']')) {
11029 lex_state_set(parser, PM_LEX_STATE_ARG);
11030 LEX(match(parser,
'=') ? PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL : PM_TOKEN_BRACKET_LEFT_RIGHT);
11033 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABEL);
11037 if (lex_state_beg_p(parser) || (lex_state_arg_p(parser) && (space_seen || lex_state_p(parser, PM_LEX_STATE_LABELED)))) {
11038 type = PM_TOKEN_BRACKET_LEFT_ARRAY;
11041 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
11042 pm_do_loop_stack_push(parser,
false);
11048 lex_state_set(parser, PM_LEX_STATE_END);
11049 pm_do_loop_stack_pop(parser);
11050 LEX(PM_TOKEN_BRACKET_RIGHT);
11054 pm_token_type_t
type = PM_TOKEN_BRACE_LEFT;
11059 lex_state_set(parser, PM_LEX_STATE_BEG);
11060 type = PM_TOKEN_LAMBDA_BEGIN;
11061 }
else if (lex_state_p(parser, PM_LEX_STATE_LABELED)) {
11063 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
11064 }
else if (lex_state_p(parser, PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_END | PM_LEX_STATE_ENDFN)) {
11067 lex_state_set(parser, PM_LEX_STATE_BEG);
11068 }
else if (lex_state_p(parser, PM_LEX_STATE_ENDARG)) {
11071 lex_state_set(parser, PM_LEX_STATE_BEG);
11074 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
11079 pm_do_loop_stack_push(parser,
false);
11087 pm_do_loop_stack_pop(parser);
11090 lex_mode_pop(parser);
11091 LEX(PM_TOKEN_EMBEXPR_END);
11095 lex_state_set(parser, PM_LEX_STATE_END);
11096 LEX(PM_TOKEN_BRACE_RIGHT);
11100 if (match(parser,
'*')) {
11101 if (match(parser,
'=')) {
11102 lex_state_set(parser, PM_LEX_STATE_BEG);
11103 LEX(PM_TOKEN_STAR_STAR_EQUAL);
11106 pm_token_type_t
type = PM_TOKEN_STAR_STAR;
11108 if (lex_state_spcarg_p(parser, space_seen)) {
11109 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR_STAR);
11110 type = PM_TOKEN_USTAR_STAR;
11111 }
else if (lex_state_beg_p(parser)) {
11112 type = PM_TOKEN_USTAR_STAR;
11113 }
else if (ambiguous_operator_p(parser, space_seen)) {
11114 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"**",
"argument prefix");
11117 if (lex_state_operator_p(parser)) {
11118 lex_state_set(parser, PM_LEX_STATE_ARG);
11120 lex_state_set(parser, PM_LEX_STATE_BEG);
11126 if (match(parser,
'=')) {
11127 lex_state_set(parser, PM_LEX_STATE_BEG);
11128 LEX(PM_TOKEN_STAR_EQUAL);
11131 pm_token_type_t
type = PM_TOKEN_STAR;
11133 if (lex_state_spcarg_p(parser, space_seen)) {
11134 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR);
11135 type = PM_TOKEN_USTAR;
11136 }
else if (lex_state_beg_p(parser)) {
11137 type = PM_TOKEN_USTAR;
11138 }
else if (ambiguous_operator_p(parser, space_seen)) {
11139 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"*",
"argument prefix");
11142 if (lex_state_operator_p(parser)) {
11143 lex_state_set(parser, PM_LEX_STATE_ARG);
11145 lex_state_set(parser, PM_LEX_STATE_BEG);
11153 if (lex_state_operator_p(parser)) {
11154 lex_state_set(parser, PM_LEX_STATE_ARG);
11155 if (match(parser,
'@')) {
11156 LEX(PM_TOKEN_BANG);
11159 lex_state_set(parser, PM_LEX_STATE_BEG);
11162 if (match(parser,
'=')) {
11163 LEX(PM_TOKEN_BANG_EQUAL);
11166 if (match(parser,
'~')) {
11167 LEX(PM_TOKEN_BANG_TILDE);
11170 LEX(PM_TOKEN_BANG);
11175 current_token_starts_line(parser) &&
11177 memcmp(parser->
current.end,
"begin", 5) == 0 &&
11178 (pm_char_is_whitespace(peek_offset(parser, 5)) || (peek_offset(parser, 5) ==
'\0'))
11180 pm_token_type_t
type = lex_embdoc(parser);
11181 if (
type == PM_TOKEN_EOF) {
11185 goto lex_next_token;
11188 if (lex_state_operator_p(parser)) {
11189 lex_state_set(parser, PM_LEX_STATE_ARG);
11191 lex_state_set(parser, PM_LEX_STATE_BEG);
11194 if (match(parser,
'>')) {
11195 LEX(PM_TOKEN_EQUAL_GREATER);
11198 if (match(parser,
'~')) {
11199 LEX(PM_TOKEN_EQUAL_TILDE);
11202 if (match(parser,
'=')) {
11203 LEX(match(parser,
'=') ? PM_TOKEN_EQUAL_EQUAL_EQUAL : PM_TOKEN_EQUAL_EQUAL);
11206 LEX(PM_TOKEN_EQUAL);
11210 if (match(parser,
'<')) {
11212 !lex_state_p(parser, PM_LEX_STATE_DOT | PM_LEX_STATE_CLASS) &&
11213 !lex_state_end_p(parser) &&
11214 (!lex_state_p(parser, PM_LEX_STATE_ARG_ANY) || lex_state_p(parser, PM_LEX_STATE_LABELED) || space_seen)
11216 const uint8_t *end = parser->
current.end;
11221 if (match(parser,
'-')) {
11222 indent = PM_HEREDOC_INDENT_DASH;
11224 else if (match(parser,
'~')) {
11225 indent = PM_HEREDOC_INDENT_TILDE;
11228 if (match(parser,
'`')) {
11229 quote = PM_HEREDOC_QUOTE_BACKTICK;
11231 else if (match(parser,
'"')) {
11232 quote = PM_HEREDOC_QUOTE_DOUBLE;
11234 else if (match(parser,
'\'')) {
11235 quote = PM_HEREDOC_QUOTE_SINGLE;
11238 const uint8_t *ident_start = parser->
current.end;
11243 }
else if (quote == PM_HEREDOC_QUOTE_NONE && (width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) == 0) {
11246 if (quote == PM_HEREDOC_QUOTE_NONE) {
11247 parser->
current.end += width;
11249 while ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end))) {
11250 parser->
current.end += width;
11256 if (*parser->
current.end ==
'\r' || *parser->
current.end ==
'\n')
break;
11261 size_t ident_length = (size_t) (parser->
current.end - ident_start);
11262 bool ident_error =
false;
11264 if (quote != PM_HEREDOC_QUOTE_NONE && !match(parser, (uint8_t) quote)) {
11265 pm_parser_err(parser, ident_start, ident_start + ident_length, PM_ERR_HEREDOC_IDENTIFIER);
11266 ident_error =
true;
11271 .mode = PM_LEX_HEREDOC,
11274 .ident_start = ident_start,
11275 .ident_length = ident_length,
11279 .next_start = parser->
current.end,
11281 .line_continuation =
false
11286 const uint8_t *body_start = next_newline(parser->
current.end, parser->
end - parser->
current.end);
11288 if (body_start == NULL) {
11293 if (!ident_error) pm_parser_err_heredoc_term(parser, ident_start, ident_length);
11294 body_start = parser->
end;
11298 pm_newline_list_append(&parser->
newline_list, body_start);
11307 LEX(PM_TOKEN_HEREDOC_START);
11311 if (match(parser,
'=')) {
11312 lex_state_set(parser, PM_LEX_STATE_BEG);
11313 LEX(PM_TOKEN_LESS_LESS_EQUAL);
11316 if (ambiguous_operator_p(parser, space_seen)) {
11317 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"<<",
"here document");
11320 if (lex_state_operator_p(parser)) {
11321 lex_state_set(parser, PM_LEX_STATE_ARG);
11323 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
11324 lex_state_set(parser, PM_LEX_STATE_BEG);
11327 LEX(PM_TOKEN_LESS_LESS);
11330 if (lex_state_operator_p(parser)) {
11331 lex_state_set(parser, PM_LEX_STATE_ARG);
11333 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
11334 lex_state_set(parser, PM_LEX_STATE_BEG);
11337 if (match(parser,
'=')) {
11338 if (match(parser,
'>')) {
11339 LEX(PM_TOKEN_LESS_EQUAL_GREATER);
11342 LEX(PM_TOKEN_LESS_EQUAL);
11345 LEX(PM_TOKEN_LESS);
11349 if (match(parser,
'>')) {
11350 if (lex_state_operator_p(parser)) {
11351 lex_state_set(parser, PM_LEX_STATE_ARG);
11353 lex_state_set(parser, PM_LEX_STATE_BEG);
11355 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_GREATER_EQUAL : PM_TOKEN_GREATER_GREATER);
11358 if (lex_state_operator_p(parser)) {
11359 lex_state_set(parser, PM_LEX_STATE_ARG);
11361 lex_state_set(parser, PM_LEX_STATE_BEG);
11364 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_EQUAL : PM_TOKEN_GREATER);
11368 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
11369 lex_mode_push_string(parser,
true, label_allowed,
'\0',
'"');
11370 LEX(PM_TOKEN_STRING_BEGIN);
11375 if (lex_state_p(parser, PM_LEX_STATE_FNAME)) {
11376 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11377 LEX(PM_TOKEN_BACKTICK);
11380 if (lex_state_p(parser, PM_LEX_STATE_DOT)) {
11381 if (previous_command_start) {
11382 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11384 lex_state_set(parser, PM_LEX_STATE_ARG);
11387 LEX(PM_TOKEN_BACKTICK);
11390 lex_mode_push_string(parser,
true,
false,
'\0',
'`');
11391 LEX(PM_TOKEN_BACKTICK);
11396 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
11397 lex_mode_push_string(parser,
false, label_allowed,
'\0',
'\'');
11398 LEX(PM_TOKEN_STRING_BEGIN);
11403 LEX(lex_question_mark(parser));
11407 if (match(parser,
'&')) {
11408 lex_state_set(parser, PM_LEX_STATE_BEG);
11410 if (match(parser,
'=')) {
11411 LEX(PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
11414 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
11417 if (match(parser,
'=')) {
11418 lex_state_set(parser, PM_LEX_STATE_BEG);
11419 LEX(PM_TOKEN_AMPERSAND_EQUAL);
11422 if (match(parser,
'.')) {
11423 lex_state_set(parser, PM_LEX_STATE_DOT);
11424 LEX(PM_TOKEN_AMPERSAND_DOT);
11427 pm_token_type_t
type = PM_TOKEN_AMPERSAND;
11428 if (lex_state_spcarg_p(parser, space_seen)) {
11429 if ((peek(parser) !=
':') || (peek_offset(parser, 1) ==
'\0')) {
11430 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
11432 const uint8_t delim = peek_offset(parser, 1);
11434 if ((delim !=
'\'') && (delim !=
'"') && !char_is_identifier(parser, parser->
current.end + 1, parser->
end - (parser->
current.end + 1))) {
11435 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
11439 type = PM_TOKEN_UAMPERSAND;
11440 }
else if (lex_state_beg_p(parser)) {
11441 type = PM_TOKEN_UAMPERSAND;
11442 }
else if (ambiguous_operator_p(parser, space_seen)) {
11443 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"&",
"argument prefix");
11446 if (lex_state_operator_p(parser)) {
11447 lex_state_set(parser, PM_LEX_STATE_ARG);
11449 lex_state_set(parser, PM_LEX_STATE_BEG);
11457 if (match(parser,
'|')) {
11458 if (match(parser,
'=')) {
11459 lex_state_set(parser, PM_LEX_STATE_BEG);
11460 LEX(PM_TOKEN_PIPE_PIPE_EQUAL);
11463 if (lex_state_p(parser, PM_LEX_STATE_BEG)) {
11465 LEX(PM_TOKEN_PIPE);
11468 lex_state_set(parser, PM_LEX_STATE_BEG);
11469 LEX(PM_TOKEN_PIPE_PIPE);
11472 if (match(parser,
'=')) {
11473 lex_state_set(parser, PM_LEX_STATE_BEG);
11474 LEX(PM_TOKEN_PIPE_EQUAL);
11477 if (lex_state_operator_p(parser)) {
11478 lex_state_set(parser, PM_LEX_STATE_ARG);
11480 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
11483 LEX(PM_TOKEN_PIPE);
11487 if (lex_state_operator_p(parser)) {
11488 lex_state_set(parser, PM_LEX_STATE_ARG);
11490 if (match(parser,
'@')) {
11491 LEX(PM_TOKEN_UPLUS);
11494 LEX(PM_TOKEN_PLUS);
11497 if (match(parser,
'=')) {
11498 lex_state_set(parser, PM_LEX_STATE_BEG);
11499 LEX(PM_TOKEN_PLUS_EQUAL);
11503 lex_state_beg_p(parser) ||
11504 (lex_state_spcarg_p(parser, space_seen) ? (pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS),
true) : false)
11506 lex_state_set(parser, PM_LEX_STATE_BEG);
11508 if (pm_char_is_decimal_digit(peek(parser))) {
11510 pm_token_type_t
type = lex_numeric(parser);
11511 lex_state_set(parser, PM_LEX_STATE_END);
11515 LEX(PM_TOKEN_UPLUS);
11518 if (ambiguous_operator_p(parser, space_seen)) {
11519 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"+",
"unary operator");
11522 lex_state_set(parser, PM_LEX_STATE_BEG);
11523 LEX(PM_TOKEN_PLUS);
11528 if (lex_state_operator_p(parser)) {
11529 lex_state_set(parser, PM_LEX_STATE_ARG);
11531 if (match(parser,
'@')) {
11532 LEX(PM_TOKEN_UMINUS);
11535 LEX(PM_TOKEN_MINUS);
11538 if (match(parser,
'=')) {
11539 lex_state_set(parser, PM_LEX_STATE_BEG);
11540 LEX(PM_TOKEN_MINUS_EQUAL);
11543 if (match(parser,
'>')) {
11544 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11545 LEX(PM_TOKEN_MINUS_GREATER);
11548 bool spcarg = lex_state_spcarg_p(parser, space_seen);
11549 bool is_beg = lex_state_beg_p(parser);
11550 if (!is_beg && spcarg) {
11551 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS);
11554 if (is_beg || spcarg) {
11555 lex_state_set(parser, PM_LEX_STATE_BEG);
11556 LEX(pm_char_is_decimal_digit(peek(parser)) ? PM_TOKEN_UMINUS_NUM : PM_TOKEN_UMINUS);
11559 if (ambiguous_operator_p(parser, space_seen)) {
11560 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"-",
"unary operator");
11563 lex_state_set(parser, PM_LEX_STATE_BEG);
11564 LEX(PM_TOKEN_MINUS);
11569 bool beg_p = lex_state_beg_p(parser);
11571 if (match(parser,
'.')) {
11572 if (match(parser,
'.')) {
11575 if (lex_state_p(parser, PM_LEX_STATE_END)) {
11576 lex_state_set(parser, PM_LEX_STATE_BEG);
11578 lex_state_set(parser, PM_LEX_STATE_ENDARG);
11580 LEX(PM_TOKEN_UDOT_DOT_DOT);
11584 pm_parser_warn_token(parser, &parser->
current, PM_WARN_DOT_DOT_DOT_EOL);
11587 lex_state_set(parser, PM_LEX_STATE_BEG);
11588 LEX(beg_p ? PM_TOKEN_UDOT_DOT_DOT : PM_TOKEN_DOT_DOT_DOT);
11591 lex_state_set(parser, PM_LEX_STATE_BEG);
11592 LEX(beg_p ? PM_TOKEN_UDOT_DOT : PM_TOKEN_DOT_DOT);
11595 lex_state_set(parser, PM_LEX_STATE_DOT);
11610 pm_token_type_t
type = lex_numeric(parser);
11611 lex_state_set(parser, PM_LEX_STATE_END);
11617 if (match(parser,
':')) {
11618 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)) {
11619 lex_state_set(parser, PM_LEX_STATE_BEG);
11620 LEX(PM_TOKEN_UCOLON_COLON);
11623 lex_state_set(parser, PM_LEX_STATE_DOT);
11624 LEX(PM_TOKEN_COLON_COLON);
11627 if (lex_state_end_p(parser) || pm_char_is_whitespace(peek(parser)) || peek(parser) ==
'#') {
11628 lex_state_set(parser, PM_LEX_STATE_BEG);
11629 LEX(PM_TOKEN_COLON);
11632 if (peek(parser) ==
'"' || peek(parser) ==
'\'') {
11633 lex_mode_push_string(parser, peek(parser) ==
'"',
false,
'\0', *parser->
current.end);
11637 lex_state_set(parser, PM_LEX_STATE_FNAME);
11638 LEX(PM_TOKEN_SYMBOL_BEGIN);
11642 if (lex_state_beg_p(parser)) {
11643 lex_mode_push_regexp(parser,
'\0',
'/');
11644 LEX(PM_TOKEN_REGEXP_BEGIN);
11647 if (match(parser,
'=')) {
11648 lex_state_set(parser, PM_LEX_STATE_BEG);
11649 LEX(PM_TOKEN_SLASH_EQUAL);
11652 if (lex_state_spcarg_p(parser, space_seen)) {
11653 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_SLASH);
11654 lex_mode_push_regexp(parser,
'\0',
'/');
11655 LEX(PM_TOKEN_REGEXP_BEGIN);
11658 if (ambiguous_operator_p(parser, space_seen)) {
11659 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"/",
"regexp literal");
11662 if (lex_state_operator_p(parser)) {
11663 lex_state_set(parser, PM_LEX_STATE_ARG);
11665 lex_state_set(parser, PM_LEX_STATE_BEG);
11668 LEX(PM_TOKEN_SLASH);
11672 if (lex_state_operator_p(parser)) {
11673 lex_state_set(parser, PM_LEX_STATE_ARG);
11675 lex_state_set(parser, PM_LEX_STATE_BEG);
11677 LEX(match(parser,
'=') ? PM_TOKEN_CARET_EQUAL : PM_TOKEN_CARET);
11681 if (lex_state_operator_p(parser)) {
11682 (void) match(parser,
'@');
11683 lex_state_set(parser, PM_LEX_STATE_ARG);
11685 lex_state_set(parser, PM_LEX_STATE_BEG);
11688 LEX(PM_TOKEN_TILDE);
11696 if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->
current.end >= parser->
end)) {
11697 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT_EOF);
11698 LEX(PM_TOKEN_PERCENT);
11701 if (!lex_state_beg_p(parser) && match(parser,
'=')) {
11702 lex_state_set(parser, PM_LEX_STATE_BEG);
11703 LEX(PM_TOKEN_PERCENT_EQUAL);
11705 lex_state_beg_p(parser) ||
11706 (lex_state_p(parser, PM_LEX_STATE_FITEM) && (peek(parser) ==
's')) ||
11707 lex_state_spcarg_p(parser, space_seen)
11710 if (*parser->
current.end >= 0x80) {
11711 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11714 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11715 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11716 LEX(PM_TOKEN_STRING_BEGIN);
11721 uint8_t delimiter = peek_offset(parser, 1);
11723 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11724 goto lex_next_token;
11727 switch (peek(parser)) {
11732 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11734 lex_mode_push_list_eof(parser);
11737 LEX(PM_TOKEN_PERCENT_LOWER_I);
11743 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11745 lex_mode_push_list_eof(parser);
11748 LEX(PM_TOKEN_PERCENT_UPPER_I);
11754 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11755 lex_mode_push_regexp(parser, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11757 lex_mode_push_regexp(parser,
'\0',
'\0');
11760 LEX(PM_TOKEN_REGEXP_BEGIN);
11766 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11767 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11769 lex_mode_push_string_eof(parser);
11772 LEX(PM_TOKEN_STRING_BEGIN);
11778 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11779 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11781 lex_mode_push_string_eof(parser);
11784 LEX(PM_TOKEN_STRING_BEGIN);
11790 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11791 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11792 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
11794 lex_mode_push_string_eof(parser);
11797 LEX(PM_TOKEN_SYMBOL_BEGIN);
11803 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11805 lex_mode_push_list_eof(parser);
11808 LEX(PM_TOKEN_PERCENT_LOWER_W);
11814 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11816 lex_mode_push_list_eof(parser);
11819 LEX(PM_TOKEN_PERCENT_UPPER_W);
11825 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11826 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11828 lex_mode_push_string_eof(parser);
11831 LEX(PM_TOKEN_PERCENT_LOWER_X);
11838 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11839 goto lex_next_token;
11843 if (ambiguous_operator_p(parser, space_seen)) {
11844 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"%",
"string literal");
11847 lex_state_set(parser, lex_state_operator_p(parser) ? PM_LEX_STATE_ARG : PM_LEX_STATE_BEG);
11848 LEX(PM_TOKEN_PERCENT);
11853 pm_token_type_t
type = lex_global_variable(parser);
11858 lex_mode_pop(parser);
11861 lex_state_set(parser, PM_LEX_STATE_END);
11867 lex_state_set(parser, parser->
lex_state & PM_LEX_STATE_FNAME ? PM_LEX_STATE_ENDFN : PM_LEX_STATE_END);
11868 LEX(lex_at_variable(parser));
11871 if (*parser->
current.start !=
'_') {
11872 size_t width = char_is_identifier_start(parser, parser->
current.start, parser->
end - parser->
current.start);
11879 if (*parser->
current.start >= 0x80) {
11880 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *parser->
current.start);
11881 }
else if (*parser->
current.start ==
'\\') {
11882 switch (peek_at(parser, parser->
current.start + 1)) {
11885 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped space");
11889 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped form feed");
11893 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped horizontal tab");
11897 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped vertical tab");
11900 if (peek_at(parser, parser->
current.start + 2) !=
'\n') {
11902 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped carriage return");
11907 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"backslash");
11910 }
else if (char_is_ascii_printable(*parser->
current.start)) {
11911 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_PRINTABLE_CHARACTER, *parser->
current.start);
11913 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_CHARACTER, *parser->
current.start);
11916 goto lex_next_token;
11922 pm_token_type_t
type = lex_identifier(parser, previous_command_start);
11930 current_token_starts_line(parser) &&
11931 (memcmp(parser->
current.start,
"__END__", 7) == 0) &&
11932 (parser->
current.end == parser->
end || match_eol(parser))
11937 const uint8_t *cursor = parser->
current.end;
11938 while ((cursor = next_newline(cursor, parser->
end - cursor)) != NULL) {
11939 pm_newline_list_append(&parser->
newline_list, cursor++);
11943 parser->
current.type = PM_TOKEN___END__;
11944 parser_lex_callback(parser);
11954 if (
type == PM_TOKEN_IDENTIFIER ||
type == PM_TOKEN_CONSTANT ||
type == PM_TOKEN_METHOD_NAME) {
11955 if (lex_state_p(parser, PM_LEX_STATE_BEG_ANY | PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_DOT)) {
11956 if (previous_command_start) {
11957 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11959 lex_state_set(parser, PM_LEX_STATE_ARG);
11961 }
else if (parser->
lex_state == PM_LEX_STATE_FNAME) {
11962 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11964 lex_state_set(parser, PM_LEX_STATE_END);
11969 !(last_state & (PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME)) &&
11970 (
type == PM_TOKEN_IDENTIFIER) &&
11971 ((pm_parser_local_depth(parser, &parser->
current) != -1) ||
11972 pm_token_is_numbered_parameter(parser->
current.start, parser->
current.end))
11974 lex_state_set(parser, PM_LEX_STATE_END | PM_LEX_STATE_LABEL);
11981 case PM_LEX_LIST: {
11995 whitespace = pm_strspn_inline_whitespace(parser->
current.end, parser->
end - parser->
current.end);
11996 if (peek_offset(parser, (ptrdiff_t)whitespace) ==
'\n') {
12003 if (whitespace > 0) {
12004 parser->
current.end += whitespace;
12005 if (peek_offset(parser, -1) ==
'\n') {
12007 parser_flush_heredoc_end(parser);
12009 LEX(PM_TOKEN_WORDS_SEP);
12021 const uint8_t *breakpoints = lex_mode->
as.list.
breakpoints;
12022 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12028 while (breakpoint != NULL) {
12031 if (pm_char_is_whitespace(*breakpoint)) {
12032 parser->
current.end = breakpoint;
12033 pm_token_buffer_flush(parser, &token_buffer);
12034 LEX(PM_TOKEN_STRING_CONTENT);
12043 parser->
current.end = breakpoint + 1;
12044 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12051 if (breakpoint > parser->
current.start) {
12052 parser->
current.end = breakpoint;
12053 pm_token_buffer_flush(parser, &token_buffer);
12054 LEX(PM_TOKEN_STRING_CONTENT);
12059 parser->
current.end = breakpoint + 1;
12060 lex_mode_pop(parser);
12061 lex_state_set(parser, PM_LEX_STATE_END);
12062 LEX(PM_TOKEN_STRING_END);
12066 if (*breakpoint ==
'\0') {
12067 breakpoint = pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->
end - (breakpoint + 1),
true);
12074 if (*breakpoint ==
'\\') {
12075 parser->
current.end = breakpoint + 1;
12084 pm_token_buffer_escape(parser, &token_buffer);
12085 uint8_t peeked = peek(parser);
12093 pm_token_buffer_push_byte(&token_buffer, peeked);
12098 if (peek(parser) !=
'\n') {
12099 pm_token_buffer_push_byte(&token_buffer,
'\r');
12104 pm_token_buffer_push_byte(&token_buffer,
'\n');
12110 parser_flush_heredoc_end(parser);
12111 pm_token_buffer_copy(parser, &token_buffer);
12112 LEX(PM_TOKEN_STRING_CONTENT);
12122 pm_token_buffer_push_byte(&token_buffer, peeked);
12125 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12127 pm_token_buffer_push_byte(&token_buffer,
'\\');
12128 pm_token_buffer_push_escaped(&token_buffer, parser);
12135 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12140 if (*breakpoint ==
'#') {
12141 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12143 if (
type == PM_TOKEN_NOT_PROVIDED) {
12148 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12152 if (
type == PM_TOKEN_STRING_CONTENT) {
12153 pm_token_buffer_flush(parser, &token_buffer);
12162 parser->
current.end = breakpoint + 1;
12163 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12169 pm_token_buffer_flush(parser, &token_buffer);
12170 LEX(PM_TOKEN_STRING_CONTENT);
12176 pm_token_buffer_flush(parser, &token_buffer);
12177 LEX(PM_TOKEN_STRING_CONTENT);
12179 case PM_LEX_REGEXP: {
12201 const uint8_t *breakpoints = lex_mode->
as.regexp.
breakpoints;
12202 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12205 while (breakpoint != NULL) {
12207 bool is_terminator = (*breakpoint == term);
12212 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
12213 if (term ==
'\n') {
12214 is_terminator =
true;
12220 if (term ==
'\r') {
12221 is_terminator =
false;
12227 if (is_terminator) {
12229 parser->
current.end = breakpoint + 1;
12230 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12238 if (breakpoint > parser->
current.start) {
12239 parser->
current.end = breakpoint;
12240 pm_regexp_token_buffer_flush(parser, &token_buffer);
12241 LEX(PM_TOKEN_STRING_CONTENT);
12245 size_t eol_length = match_eol_at(parser, breakpoint);
12247 parser->
current.end = breakpoint + eol_length;
12250 parser->
current.end = breakpoint + 1;
12257 lex_mode_pop(parser);
12258 lex_state_set(parser, PM_LEX_STATE_END);
12259 LEX(PM_TOKEN_REGEXP_END);
12264 if (*breakpoint && *breakpoint == lex_mode->
as.regexp.
incrementor) {
12265 parser->
current.end = breakpoint + 1;
12266 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12271 switch (*breakpoint) {
12274 parser->
current.end = breakpoint + 1;
12275 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12278 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12279 parser->
current.end = breakpoint + 1;
12280 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12285 parser->
current.end = breakpoint;
12286 pm_regexp_token_buffer_escape(parser, &token_buffer);
12294 pm_newline_list_append(&parser->
newline_list, breakpoint);
12295 parser->
current.end = breakpoint + 1;
12296 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12300 parser->
current.end = breakpoint + 1;
12301 parser_flush_heredoc_end(parser);
12302 pm_regexp_token_buffer_flush(parser, &token_buffer);
12303 LEX(PM_TOKEN_STRING_CONTENT);
12308 parser->
current.end = breakpoint + 1;
12317 pm_regexp_token_buffer_escape(parser, &token_buffer);
12318 uint8_t peeked = peek(parser);
12323 if (peek(parser) !=
'\n') {
12325 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12327 pm_regexp_token_buffer_push_byte(&token_buffer,
'\r');
12328 pm_token_buffer_push_byte(&token_buffer.
base,
'\r');
12337 parser_flush_heredoc_end(parser);
12338 pm_regexp_token_buffer_copy(parser, &token_buffer);
12339 LEX(PM_TOKEN_STRING_CONTENT);
12360 case '$':
case ')':
case '*':
case '+':
12361 case '.':
case '>':
case '?':
case ']':
12362 case '^':
case '|':
case '}':
12363 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12369 pm_regexp_token_buffer_push_byte(&token_buffer, peeked);
12370 pm_token_buffer_push_byte(&token_buffer.
base, peeked);
12375 if (peeked < 0x80) pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12376 pm_regexp_token_buffer_push_escaped(&token_buffer, parser);
12381 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12387 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12389 if (
type == PM_TOKEN_NOT_PROVIDED) {
12394 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12398 if (
type == PM_TOKEN_STRING_CONTENT) {
12399 pm_regexp_token_buffer_flush(parser, &token_buffer);
12405 assert(
false &&
"unreachable");
12411 pm_regexp_token_buffer_flush(parser, &token_buffer);
12412 LEX(PM_TOKEN_STRING_CONTENT);
12418 pm_regexp_token_buffer_flush(parser, &token_buffer);
12419 LEX(PM_TOKEN_STRING_CONTENT);
12421 case PM_LEX_STRING: {
12440 const uint8_t *breakpoints = lex_mode->
as.string.
breakpoints;
12441 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12447 while (breakpoint != NULL) {
12452 parser->
current.end = breakpoint + 1;
12453 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12458 bool is_terminator = (*breakpoint == term);
12463 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
12464 if (term ==
'\n') {
12465 is_terminator =
true;
12471 if (term ==
'\r') {
12472 is_terminator =
false;
12479 if (is_terminator) {
12483 parser->
current.end = breakpoint + 1;
12484 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12491 if (breakpoint > parser->
current.start) {
12492 parser->
current.end = breakpoint;
12493 pm_token_buffer_flush(parser, &token_buffer);
12494 LEX(PM_TOKEN_STRING_CONTENT);
12499 size_t eol_length = match_eol_at(parser, breakpoint);
12501 parser->
current.end = breakpoint + eol_length;
12504 parser->
current.end = breakpoint + 1;
12507 if (lex_mode->
as.string.
label_allowed && (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')) {
12509 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
12510 lex_mode_pop(parser);
12511 LEX(PM_TOKEN_LABEL_END);
12514 lex_state_set(parser, PM_LEX_STATE_END);
12515 lex_mode_pop(parser);
12516 LEX(PM_TOKEN_STRING_END);
12519 switch (*breakpoint) {
12522 parser->
current.end = breakpoint + 1;
12523 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12526 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12527 parser->
current.end = breakpoint + 1;
12528 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12535 parser->
current.end = breakpoint;
12536 pm_token_buffer_escape(parser, &token_buffer);
12537 token_buffer.
cursor = breakpoint;
12546 pm_newline_list_append(&parser->
newline_list, breakpoint);
12547 parser->
current.end = breakpoint + 1;
12548 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12552 parser->
current.end = breakpoint + 1;
12553 parser_flush_heredoc_end(parser);
12554 pm_token_buffer_flush(parser, &token_buffer);
12555 LEX(PM_TOKEN_STRING_CONTENT);
12558 parser->
current.end = breakpoint + 1;
12567 pm_token_buffer_escape(parser, &token_buffer);
12568 uint8_t peeked = peek(parser);
12572 pm_token_buffer_push_byte(&token_buffer,
'\\');
12577 if (peek(parser) !=
'\n') {
12579 pm_token_buffer_push_byte(&token_buffer,
'\\');
12581 pm_token_buffer_push_byte(&token_buffer,
'\r');
12587 pm_token_buffer_push_byte(&token_buffer,
'\\');
12588 pm_token_buffer_push_byte(&token_buffer,
'\n');
12595 parser_flush_heredoc_end(parser);
12596 pm_token_buffer_copy(parser, &token_buffer);
12597 LEX(PM_TOKEN_STRING_CONTENT);
12607 pm_token_buffer_push_byte(&token_buffer, peeked);
12610 pm_token_buffer_push_byte(&token_buffer, peeked);
12613 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12615 pm_token_buffer_push_byte(&token_buffer,
'\\');
12616 pm_token_buffer_push_escaped(&token_buffer, parser);
12623 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12627 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12629 if (
type == PM_TOKEN_NOT_PROVIDED) {
12634 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12638 if (
type == PM_TOKEN_STRING_CONTENT) {
12639 pm_token_buffer_flush(parser, &token_buffer);
12645 assert(
false &&
"unreachable");
12650 pm_token_buffer_flush(parser, &token_buffer);
12651 LEX(PM_TOKEN_STRING_CONTENT);
12657 pm_token_buffer_flush(parser, &token_buffer);
12658 LEX(PM_TOKEN_STRING_CONTENT);
12660 case PM_LEX_HEREDOC: {
12687 lex_state_set(parser, PM_LEX_STATE_END);
12688 lex_mode_pop(parser);
12689 LEX(PM_TOKEN_HEREDOC_END);
12692 const uint8_t *ident_start = heredoc_lex_mode->
ident_start;
12697 if (current_token_starts_line(parser)) {
12698 const uint8_t *start = parser->
current.start;
12700 if (!line_continuation && (start + ident_length <= parser->end)) {
12701 const uint8_t *newline = next_newline(start, parser->
end - start);
12702 const uint8_t *ident_end = newline;
12703 const uint8_t *terminator_end = newline;
12705 if (newline == NULL) {
12706 terminator_end = parser->
end;
12707 ident_end = parser->
end;
12710 if (newline[-1] ==
'\r') {
12715 const uint8_t *terminator_start = ident_end - ident_length;
12716 const uint8_t *cursor = start;
12718 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12719 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12725 (cursor == terminator_start) &&
12726 (memcmp(terminator_start, ident_start, ident_length) == 0)
12728 if (newline != NULL) {
12729 pm_newline_list_append(&parser->
newline_list, newline);
12732 parser->
current.end = terminator_end;
12740 lex_state_set(parser, PM_LEX_STATE_END);
12741 lex_mode_pop(parser);
12742 LEX(PM_TOKEN_HEREDOC_END);
12746 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, heredoc_lex_mode->
indent);
12748 heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE &&
12751 peek_at(parser, start) !=
'\n'
12760 uint8_t breakpoints[] =
"\r\n\\#";
12763 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12764 breakpoints[3] =
'\0';
12767 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12769 bool was_line_continuation =
false;
12771 while (breakpoint != NULL) {
12772 switch (*breakpoint) {
12775 parser->
current.end = breakpoint + 1;
12776 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12779 parser->
current.end = breakpoint + 1;
12781 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12782 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12789 pm_token_buffer_escape(parser, &token_buffer);
12790 token_buffer.
cursor = breakpoint;
12795 parser_flush_heredoc_end(parser);
12796 parser->
current.end = breakpoint + 1;
12797 pm_token_buffer_flush(parser, &token_buffer);
12798 LEX(PM_TOKEN_STRING_CONTENT);
12801 pm_newline_list_append(&parser->
newline_list, breakpoint);
12805 const uint8_t *start = breakpoint + 1;
12807 if (!was_line_continuation && (start + ident_length <= parser->end)) {
12810 const uint8_t *newline = next_newline(start, parser->
end - start);
12812 if (newline == NULL) {
12813 newline = parser->
end;
12814 }
else if (newline[-1] ==
'\r') {
12819 const uint8_t *terminator_start = newline - ident_length;
12823 const uint8_t *cursor = start;
12825 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12826 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12832 cursor == terminator_start &&
12833 (memcmp(terminator_start, ident_start, ident_length) == 0)
12835 parser->
current.end = breakpoint + 1;
12836 pm_token_buffer_flush(parser, &token_buffer);
12837 LEX(PM_TOKEN_STRING_CONTENT);
12841 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->
as.heredoc.
base.
indent);
12848 if (lex_mode->
as.heredoc.
base.
indent == PM_HEREDOC_INDENT_TILDE) {
12853 parser->
current.end = breakpoint + 1;
12854 pm_token_buffer_flush(parser, &token_buffer);
12855 LEX(PM_TOKEN_STRING_CONTENT);
12860 parser->
current.end = breakpoint + 1;
12861 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12871 parser->
current.end = breakpoint + 1;
12880 pm_token_buffer_escape(parser, &token_buffer);
12881 uint8_t peeked = peek(parser);
12883 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12887 if (peek(parser) !=
'\n') {
12888 pm_token_buffer_push_byte(&token_buffer,
'\\');
12889 pm_token_buffer_push_byte(&token_buffer,
'\r');
12894 pm_token_buffer_push_byte(&token_buffer,
'\\');
12895 pm_token_buffer_push_byte(&token_buffer,
'\n');
12897 breakpoint = parser->
current.end;
12900 pm_token_buffer_push_byte(&token_buffer,
'\\');
12901 pm_token_buffer_push_escaped(&token_buffer, parser);
12908 if (peek(parser) !=
'\n') {
12909 pm_token_buffer_push_byte(&token_buffer,
'\r');
12917 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12918 const uint8_t *end = parser->
current.end;
12923 parser->
current.end = breakpoint;
12924 pm_token_buffer_flush(parser, &token_buffer);
12928 parser->
current.end = end + 1;
12930 LEX(PM_TOKEN_STRING_CONTENT);
12933 was_line_continuation =
true;
12935 breakpoint = parser->
current.end;
12938 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12944 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12948 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12950 if (
type == PM_TOKEN_NOT_PROVIDED) {
12956 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12960 if (
type == PM_TOKEN_STRING_CONTENT) {
12961 pm_token_buffer_flush(parser, &token_buffer);
12967 assert(
false &&
"unreachable");
12970 was_line_continuation =
false;
12975 pm_token_buffer_flush(parser, &token_buffer);
12976 LEX(PM_TOKEN_STRING_CONTENT);
12982 pm_token_buffer_flush(parser, &token_buffer);
12983 LEX(PM_TOKEN_STRING_CONTENT);
12987 assert(
false &&
"unreachable");
13005 PM_BINDING_POWER_UNSET = 0,
13006 PM_BINDING_POWER_STATEMENT = 2,
13007 PM_BINDING_POWER_MODIFIER_RESCUE = 4,
13008 PM_BINDING_POWER_MODIFIER = 6,
13009 PM_BINDING_POWER_COMPOSITION = 8,
13010 PM_BINDING_POWER_NOT = 10,
13011 PM_BINDING_POWER_MATCH = 12,
13012 PM_BINDING_POWER_DEFINED = 14,
13013 PM_BINDING_POWER_MULTI_ASSIGNMENT = 16,
13014 PM_BINDING_POWER_ASSIGNMENT = 18,
13015 PM_BINDING_POWER_TERNARY = 20,
13016 PM_BINDING_POWER_RANGE = 22,
13017 PM_BINDING_POWER_LOGICAL_OR = 24,
13018 PM_BINDING_POWER_LOGICAL_AND = 26,
13019 PM_BINDING_POWER_EQUALITY = 28,
13020 PM_BINDING_POWER_COMPARISON = 30,
13021 PM_BINDING_POWER_BITWISE_OR = 32,
13022 PM_BINDING_POWER_BITWISE_AND = 34,
13023 PM_BINDING_POWER_SHIFT = 36,
13024 PM_BINDING_POWER_TERM = 38,
13025 PM_BINDING_POWER_FACTOR = 40,
13026 PM_BINDING_POWER_UMINUS = 42,
13027 PM_BINDING_POWER_EXPONENT = 44,
13028 PM_BINDING_POWER_UNARY = 46,
13029 PM_BINDING_POWER_INDEX = 48,
13030 PM_BINDING_POWER_CALL = 50,
13031 PM_BINDING_POWER_MAX = 52
13032} pm_binding_power_t;
13055#define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true, false }
13056#define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, false }
13057#define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true, false }
13058#define NON_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, true }
13059#define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false, false }
13063 [PM_TOKEN_KEYWORD_RESCUE_MODIFIER] = { PM_BINDING_POWER_MODIFIER_RESCUE, PM_BINDING_POWER_COMPOSITION,
true,
false },
13066 [PM_TOKEN_KEYWORD_IF_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
13067 [PM_TOKEN_KEYWORD_UNLESS_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
13068 [PM_TOKEN_KEYWORD_UNTIL_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
13069 [PM_TOKEN_KEYWORD_WHILE_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
13072 [PM_TOKEN_KEYWORD_AND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
13073 [PM_TOKEN_KEYWORD_OR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
13076 [PM_TOKEN_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
13077 [PM_TOKEN_KEYWORD_IN] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
13080 [PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
13081 [PM_TOKEN_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
13082 [PM_TOKEN_CARET_EQUAL] = BINDING_POWER_ASSIGNMENT,
13083 [PM_TOKEN_EQUAL] = BINDING_POWER_ASSIGNMENT,
13084 [PM_TOKEN_GREATER_GREATER_EQUAL] = BINDING_POWER_ASSIGNMENT,
13085 [PM_TOKEN_LESS_LESS_EQUAL] = BINDING_POWER_ASSIGNMENT,
13086 [PM_TOKEN_MINUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
13087 [PM_TOKEN_PERCENT_EQUAL] = BINDING_POWER_ASSIGNMENT,
13088 [PM_TOKEN_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
13089 [PM_TOKEN_PIPE_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
13090 [PM_TOKEN_PLUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
13091 [PM_TOKEN_SLASH_EQUAL] = BINDING_POWER_ASSIGNMENT,
13092 [PM_TOKEN_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
13093 [PM_TOKEN_STAR_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
13096 [PM_TOKEN_QUESTION_MARK] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_TERNARY),
13099 [PM_TOKEN_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
13100 [PM_TOKEN_DOT_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
13101 [PM_TOKEN_UDOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
13102 [PM_TOKEN_UDOT_DOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
13105 [PM_TOKEN_PIPE_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_OR),
13108 [PM_TOKEN_AMPERSAND_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_AND),
13111 [PM_TOKEN_BANG_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
13112 [PM_TOKEN_BANG_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
13113 [PM_TOKEN_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
13114 [PM_TOKEN_EQUAL_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
13115 [PM_TOKEN_EQUAL_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
13116 [PM_TOKEN_LESS_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
13119 [PM_TOKEN_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
13120 [PM_TOKEN_GREATER_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
13121 [PM_TOKEN_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
13122 [PM_TOKEN_LESS_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
13125 [PM_TOKEN_CARET] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
13126 [PM_TOKEN_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
13129 [PM_TOKEN_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_AND),
13132 [PM_TOKEN_GREATER_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
13133 [PM_TOKEN_LESS_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
13136 [PM_TOKEN_MINUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
13137 [PM_TOKEN_PLUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
13140 [PM_TOKEN_PERCENT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
13141 [PM_TOKEN_SLASH] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
13142 [PM_TOKEN_STAR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
13143 [PM_TOKEN_USTAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_FACTOR),
13146 [PM_TOKEN_UMINUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UMINUS),
13147 [PM_TOKEN_UMINUS_NUM] = { PM_BINDING_POWER_UMINUS, PM_BINDING_POWER_MAX,
false,
false },
13150 [PM_TOKEN_STAR_STAR] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_EXPONENT),
13151 [PM_TOKEN_USTAR_STAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13154 [PM_TOKEN_BANG] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13155 [PM_TOKEN_TILDE] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13156 [PM_TOKEN_UPLUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13159 [PM_TOKEN_BRACKET_LEFT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_INDEX),
13162 [PM_TOKEN_COLON_COLON] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
13163 [PM_TOKEN_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
13164 [PM_TOKEN_AMPERSAND_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL)
13167#undef BINDING_POWER_ASSIGNMENT
13168#undef LEFT_ASSOCIATIVE
13169#undef RIGHT_ASSOCIATIVE
13170#undef RIGHT_ASSOCIATIVE_UNARY
13184match2(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
13185 return match1(parser, type1) || match1(parser, type2);
13192match3(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3) {
13193 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3);
13200match4(
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) {
13201 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4);
13208match7(
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) {
13209 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7);
13216match8(
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) {
13217 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);
13228 if (match1(parser,
type)) {
13229 parser_lex(parser);
13240accept2(
pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
13241 if (match2(parser, type1, type2)) {
13242 parser_lex(parser);
13261 if (accept1(parser,
type))
return;
13264 pm_parser_err(parser, location, location, diag_id);
13276 if (accept2(parser, type1, type2))
return;
13279 pm_parser_err(parser, location, location, diag_id);
13290expect1_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
13291 if (match1(parser, PM_TOKEN_HEREDOC_END)) {
13292 parser_lex(parser);
13294 pm_parser_err_heredoc_term(parser, ident_start, ident_length);
13301parse_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);
13308parse_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) {
13309 pm_node_t *node = parse_expression(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
13310 pm_assert_value_expression(parser, node);
13333token_begins_expression_p(pm_token_type_t
type) {
13335 case PM_TOKEN_EQUAL_GREATER:
13336 case PM_TOKEN_KEYWORD_IN:
13340 case PM_TOKEN_BRACE_RIGHT:
13341 case PM_TOKEN_BRACKET_RIGHT:
13342 case PM_TOKEN_COLON:
13343 case PM_TOKEN_COMMA:
13344 case PM_TOKEN_EMBEXPR_END:
13346 case PM_TOKEN_LAMBDA_BEGIN:
13347 case PM_TOKEN_KEYWORD_DO:
13348 case PM_TOKEN_KEYWORD_DO_LOOP:
13349 case PM_TOKEN_KEYWORD_END:
13350 case PM_TOKEN_KEYWORD_ELSE:
13351 case PM_TOKEN_KEYWORD_ELSIF:
13352 case PM_TOKEN_KEYWORD_ENSURE:
13353 case PM_TOKEN_KEYWORD_THEN:
13354 case PM_TOKEN_KEYWORD_RESCUE:
13355 case PM_TOKEN_KEYWORD_WHEN:
13356 case PM_TOKEN_NEWLINE:
13357 case PM_TOKEN_PARENTHESIS_RIGHT:
13358 case PM_TOKEN_SEMICOLON:
13364 assert(pm_binding_powers[
type].left == PM_BINDING_POWER_UNSET);
13366 case PM_TOKEN_UAMPERSAND:
13370 case PM_TOKEN_UCOLON_COLON:
13371 case PM_TOKEN_UMINUS:
13372 case PM_TOKEN_UMINUS_NUM:
13373 case PM_TOKEN_UPLUS:
13374 case PM_TOKEN_BANG:
13375 case PM_TOKEN_TILDE:
13376 case PM_TOKEN_UDOT_DOT:
13377 case PM_TOKEN_UDOT_DOT_DOT:
13384 return pm_binding_powers[
type].
left == PM_BINDING_POWER_UNSET;
13393parse_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) {
13394 if (accept1(parser, PM_TOKEN_USTAR)) {
13396 pm_node_t *expression = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13397 return (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
13400 return parse_value_expression(parser, binding_power, accepts_command_call,
false, diag_id, depth);
13414 size_t length = constant->
length;
13415 uint8_t *name =
xcalloc(length + 1,
sizeof(uint8_t));
13416 if (name == NULL)
return;
13418 memcpy(name, constant->
start, length);
13419 name[length] =
'=';
13424 *name_field = pm_constant_pool_insert_owned(&parser->
constant_pool, name, length + 1);
13435 switch (PM_NODE_TYPE(target)) {
13436 case PM_SOURCE_ENCODING_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13437 case PM_FALSE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13438 case PM_SOURCE_FILE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13439 case PM_SOURCE_LINE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13440 case PM_NIL_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13441 case PM_SELF_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13442 case PM_TRUE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13449 pm_node_destroy(parser, target);
13462 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
13463 if (implicit_parameters->
nodes[index] == node) {
13467 if (index != implicit_parameters->
size - 1) {
13468 memcpy(&implicit_parameters->
nodes[index], &implicit_parameters->
nodes[index + 1], (implicit_parameters->
size - index - 1) *
sizeof(
pm_node_t *));
13471 implicit_parameters->
size--;
13487 switch (PM_NODE_TYPE(target)) {
13488 case PM_MISSING_NODE:
13490 case PM_SOURCE_ENCODING_NODE:
13491 case PM_FALSE_NODE:
13492 case PM_SOURCE_FILE_NODE:
13493 case PM_SOURCE_LINE_NODE:
13496 case PM_TRUE_NODE: {
13499 return parse_unwriteable_target(parser, target);
13501 case PM_CLASS_VARIABLE_READ_NODE:
13503 target->
type = PM_CLASS_VARIABLE_TARGET_NODE;
13505 case PM_CONSTANT_PATH_NODE:
13506 if (context_def_p(parser)) {
13507 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13511 target->
type = PM_CONSTANT_PATH_TARGET_NODE;
13514 case PM_CONSTANT_READ_NODE:
13515 if (context_def_p(parser)) {
13516 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13520 target->
type = PM_CONSTANT_TARGET_NODE;
13523 case PM_BACK_REFERENCE_READ_NODE:
13524 case PM_NUMBERED_REFERENCE_READ_NODE:
13525 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13527 case PM_GLOBAL_VARIABLE_READ_NODE:
13529 target->
type = PM_GLOBAL_VARIABLE_TARGET_NODE;
13531 case PM_LOCAL_VARIABLE_READ_NODE: {
13534 parse_target_implicit_parameter(parser, target);
13538 uint32_t name = cast->
name;
13539 uint32_t depth = cast->
depth;
13540 pm_locals_unread(&pm_parser_scope_find(parser, depth)->locals, name);
13543 target->
type = PM_LOCAL_VARIABLE_TARGET_NODE;
13547 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
13551 parse_target_implicit_parameter(parser, target);
13552 pm_node_destroy(parser, target);
13556 case PM_INSTANCE_VARIABLE_READ_NODE:
13558 target->
type = PM_INSTANCE_VARIABLE_TARGET_NODE;
13560 case PM_MULTI_TARGET_NODE:
13561 if (splat_parent) {
13564 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13568 case PM_SPLAT_NODE: {
13577 case PM_CALL_NODE: {
13589 (call->
block == NULL)
13604 pm_node_destroy(parser, target);
13606 return (
pm_node_t *) pm_local_variable_target_node_create(parser, &message_loc, name, 0);
13610 if (multiple && PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
13611 pm_parser_err_node(parser, (
const pm_node_t *) call, PM_ERR_UNEXPECTED_SAFE_NAVIGATION);
13614 parse_write_name(parser, &call->
name);
13615 return (
pm_node_t *) pm_call_target_node_create(parser, call);
13622 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
13623 return (
pm_node_t *) pm_index_target_node_create(parser, call);
13631 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13642 pm_node_t *result = parse_target(parser, target, multiple,
false);
13647 !match1(parser, PM_TOKEN_EQUAL) &&
13649 !(context_p(parser,
PM_CONTEXT_PARENS) && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
13651 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13665 if (shareable_constant != PM_SCOPE_SHAREABLE_CONSTANT_NONE) {
13666 return (
pm_node_t *) pm_shareable_constant_node_create(parser, write, shareable_constant);
13677 switch (PM_NODE_TYPE(target)) {
13678 case PM_MISSING_NODE:
13679 pm_node_destroy(parser, value);
13681 case PM_CLASS_VARIABLE_READ_NODE: {
13683 pm_node_destroy(parser, target);
13686 case PM_CONSTANT_PATH_NODE: {
13689 if (context_def_p(parser)) {
13690 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13693 return parse_shareable_constant_write(parser, node);
13695 case PM_CONSTANT_READ_NODE: {
13698 if (context_def_p(parser)) {
13699 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13702 pm_node_destroy(parser, target);
13703 return parse_shareable_constant_write(parser, node);
13705 case PM_BACK_REFERENCE_READ_NODE:
13706 case PM_NUMBERED_REFERENCE_READ_NODE:
13707 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13709 case PM_GLOBAL_VARIABLE_READ_NODE: {
13711 pm_node_destroy(parser, target);
13714 case PM_LOCAL_VARIABLE_READ_NODE: {
13720 uint32_t depth = local_read->
depth;
13721 pm_scope_t *scope = pm_parser_scope_find(parser, depth);
13724 pm_diagnostic_id_t diag_id = (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND) ? PM_ERR_EXPRESSION_NOT_WRITABLE_NUMBERED : PM_ERR_PARAMETER_NUMBERED_RESERVED;
13726 parse_target_implicit_parameter(parser, target);
13729 pm_locals_unread(&scope->
locals, name);
13730 pm_node_destroy(parser, target);
13732 return (
pm_node_t *) pm_local_variable_write_node_create(parser, name, depth, value, &name_loc,
operator);
13734 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
13738 parse_target_implicit_parameter(parser, target);
13739 pm_node_destroy(parser, target);
13743 case PM_INSTANCE_VARIABLE_READ_NODE: {
13745 pm_node_destroy(parser, target);
13748 case PM_MULTI_TARGET_NODE:
13750 case PM_SPLAT_NODE: {
13758 pm_multi_target_node_targets_append(parser, multi_target, (
pm_node_t *) splat);
13760 return (
pm_node_t *) pm_multi_write_node_create(parser, multi_target,
operator, value);
13762 case PM_CALL_NODE: {
13774 (call->
block == NULL)
13788 pm_parser_local_add_location(parser, message.
start, message.
end, 0);
13789 pm_node_destroy(parser, target);
13792 target = (
pm_node_t *) pm_local_variable_write_node_create(parser, constant_id, 0, value, &message,
operator);
13794 pm_refute_numbered_parameter(parser, message.
start, message.
end);
13812 pm_arguments_node_arguments_append(arguments, value);
13814 call->
equal_loc = PM_LOCATION_TOKEN_VALUE(
operator);
13816 parse_write_name(parser, &call->
name);
13817 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));
13826 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
13828 call->
arguments = pm_arguments_node_create(parser);
13831 pm_arguments_node_arguments_append(call->
arguments, value);
13835 call->
name = pm_parser_constant_id_constant(parser,
"[]=", 3);
13836 call->
equal_loc = PM_LOCATION_TOKEN_VALUE(
operator);
13840 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));
13850 pm_node_destroy(parser, value);
13857 pm_parser_err_token(parser,
operator, PM_ERR_WRITE_TARGET_UNEXPECTED);
13870 switch (PM_NODE_TYPE(target)) {
13871 case PM_SOURCE_ENCODING_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13872 case PM_FALSE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13873 case PM_SOURCE_FILE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13874 case PM_SOURCE_LINE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13875 case PM_NIL_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13876 case PM_SELF_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13877 case PM_TRUE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13884 pm_node_destroy(parser, target);
13899parse_targets(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13900 bool has_rest = PM_NODE_TYPE_P(first_target, PM_SPLAT_NODE);
13903 pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target,
true,
false));
13905 while (accept1(parser, PM_TOKEN_COMMA)) {
13906 if (accept1(parser, PM_TOKEN_USTAR)) {
13911 pm_parser_err_previous(parser, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
13917 if (token_begins_expression_p(parser->
current.type)) {
13918 name = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13919 name = parse_target(parser, name,
true,
true);
13922 pm_node_t *splat = (
pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
13923 pm_multi_target_node_targets_append(parser, result, splat);
13925 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
13927 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13928 target = parse_target(parser, target,
true,
false);
13930 pm_multi_target_node_targets_append(parser, result, target);
13931 context_pop(parser);
13932 }
else if (token_begins_expression_p(parser->
current.type)) {
13933 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13934 target = parse_target(parser, target,
true,
false);
13936 pm_multi_target_node_targets_append(parser, result, target);
13937 }
else if (!match1(parser, PM_TOKEN_EOF)) {
13941 pm_multi_target_node_targets_append(parser, result, rest);
13954parse_targets_validate(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13955 pm_node_t *result = parse_targets(parser, first_target, binding_power, depth);
13956 accept1(parser, PM_TOKEN_NEWLINE);
13959 if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
13960 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13973 while (accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE));
13976 if (context_terminator(context, &parser->
current))
return NULL;
13982 context_push(parser, context);
13985 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
13986 pm_statements_node_body_append(parser, statements, node,
true);
13999 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
14002 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
14003 if (context_terminator(context, &parser->
current))
break;
14013 if (context_terminator(context, &parser->
current))
break;
14025 if (PM_NODE_TYPE_P(node, PM_MISSING_NODE)) {
14026 parser_lex(parser);
14032 if (match1(parser, PM_TOKEN_EOF)) {
14037 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
14038 if (context_terminator(context, &parser->
current))
break;
14039 }
else if (!accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_EOF)) {
14049 context_pop(parser);
14050 bool last_value =
true;
14054 last_value =
false;
14059 pm_void_statements_check(parser, statements, last_value);
14072 if (duplicated != NULL) {
14076 pm_diagnostic_list_append_format(
14080 PM_WARN_DUPLICATED_HASH_KEY,
14098 if ((previous = pm_static_literals_add(&parser->
newline_list, parser->
start_line, literals, node,
false)) != NULL) {
14099 pm_diagnostic_list_append_format(
14103 PM_WARN_DUPLICATED_WHEN_CLAUSE,
14115 assert(PM_NODE_TYPE_P(node, PM_HASH_NODE) || PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE));
14116 bool contains_keyword_splat =
false;
14121 switch (parser->
current.type) {
14122 case PM_TOKEN_USTAR_STAR: {
14123 parser_lex(parser);
14127 if (match1(parser, PM_TOKEN_BRACE_LEFT)) {
14133 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
14134 }
else if (token_begins_expression_p(parser->
current.type)) {
14135 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
14137 pm_parser_scope_forwarding_keywords_check(parser, &
operator);
14140 element = (
pm_node_t *) pm_assoc_splat_node_create(parser, value, &
operator);
14141 contains_keyword_splat =
true;
14144 case PM_TOKEN_LABEL: {
14146 parser_lex(parser);
14149 pm_hash_key_static_literals_add(parser, literals, key);
14154 if (token_begins_expression_p(parser->
current.type)) {
14155 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_EXPRESSION_AFTER_LABEL, (uint16_t) (depth + 1));
14158 pm_token_t constant = { .type = PM_TOKEN_CONSTANT, .start = label.
start, .end = label.
end - 1 };
14159 value = (
pm_node_t *) pm_constant_read_node_create(parser, &constant);
14164 if (identifier.
end[-1] ==
'!' || identifier.
end[-1] ==
'?') {
14165 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, identifier, PM_ERR_INVALID_LOCAL_VARIABLE_READ);
14167 depth = pm_parser_local_depth(parser, &identifier);
14171 value = (
pm_node_t *) pm_call_node_variable_call_create(parser, &identifier);
14173 value = (
pm_node_t *) pm_local_variable_read_node_create(parser, &identifier, (uint32_t) depth);
14178 value = (
pm_node_t *) pm_implicit_node_create(parser, value);
14181 element = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
14185 pm_node_t *key = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_HASH_KEY, (uint16_t) (depth + 1));
14189 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
14190 pm_node_flag_set(key, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
14193 pm_hash_key_static_literals_add(parser, literals, key);
14196 if (pm_symbol_node_label_p(key)) {
14197 operator = not_provided(parser);
14199 expect1(parser, PM_TOKEN_EQUAL_GREATER, PM_ERR_HASH_ROCKET);
14203 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
14204 element = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
14209 if (PM_NODE_TYPE_P(node, PM_HASH_NODE)) {
14216 if (!accept1(parser, PM_TOKEN_COMMA))
break;
14220 if (match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL))
continue;
14224 if (token_begins_expression_p(parser->
current.type))
continue;
14230 return contains_keyword_splat;
14239 arguments->
arguments = pm_arguments_node_create(parser);
14242 pm_arguments_node_arguments_append(arguments->
arguments, argument);
14249parse_arguments(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_forwarding, pm_token_type_t terminator, uint16_t depth) {
14250 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].
left;
14255 match2(parser, terminator, PM_TOKEN_EOF) ||
14256 (binding_power != PM_BINDING_POWER_UNSET && binding_power < PM_BINDING_POWER_RANGE) ||
14262 bool parsed_first_argument =
false;
14263 bool parsed_bare_hash =
false;
14264 bool parsed_block_argument =
false;
14265 bool parsed_forwarding_arguments =
false;
14267 while (!match1(parser, PM_TOKEN_EOF)) {
14268 if (parsed_forwarding_arguments) {
14269 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES);
14274 switch (parser->
current.type) {
14275 case PM_TOKEN_USTAR_STAR:
14276 case PM_TOKEN_LABEL: {
14277 if (parsed_bare_hash) {
14278 pm_parser_err_current(parser, PM_ERR_ARGUMENT_BARE_HASH);
14285 bool contains_keyword_splat = parse_assocs(parser, &hash_keys, (
pm_node_t *) hash, (uint16_t) (depth + 1));
14287 parse_arguments_append(parser, arguments, argument);
14289 pm_node_flags_t flags = PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
14290 if (contains_keyword_splat) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
14293 pm_static_literals_free(&hash_keys);
14294 parsed_bare_hash =
true;
14298 case PM_TOKEN_UAMPERSAND: {
14299 parser_lex(parser);
14303 if (token_begins_expression_p(parser->
current.type)) {
14304 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14306 pm_parser_scope_forwarding_block_check(parser, &
operator);
14309 argument = (
pm_node_t *) pm_block_argument_node_create(parser, &
operator, expression);
14310 if (parsed_block_argument) {
14311 parse_arguments_append(parser, arguments, argument);
14313 arguments->
block = argument;
14316 if (match1(parser, PM_TOKEN_COMMA)) {
14317 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK);
14320 parsed_block_argument =
true;
14323 case PM_TOKEN_USTAR: {
14324 parser_lex(parser);
14327 if (match4(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_SEMICOLON, PM_TOKEN_BRACKET_RIGHT)) {
14328 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
14329 argument = (
pm_node_t *) pm_splat_node_create(parser, &
operator, NULL);
14330 if (parsed_bare_hash) {
14331 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
14334 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT, (uint16_t) (depth + 1));
14336 if (parsed_bare_hash) {
14337 pm_parser_err(parser,
operator.start, expression->
location.
end, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
14340 argument = (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
14343 parse_arguments_append(parser, arguments, argument);
14346 case PM_TOKEN_UDOT_DOT_DOT: {
14347 if (accepts_forwarding) {
14348 parser_lex(parser);
14350 if (token_begins_expression_p(parser->
current.type)) {
14355 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_RANGE,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
14360 if (PM_NODE_TYPE_P(right, PM_RANGE_NODE)) {
14362 pm_parser_err(parser, range->operator_loc.start, range->operator_loc.end, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
14365 argument = (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
14367 pm_parser_scope_forwarding_all_check(parser, &parser->
previous);
14368 if (parsed_first_argument && terminator == PM_TOKEN_EOF) {
14369 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORWARDING_UNBOUND);
14372 argument = (
pm_node_t *) pm_forwarding_arguments_node_create(parser, &parser->
previous);
14373 parse_arguments_append(parser, arguments, argument);
14374 pm_node_flag_set((
pm_node_t *) arguments->
arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING);
14376 parsed_forwarding_arguments =
true;
14383 if (argument == NULL) {
14384 argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, !parsed_first_argument,
true, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14387 bool contains_keywords =
false;
14388 bool contains_keyword_splat =
false;
14390 if (pm_symbol_node_label_p(argument) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
14391 if (parsed_bare_hash) {
14392 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
14396 if (parser->
previous.
type == PM_TOKEN_EQUAL_GREATER) {
14399 operator = not_provided(parser);
14403 contains_keywords =
true;
14407 pm_hash_key_static_literals_add(parser, &hash_keys, argument);
14410 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
14411 argument = (
pm_node_t *) pm_assoc_node_create(parser, argument, &
operator, value);
14413 pm_keyword_hash_node_elements_append(bare_hash, argument);
14417 if (accept1(parser, PM_TOKEN_COMMA) && (
14418 token_begins_expression_p(parser->
current.type) ||
14419 match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL)
14421 contains_keyword_splat = parse_assocs(parser, &hash_keys, (
pm_node_t *) bare_hash, (uint16_t) (depth + 1));
14424 pm_static_literals_free(&hash_keys);
14425 parsed_bare_hash =
true;
14428 parse_arguments_append(parser, arguments, argument);
14430 pm_node_flags_t flags = 0;
14431 if (contains_keywords) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
14432 if (contains_keyword_splat) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
14439 parsed_first_argument =
true;
14442 if (PM_NODE_TYPE_P(argument, PM_MISSING_NODE) || parser->
recovering)
break;
14447 bool accepted_newline =
false;
14448 if (terminator != PM_TOKEN_EOF) {
14449 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
14452 if (parser->
previous.
type == PM_TOKEN_COMMA && parsed_bare_hash) {
14456 }
else if (accept1(parser, PM_TOKEN_COMMA)) {
14459 if (accepted_newline) {
14460 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14466 if (PM_NODE_TYPE_P(argument, PM_CALL_NODE)) {
14469 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14481 if (match1(parser, terminator))
break;
14496parse_required_destructured_parameter(
pm_parser_t *parser) {
14497 expect1(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_ERR_EXPECT_LPAREN_REQ_PARAMETER);
14500 pm_multi_target_node_opening_set(node, &parser->
previous);
14509 if (node->
lefts.
size > 0 && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
14511 pm_multi_target_node_targets_append(parser, node, param);
14512 pm_parser_err_current(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14516 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
14517 param = (
pm_node_t *) parse_required_destructured_parameter(parser);
14518 }
else if (accept1(parser, PM_TOKEN_USTAR)) {
14522 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14524 value = (
pm_node_t *) pm_required_parameter_node_create(parser, &name);
14525 if (pm_parser_parameter_name_check(parser, &name)) {
14526 pm_node_flag_set_repeated_parameter(value);
14528 pm_parser_local_add_token(parser, &name, 1);
14531 param = (
pm_node_t *) pm_splat_node_create(parser, &star, value);
14533 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EXPECT_IDENT_REQ_PARAMETER);
14536 param = (
pm_node_t *) pm_required_parameter_node_create(parser, &name);
14537 if (pm_parser_parameter_name_check(parser, &name)) {
14538 pm_node_flag_set_repeated_parameter(param);
14540 pm_parser_local_add_token(parser, &name, 1);
14543 pm_multi_target_node_targets_append(parser, node, param);
14544 }
while (accept1(parser, PM_TOKEN_COMMA));
14546 accept1(parser, PM_TOKEN_NEWLINE);
14547 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN_REQ_PARAMETER);
14548 pm_multi_target_node_closing_set(node, &parser->
previous);
14558 PM_PARAMETERS_NO_CHANGE = 0,
14559 PM_PARAMETERS_ORDER_NOTHING_AFTER = 1,
14560 PM_PARAMETERS_ORDER_KEYWORDS_REST,
14561 PM_PARAMETERS_ORDER_KEYWORDS,
14562 PM_PARAMETERS_ORDER_REST,
14563 PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14564 PM_PARAMETERS_ORDER_OPTIONAL,
14565 PM_PARAMETERS_ORDER_NAMED,
14566 PM_PARAMETERS_ORDER_NONE,
14567} pm_parameters_order_t;
14572static pm_parameters_order_t parameters_ordering[PM_TOKEN_MAXIMUM] = {
14573 [0] = PM_PARAMETERS_NO_CHANGE,
14574 [PM_TOKEN_UAMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14575 [PM_TOKEN_AMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14576 [PM_TOKEN_UDOT_DOT_DOT] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14577 [PM_TOKEN_IDENTIFIER] = PM_PARAMETERS_ORDER_NAMED,
14578 [PM_TOKEN_PARENTHESIS_LEFT] = PM_PARAMETERS_ORDER_NAMED,
14579 [PM_TOKEN_EQUAL] = PM_PARAMETERS_ORDER_OPTIONAL,
14580 [PM_TOKEN_LABEL] = PM_PARAMETERS_ORDER_KEYWORDS,
14581 [PM_TOKEN_USTAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14582 [PM_TOKEN_STAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14583 [PM_TOKEN_USTAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST,
14584 [PM_TOKEN_STAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST
14596 pm_parameters_order_t state = parameters_ordering[token->type];
14597 if (state == PM_PARAMETERS_NO_CHANGE)
return true;
14601 if (*current == PM_PARAMETERS_ORDER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14602 *current = PM_PARAMETERS_ORDER_AFTER_OPTIONAL;
14604 }
else if (*current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14608 if (token->type == PM_TOKEN_USTAR && *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14609 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_STAR);
14611 }
else if (token->type == PM_TOKEN_UDOT_DOT_DOT && (*current >= PM_PARAMETERS_ORDER_KEYWORDS_REST && *current <= PM_PARAMETERS_ORDER_AFTER_OPTIONAL)) {
14612 pm_parser_err_token(parser, token, *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL ? PM_ERR_PARAMETER_FORWARDING_AFTER_REST : PM_ERR_PARAMETER_ORDER);
14614 }
else if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
14616 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_ORDER);
14620 if (state < *current) *current = state;
14631 if (match1(parser, PM_TOKEN_EQUAL)) {
14632 pm_parser_err_previous(parser, PM_ERR_DEF_ENDLESS_PARAMETERS);
14642 pm_binding_power_t binding_power,
14643 bool uses_parentheses,
14644 bool allows_trailing_comma,
14645 bool allows_forwarding_parameters,
14646 bool accepts_blocks_in_defaults,
14650 pm_do_loop_stack_push(parser,
false);
14653 pm_parameters_order_t order = PM_PARAMETERS_ORDER_NONE;
14656 bool parsing =
true;
14658 switch (parser->
current.type) {
14659 case PM_TOKEN_PARENTHESIS_LEFT: {
14660 update_parameter_state(parser, &parser->
current, &order);
14663 if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14664 pm_parameters_node_requireds_append(params, param);
14666 pm_parameters_node_posts_append(params, param);
14670 case PM_TOKEN_UAMPERSAND:
14671 case PM_TOKEN_AMPERSAND: {
14672 update_parameter_state(parser, &parser->
current, &order);
14673 parser_lex(parser);
14678 bool repeated =
false;
14679 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14681 repeated = pm_parser_parameter_name_check(parser, &name);
14682 pm_parser_local_add_token(parser, &name, 1);
14684 name = not_provided(parser);
14688 if (!uses_parentheses) {
14689 refute_optional_parameter(parser);
14694 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14696 if (params->
block == NULL) {
14697 pm_parameters_node_block_set(params, param);
14699 pm_parser_err_node(parser, (
pm_node_t *) param, PM_ERR_PARAMETER_BLOCK_MULTI);
14700 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14705 case PM_TOKEN_UDOT_DOT_DOT: {
14706 if (!allows_forwarding_parameters) {
14707 pm_parser_err_current(parser, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
14710 bool succeeded = update_parameter_state(parser, &parser->
current, &order);
14711 parser_lex(parser);
14713 if (!uses_parentheses) {
14714 refute_optional_parameter(parser);
14724 pm_parameters_node_posts_append(params, keyword_rest);
14725 if (succeeded) pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD);
14729 pm_parameters_node_keyword_rest_set(params, (
pm_node_t *) param);
14732 case PM_TOKEN_CLASS_VARIABLE:
14733 case PM_TOKEN_IDENTIFIER:
14734 case PM_TOKEN_CONSTANT:
14735 case PM_TOKEN_INSTANCE_VARIABLE:
14736 case PM_TOKEN_GLOBAL_VARIABLE:
14737 case PM_TOKEN_METHOD_NAME: {
14738 parser_lex(parser);
14740 case PM_TOKEN_CONSTANT:
14741 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14743 case PM_TOKEN_INSTANCE_VARIABLE:
14744 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
14746 case PM_TOKEN_GLOBAL_VARIABLE:
14747 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
14749 case PM_TOKEN_CLASS_VARIABLE:
14750 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
14752 case PM_TOKEN_METHOD_NAME:
14753 pm_parser_err_previous(parser, PM_ERR_PARAMETER_METHOD_NAME);
14758 if (parser->
current.type == PM_TOKEN_EQUAL) {
14759 update_parameter_state(parser, &parser->
current, &order);
14761 update_parameter_state(parser, &parser->
previous, &order);
14765 bool repeated = pm_parser_parameter_name_check(parser, &name);
14766 pm_parser_local_add_token(parser, &name, 1);
14768 if (match1(parser, PM_TOKEN_EQUAL)) {
14771 parser_lex(parser);
14776 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14777 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
14778 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14783 pm_node_flag_set_repeated_parameter((
pm_node_t *) param);
14785 pm_parameters_node_optionals_append(params, param);
14791 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, name, PM_ERR_PARAMETER_CIRCULAR);
14794 context_pop(parser);
14803 }
else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14806 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14808 pm_parameters_node_requireds_append(params, (
pm_node_t *) param);
14812 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14814 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14819 case PM_TOKEN_LABEL: {
14820 if (!uses_parentheses && !in_block) parser->
in_keyword_arg =
true;
14821 update_parameter_state(parser, &parser->
current, &order);
14824 parser_lex(parser);
14831 pm_parser_err(parser, local.
start, local.
end, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14832 }
else if (local.
end[-1] ==
'!' || local.
end[-1] ==
'?') {
14833 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
14836 bool repeated = pm_parser_parameter_name_check(parser, &local);
14837 pm_parser_local_add_token(parser, &local, 1);
14839 switch (parser->
current.type) {
14840 case PM_TOKEN_COMMA:
14841 case PM_TOKEN_PARENTHESIS_RIGHT:
14842 case PM_TOKEN_PIPE: {
14843 context_pop(parser);
14845 pm_node_t *param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14847 pm_node_flag_set_repeated_parameter(param);
14850 pm_parameters_node_keywords_append(params, param);
14853 case PM_TOKEN_SEMICOLON:
14854 case PM_TOKEN_NEWLINE: {
14855 context_pop(parser);
14857 if (uses_parentheses) {
14862 pm_node_t *param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14864 pm_node_flag_set_repeated_parameter(param);
14867 pm_parameters_node_keywords_append(params, param);
14873 if (token_begins_expression_p(parser->
current.type)) {
14877 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14878 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT_KW, (uint16_t) (depth + 1));
14879 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14882 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_PARAMETER_CIRCULAR);
14885 param = (
pm_node_t *) pm_optional_keyword_parameter_node_create(parser, &name, value);
14888 param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14892 pm_node_flag_set_repeated_parameter(param);
14895 context_pop(parser);
14896 pm_parameters_node_keywords_append(params, param);
14898 if (!uses_parentheses) {
14899 refute_optional_parameter(parser);
14915 case PM_TOKEN_USTAR:
14916 case PM_TOKEN_STAR: {
14917 update_parameter_state(parser, &parser->
current, &order);
14918 parser_lex(parser);
14922 bool repeated =
false;
14924 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14926 repeated = pm_parser_parameter_name_check(parser, &name);
14927 pm_parser_local_add_token(parser, &name, 1);
14929 name = not_provided(parser);
14933 if (!uses_parentheses) {
14934 refute_optional_parameter(parser);
14937 pm_node_t *param = (
pm_node_t *) pm_rest_parameter_node_create(parser, &
operator, &name);
14939 pm_node_flag_set_repeated_parameter(param);
14942 if (params->
rest == NULL) {
14943 pm_parameters_node_rest_set(params, param);
14945 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_SPLAT_MULTI);
14946 pm_parameters_node_posts_append(params, param);
14951 case PM_TOKEN_STAR_STAR:
14952 case PM_TOKEN_USTAR_STAR: {
14953 pm_parameters_order_t previous_order = order;
14954 update_parameter_state(parser, &parser->
current, &order);
14955 parser_lex(parser);
14960 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
14961 if (previous_order <= PM_PARAMETERS_ORDER_KEYWORDS) {
14962 pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_NO_KW);
14965 param = (
pm_node_t *) pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous);
14969 bool repeated =
false;
14970 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14972 repeated = pm_parser_parameter_name_check(parser, &name);
14973 pm_parser_local_add_token(parser, &name, 1);
14975 name = not_provided(parser);
14979 param = (
pm_node_t *) pm_keyword_rest_parameter_node_create(parser, &
operator, &name);
14981 pm_node_flag_set_repeated_parameter(param);
14985 if (!uses_parentheses) {
14986 refute_optional_parameter(parser);
14990 pm_parameters_node_keyword_rest_set(params, param);
14992 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI);
14993 pm_parameters_node_posts_append(params, param);
15000 if (allows_trailing_comma && order >= PM_PARAMETERS_ORDER_NAMED) {
15005 if (params->
rest == NULL) {
15006 pm_parameters_node_rest_set(params, param);
15008 pm_parser_err_node(parser, (
pm_node_t *) param, PM_ERR_PARAMETER_SPLAT_MULTI);
15009 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
15012 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
15023 if (!parsing)
break;
15025 bool accepted_newline =
false;
15026 if (uses_parentheses) {
15027 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
15030 if (accept1(parser, PM_TOKEN_COMMA)) {
15033 if (accepted_newline) {
15034 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
15042 pm_do_loop_stack_pop(parser);
15046 pm_node_destroy(parser, (
pm_node_t *) params);
15078token_column(
const pm_parser_t *parser,
size_t newline_index,
const pm_token_t *token,
bool break_on_non_space) {
15080 const uint8_t *end = token->start;
15084 newline_index == 0 &&
15085 parser->
start[0] == 0xef &&
15086 parser->
start[1] == 0xbb &&
15087 parser->
start[2] == 0xbf
15090 int64_t column = 0;
15091 for (; cursor < end; cursor++) {
15094 column = ((column / PM_TAB_WHITESPACE_SIZE) + 1) * PM_TAB_WHITESPACE_SIZE;
15101 if (break_on_non_space)
return -1;
15114parser_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) {
15119 size_t closing_newline_index = token_newline_index(parser);
15120 if (opening_newline_index == closing_newline_index)
return;
15125 int64_t opening_column = token_column(parser, opening_newline_index, opening_token, !if_after_else);
15126 if (!if_after_else && (opening_column == -1))
return;
15133 int64_t closing_column = token_column(parser, closing_newline_index, closing_token,
true);
15134 if ((closing_column == -1) || (opening_column == closing_column))
return;
15138 if (allow_indent && (closing_column > opening_column))
return;
15141 PM_PARSER_WARN_FORMAT(
15143 closing_token->
start,
15144 closing_token->
end,
15145 PM_WARN_INDENTATION_MISMATCH,
15146 (
int) (closing_token->
end - closing_token->
start),
15147 (
const char *) closing_token->
start,
15148 (
int) (opening_token->
end - opening_token->
start),
15149 (
const char *) opening_token->
start,
15150 ((int32_t) opening_newline_index) + parser->
start_line
15155 PM_RESCUES_BEGIN = 1,
15162} pm_rescues_type_t;
15172 while (match1(parser, PM_TOKEN_KEYWORD_RESCUE)) {
15173 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15174 parser_lex(parser);
15178 switch (parser->
current.type) {
15179 case PM_TOKEN_EQUAL_GREATER: {
15183 parser_lex(parser);
15184 pm_rescue_node_operator_set(rescue, &parser->
previous);
15186 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15187 reference = parse_target(parser, reference,
false,
false);
15189 pm_rescue_node_reference_set(rescue, reference);
15192 case PM_TOKEN_NEWLINE:
15193 case PM_TOKEN_SEMICOLON:
15194 case PM_TOKEN_KEYWORD_THEN:
15199 if (token_begins_expression_p(parser->
current.type) || match1(parser, PM_TOKEN_USTAR)) {
15204 pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED,
false, PM_ERR_RESCUE_EXPRESSION, (uint16_t) (depth + 1));
15205 pm_rescue_node_exceptions_append(rescue, expression);
15209 if (match3(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_THEN))
break;
15213 if (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
15214 pm_rescue_node_operator_set(rescue, &parser->
previous);
15216 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15217 reference = parse_target(parser, reference,
false,
false);
15219 pm_rescue_node_reference_set(rescue, reference);
15222 }
while (accept1(parser, PM_TOKEN_COMMA));
15227 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
15228 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
15232 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_RESCUE_TERM);
15236 if (!match3(parser, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_END)) {
15237 pm_accepts_block_stack_push(parser,
true);
15252 if (statements != NULL) pm_rescue_node_statements_set(rescue, statements);
15254 pm_accepts_block_stack_pop(parser);
15255 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15258 if (current == NULL) {
15259 pm_begin_node_rescue_clause_set(parent_node, rescue);
15261 pm_rescue_node_subsequent_set(current, rescue);
15270 if (current != NULL) {
15274 while (clause != NULL) {
15281 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
15282 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15283 opening_newline_index = token_newline_index(parser);
15285 else_keyword = parser->
current;
15286 opening = &else_keyword;
15288 parser_lex(parser);
15289 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15292 if (!match2(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_ENSURE)) {
15293 pm_accepts_block_stack_push(parser,
true);
15307 else_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15308 pm_accepts_block_stack_pop(parser);
15310 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15313 pm_else_node_t *else_clause = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
current);
15314 pm_begin_node_else_clause_set(parent_node, else_clause);
15318 if (current == NULL) pm_parser_err_node(parser, (
pm_node_t *) else_clause, PM_ERR_BEGIN_LONELY_ELSE);
15321 if (match1(parser, PM_TOKEN_KEYWORD_ENSURE)) {
15322 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15325 parser_lex(parser);
15326 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15329 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
15330 pm_accepts_block_stack_push(parser,
true);
15344 ensure_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15345 pm_accepts_block_stack_pop(parser);
15347 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15350 pm_ensure_node_t *ensure_clause = pm_ensure_node_create(parser, &ensure_keyword, ensure_statements, &parser->
current);
15351 pm_begin_node_ensure_clause_set(parent_node, ensure_clause);
15354 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
15355 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15356 pm_begin_node_end_keyword_set(parent_node, &parser->
current);
15359 pm_begin_node_end_keyword_set(parent_node, &end_keyword);
15369 pm_token_t begin_keyword = not_provided(parser);
15370 pm_begin_node_t *node = pm_begin_node_create(parser, &begin_keyword, statements);
15372 parse_rescues(parser, opening_newline_index, opening, node,
type, (uint16_t) (depth + 1));
15382parse_block_parameters(
15384 bool allows_trailing_comma,
15386 bool is_lambda_literal,
15387 bool accepts_blocks_in_defaults,
15391 if (!match1(parser, PM_TOKEN_SEMICOLON)) {
15392 parameters = parse_parameters(
15394 is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
15396 allows_trailing_comma,
15398 accepts_blocks_in_defaults,
15400 (uint16_t) (depth + 1)
15405 if ((opening->
type != PM_TOKEN_NOT_PROVIDED)) {
15406 accept1(parser, PM_TOKEN_NEWLINE);
15408 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
15410 switch (parser->
current.type) {
15411 case PM_TOKEN_CONSTANT:
15412 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
15413 parser_lex(parser);
15415 case PM_TOKEN_INSTANCE_VARIABLE:
15416 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
15417 parser_lex(parser);
15419 case PM_TOKEN_GLOBAL_VARIABLE:
15420 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
15421 parser_lex(parser);
15423 case PM_TOKEN_CLASS_VARIABLE:
15424 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
15425 parser_lex(parser);
15428 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_BLOCK_PARAM_LOCAL_VARIABLE);
15432 bool repeated = pm_parser_parameter_name_check(parser, &parser->
previous);
15433 pm_parser_local_add_token(parser, &parser->
previous, 1);
15436 if (repeated) pm_node_flag_set_repeated_parameter((
pm_node_t *) local);
15438 pm_block_parameters_node_append_local(block_parameters, local);
15439 }
while (accept1(parser, PM_TOKEN_COMMA));
15443 return block_parameters;
15451outer_scope_using_numbered_parameters_p(
pm_parser_t *parser) {
15453 if (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND)
return true;
15464static const char *
const pm_numbered_parameter_names[] = {
15465 "_1",
"_2",
"_3",
"_4",
"_5",
"_6",
"_7",
"_8",
"_9"
15479 if (parameters != NULL) {
15481 if (implicit_parameters->
size > 0) {
15484 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
15485 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_ORDINARY);
15486 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
15487 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_ORDINARY);
15489 assert(
false &&
"unreachable");
15498 if (implicit_parameters->
size == 0) {
15505 uint8_t numbered_parameter = 0;
15506 bool it_parameter =
false;
15508 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
15511 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
15512 if (it_parameter) {
15513 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_IT);
15514 }
else if (outer_scope_using_numbered_parameters_p(parser)) {
15515 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_OUTER_BLOCK);
15517 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK);
15519 numbered_parameter = MAX(numbered_parameter, (uint8_t) (node->
location.
start[1] -
'0'));
15521 assert(
false &&
"unreachable");
15523 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
15524 if (numbered_parameter > 0) {
15525 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_NUMBERED);
15527 it_parameter =
true;
15532 if (numbered_parameter > 0) {
15536 scope->
parameters |= PM_SCOPE_PARAMETERS_NUMBERED_INNER;
15540 return (
pm_node_t *) pm_numbered_parameters_node_create(parser, &location, numbered_parameter);
15543 if (it_parameter) {
15544 return (
pm_node_t *) pm_it_parameters_node_create(parser, opening, closing);
15554parse_block(
pm_parser_t *parser, uint16_t depth) {
15556 accept1(parser, PM_TOKEN_NEWLINE);
15558 pm_accepts_block_stack_push(parser,
true);
15559 pm_parser_scope_push(parser,
false);
15563 if (accept1(parser, PM_TOKEN_PIPE)) {
15565 if (match1(parser, PM_TOKEN_PIPE)) {
15566 block_parameters = pm_block_parameters_node_create(parser, NULL, &block_parameters_opening);
15568 parser_lex(parser);
15570 block_parameters = parse_block_parameters(parser,
true, &block_parameters_opening,
false,
true, (uint16_t) (depth + 1));
15571 accept1(parser, PM_TOKEN_NEWLINE);
15573 expect1(parser, PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM);
15576 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
15579 accept1(parser, PM_TOKEN_NEWLINE);
15582 if (opening.
type == PM_TOKEN_BRACE_LEFT) {
15583 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
15587 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE);
15589 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
15590 if (!match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE)) {
15591 pm_accepts_block_stack_push(parser,
true);
15593 pm_accepts_block_stack_pop(parser);
15596 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
15597 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
15598 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));
15602 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END);
15606 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
15609 pm_parser_scope_pop(parser);
15610 pm_accepts_block_stack_pop(parser);
15612 return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->
previous);
15621parse_arguments_list(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_block,
bool accepts_command_call, uint16_t depth) {
15622 bool found =
false;
15624 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
15628 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
15631 pm_accepts_block_stack_push(parser,
true);
15632 parse_arguments(parser, arguments, accepts_block, PM_TOKEN_PARENTHESIS_RIGHT, (uint16_t) (depth + 1));
15634 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
15640 pm_accepts_block_stack_pop(parser);
15643 }
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)) {
15645 pm_accepts_block_stack_push(parser,
false);
15650 parse_arguments(parser, arguments, accepts_block, PM_TOKEN_EOF, (uint16_t) (depth + 1));
15655 if (parser->
previous.
type == PM_TOKEN_COMMA && !match1(parser, PM_TOKEN_SEMICOLON)) {
15659 pm_accepts_block_stack_pop(parser);
15665 if (accepts_block) {
15668 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
15670 block = parse_block(parser, (uint16_t) (depth + 1));
15671 pm_arguments_validate_block(parser, arguments, block);
15672 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
15674 block = parse_block(parser, (uint16_t) (depth + 1));
15677 if (block != NULL) {
15681 pm_parser_err_node(parser, (
pm_node_t *) block, PM_ERR_ARGUMENT_BLOCK_MULTI);
15683 if (arguments->
block != NULL) {
15685 arguments->
arguments = pm_arguments_node_create(parser);
15687 pm_arguments_node_arguments_append(arguments->
arguments, arguments->
block);
15703 bool in_sclass =
false;
15705 switch (context_node->
context) {
15750 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15772 assert(
false &&
"unreachable");
15777 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15788 switch (context_node->
context) {
15862 assert(
false &&
"unreachable");
15876 return previous_block_exits;
15890 switch (PM_NODE_TYPE(block_exit)) {
15891 case PM_BREAK_NODE:
type =
"break";
break;
15892 case PM_NEXT_NODE:
type =
"next";
break;
15893 case PM_REDO_NODE:
type =
"redo";
break;
15894 default: assert(
false &&
"unreachable");
type =
"";
break;
15897 PM_PARSER_ERR_NODE_FORMAT(parser, block_exit, PM_ERR_INVALID_BLOCK_EXIT,
type);
15909 if (match2(parser, PM_TOKEN_KEYWORD_WHILE_MODIFIER, PM_TOKEN_KEYWORD_UNTIL_MODIFIER)) {
15914 }
else if (previous_block_exits != NULL) {
15926 flush_block_exits(parser, previous_block_exits);
15934 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, error_id, (uint16_t) (depth + 1));
15937 bool predicate_closed = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15939 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
15940 predicate_closed =
true;
15944 if (!predicate_closed) {
15945 pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
15948 context_pop(parser);
15953parse_conditional(
pm_parser_t *parser,
pm_context_t context,
size_t opening_newline_index,
bool if_after_else, uint16_t depth) {
15955 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
15958 pm_token_t then_keyword = not_provided(parser);
15960 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context, &then_keyword, (uint16_t) (depth + 1));
15963 if (!match3(parser, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
15964 pm_accepts_block_stack_push(parser,
true);
15965 statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15966 pm_accepts_block_stack_pop(parser);
15967 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15970 pm_token_t end_keyword = not_provided(parser);
15975 parent = (
pm_node_t *) pm_if_node_create(parser, &keyword, predicate, &then_keyword, statements, NULL, &end_keyword);
15978 parent = (
pm_node_t *) pm_unless_node_create(parser, &keyword, predicate, &then_keyword, statements);
15981 assert(
false &&
"unreachable");
15990 while (match1(parser, PM_TOKEN_KEYWORD_ELSIF)) {
15991 if (parser_end_of_line_p(parser)) {
15992 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
15995 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15997 parser_lex(parser);
15999 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER,
PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1));
16000 pm_accepts_block_stack_push(parser,
true);
16003 pm_accepts_block_stack_pop(parser);
16004 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
16006 pm_node_t *elsif = (
pm_node_t *) pm_if_node_create(parser, &elsif_keyword, predicate, &then_keyword, statements, NULL, &end_keyword);
16012 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
16013 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
16014 opening_newline_index = token_newline_index(parser);
16016 parser_lex(parser);
16019 pm_accepts_block_stack_push(parser,
true);
16021 pm_accepts_block_stack_pop(parser);
16023 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
16024 parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword,
false,
false);
16025 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE);
16027 pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
previous);
16037 assert(
false &&
"unreachable");
16041 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else,
false);
16042 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM);
16049 bool recursing =
true;
16051 while (recursing) {
16052 switch (PM_NODE_TYPE(current)) {
16056 recursing = current != NULL;
16074 assert(
false &&
"unreachable");
16078 pop_block_exits(parser, previous_block_exits);
16079 pm_node_list_free(¤t_block_exits);
16088#define PM_CASE_KEYWORD PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
16089 case PM_TOKEN_KEYWORD_ALIAS: case PM_TOKEN_KEYWORD_AND: case PM_TOKEN_KEYWORD_BEGIN: case PM_TOKEN_KEYWORD_BEGIN_UPCASE: \
16090 case PM_TOKEN_KEYWORD_BREAK: case PM_TOKEN_KEYWORD_CASE: case PM_TOKEN_KEYWORD_CLASS: case PM_TOKEN_KEYWORD_DEF: \
16091 case PM_TOKEN_KEYWORD_DEFINED: case PM_TOKEN_KEYWORD_DO: case PM_TOKEN_KEYWORD_DO_LOOP: case PM_TOKEN_KEYWORD_ELSE: \
16092 case PM_TOKEN_KEYWORD_ELSIF: case PM_TOKEN_KEYWORD_END: case PM_TOKEN_KEYWORD_END_UPCASE: case PM_TOKEN_KEYWORD_ENSURE: \
16093 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD_FOR: case PM_TOKEN_KEYWORD_IF: case PM_TOKEN_KEYWORD_IN: \
16094 case PM_TOKEN_KEYWORD_MODULE: case PM_TOKEN_KEYWORD_NEXT: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_NOT: \
16095 case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_KEYWORD_REDO: case PM_TOKEN_KEYWORD_RESCUE: case PM_TOKEN_KEYWORD_RETRY: \
16096 case PM_TOKEN_KEYWORD_RETURN: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_SUPER: case PM_TOKEN_KEYWORD_THEN: \
16097 case PM_TOKEN_KEYWORD_TRUE: case PM_TOKEN_KEYWORD_UNDEF: case PM_TOKEN_KEYWORD_UNLESS: case PM_TOKEN_KEYWORD_UNTIL: \
16098 case PM_TOKEN_KEYWORD_WHEN: case PM_TOKEN_KEYWORD_WHILE: case PM_TOKEN_KEYWORD_YIELD
16104#define PM_CASE_OPERATOR PM_TOKEN_AMPERSAND: case PM_TOKEN_BACKTICK: case PM_TOKEN_BANG_EQUAL: \
16105 case PM_TOKEN_BANG_TILDE: case PM_TOKEN_BANG: case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL: \
16106 case PM_TOKEN_BRACKET_LEFT_RIGHT: case PM_TOKEN_CARET: case PM_TOKEN_EQUAL_EQUAL_EQUAL: case PM_TOKEN_EQUAL_EQUAL: \
16107 case PM_TOKEN_EQUAL_TILDE: case PM_TOKEN_GREATER_EQUAL: case PM_TOKEN_GREATER_GREATER: case PM_TOKEN_GREATER: \
16108 case PM_TOKEN_LESS_EQUAL_GREATER: case PM_TOKEN_LESS_EQUAL: case PM_TOKEN_LESS_LESS: case PM_TOKEN_LESS: \
16109 case PM_TOKEN_MINUS: case PM_TOKEN_PERCENT: case PM_TOKEN_PIPE: case PM_TOKEN_PLUS: case PM_TOKEN_SLASH: \
16110 case PM_TOKEN_STAR_STAR: case PM_TOKEN_STAR: case PM_TOKEN_TILDE: case PM_TOKEN_UAMPERSAND: case PM_TOKEN_UMINUS: \
16111 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_UPLUS: case PM_TOKEN_USTAR: case PM_TOKEN_USTAR_STAR
16118#define PM_CASE_PRIMITIVE PM_TOKEN_INTEGER: case PM_TOKEN_INTEGER_IMAGINARY: case PM_TOKEN_INTEGER_RATIONAL: \
16119 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: case PM_TOKEN_FLOAT: case PM_TOKEN_FLOAT_IMAGINARY: \
16120 case PM_TOKEN_FLOAT_RATIONAL: case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY: case PM_TOKEN_SYMBOL_BEGIN: \
16121 case PM_TOKEN_REGEXP_BEGIN: case PM_TOKEN_BACKTICK: case PM_TOKEN_PERCENT_LOWER_X: case PM_TOKEN_PERCENT_LOWER_I: \
16122 case PM_TOKEN_PERCENT_LOWER_W: case PM_TOKEN_PERCENT_UPPER_I: case PM_TOKEN_PERCENT_UPPER_W: \
16123 case PM_TOKEN_STRING_BEGIN: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_TRUE: \
16124 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
16125 case PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_MINUS_GREATER: case PM_TOKEN_HEREDOC_START: \
16126 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_CHARACTER_LITERAL
16132#define PM_CASE_PARAMETER PM_TOKEN_UAMPERSAND: case PM_TOKEN_AMPERSAND: case PM_TOKEN_UDOT_DOT_DOT: \
16133 case PM_TOKEN_IDENTIFIER: case PM_TOKEN_LABEL: case PM_TOKEN_USTAR: case PM_TOKEN_STAR: case PM_TOKEN_STAR_STAR: \
16134 case PM_TOKEN_USTAR_STAR: case PM_TOKEN_CONSTANT: case PM_TOKEN_INSTANCE_VARIABLE: case PM_TOKEN_GLOBAL_VARIABLE: \
16135 case PM_TOKEN_CLASS_VARIABLE
16141#define PM_CASE_WRITABLE PM_CLASS_VARIABLE_READ_NODE: case PM_CONSTANT_PATH_NODE: \
16142 case PM_CONSTANT_READ_NODE: case PM_GLOBAL_VARIABLE_READ_NODE: case PM_LOCAL_VARIABLE_READ_NODE: \
16143 case PM_INSTANCE_VARIABLE_READ_NODE: case PM_MULTI_TARGET_NODE: case PM_BACK_REFERENCE_READ_NODE: \
16144 case PM_NUMBERED_REFERENCE_READ_NODE: case PM_IT_LOCAL_VARIABLE_READ_NODE
16148PM_STATIC_ASSERT(__LINE__, ((
int) PM_STRING_FLAGS_FORCED_UTF8_ENCODING) == ((
int) PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING),
"Expected the flags to match.");
16154static inline pm_node_flags_t
16155parse_unescaped_encoding(
const pm_parser_t *parser) {
16160 return PM_STRING_FLAGS_FORCED_UTF8_ENCODING;
16166 return PM_STRING_FLAGS_FORCED_BINARY_ENCODING;
16177parse_string_part(
pm_parser_t *parser, uint16_t depth) {
16178 switch (parser->
current.type) {
16185 case PM_TOKEN_STRING_CONTENT: {
16190 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16192 parser_lex(parser);
16201 case PM_TOKEN_EMBEXPR_BEGIN: {
16210 lex_state_set(parser, PM_LEX_STATE_BEG);
16211 parser_lex(parser);
16216 if (!match1(parser, PM_TOKEN_EMBEXPR_END)) {
16217 pm_accepts_block_stack_push(parser,
true);
16219 pm_accepts_block_stack_pop(parser);
16223 lex_state_set(parser, state);
16225 expect1(parser, PM_TOKEN_EMBEXPR_END, PM_ERR_EMBEXPR_END);
16231 if (statements != NULL && statements->
body.
size == 1) {
16232 pm_node_flag_unset(statements->
body.
nodes[0], PM_NODE_FLAG_NEWLINE);
16235 return (
pm_node_t *) pm_embedded_statements_node_create(parser, &opening, statements, &closing);
16244 case PM_TOKEN_EMBVAR: {
16249 lex_state_set(parser, PM_LEX_STATE_BEG);
16250 parser_lex(parser);
16255 switch (parser->
current.type) {
16258 case PM_TOKEN_BACK_REFERENCE:
16259 parser_lex(parser);
16260 variable = (
pm_node_t *) pm_back_reference_read_node_create(parser, &parser->
previous);
16264 case PM_TOKEN_NUMBERED_REFERENCE:
16265 parser_lex(parser);
16266 variable = (
pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->
previous);
16270 case PM_TOKEN_GLOBAL_VARIABLE:
16271 parser_lex(parser);
16272 variable = (
pm_node_t *) pm_global_variable_read_node_create(parser, &parser->
previous);
16276 case PM_TOKEN_INSTANCE_VARIABLE:
16277 parser_lex(parser);
16278 variable = (
pm_node_t *) pm_instance_variable_read_node_create(parser, &parser->
previous);
16282 case PM_TOKEN_CLASS_VARIABLE:
16283 parser_lex(parser);
16284 variable = (
pm_node_t *) pm_class_variable_read_node_create(parser, &parser->
previous);
16290 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EMBVAR_INVALID);
16295 return (
pm_node_t *) pm_embedded_variable_node_create(parser, &
operator, variable);
16298 parser_lex(parser);
16299 pm_parser_err_previous(parser, PM_ERR_CANNOT_PARSE_STRING_PART);
16309static const uint8_t *
16310parse_operator_symbol_name(
const pm_token_t *name) {
16311 switch (name->
type) {
16312 case PM_TOKEN_TILDE:
16313 case PM_TOKEN_BANG:
16314 if (name->
end[-1] ==
'@')
return name->
end - 1;
16326 const uint8_t *end = parse_operator_symbol_name(&parser->
current);
16328 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16329 parser_lex(parser);
16332 pm_node_flag_set((
pm_node_t *) symbol, PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING);
16346 if (lex_mode->
mode != PM_LEX_STRING) {
16347 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16349 switch (parser->
current.type) {
16350 case PM_CASE_OPERATOR:
16351 return parse_operator_symbol(parser, &opening, next_state == PM_LEX_STATE_NONE ? PM_LEX_STATE_ENDFN : next_state);
16352 case PM_TOKEN_IDENTIFIER:
16353 case PM_TOKEN_CONSTANT:
16354 case PM_TOKEN_INSTANCE_VARIABLE:
16355 case PM_TOKEN_METHOD_NAME:
16356 case PM_TOKEN_CLASS_VARIABLE:
16357 case PM_TOKEN_GLOBAL_VARIABLE:
16358 case PM_TOKEN_NUMBERED_REFERENCE:
16359 case PM_TOKEN_BACK_REFERENCE:
16360 case PM_CASE_KEYWORD:
16361 parser_lex(parser);
16364 expect2(parser, PM_TOKEN_IDENTIFIER, PM_TOKEN_METHOD_NAME, PM_ERR_SYMBOL_INVALID);
16372 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16379 if (match1(parser, PM_TOKEN_STRING_END)) {
16380 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16381 parser_lex(parser);
16385 return (
pm_node_t *) pm_symbol_node_create(parser, &opening, &content, &closing);
16389 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
16393 if (part && PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16394 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16395 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16401 if (part) pm_interpolated_symbol_node_append(symbol, part);
16403 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16404 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16405 pm_interpolated_symbol_node_append(symbol, part);
16409 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16410 if (match1(parser, PM_TOKEN_EOF)) {
16411 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16413 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16416 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
16423 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16426 parser_lex(parser);
16437 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16441 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &unescaped);
16442 pm_interpolated_symbol_node_append(symbol, part);
16445 pm_interpolated_symbol_node_append(symbol, part);
16447 if (next_state != PM_LEX_STATE_NONE) {
16448 lex_state_set(parser, next_state);
16451 parser_lex(parser);
16452 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
16454 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
16459 pm_string_shared_init(&unescaped, content.
start, content.
end);
16462 if (next_state != PM_LEX_STATE_NONE) {
16463 lex_state_set(parser, next_state);
16466 if (match1(parser, PM_TOKEN_EOF)) {
16467 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_DYNAMIC);
16469 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
16472 return (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
false));
16480parse_undef_argument(
pm_parser_t *parser, uint16_t depth) {
16481 switch (parser->
current.type) {
16482 case PM_CASE_OPERATOR: {
16483 const pm_token_t opening = not_provided(parser);
16484 return parse_operator_symbol(parser, &opening, PM_LEX_STATE_NONE);
16486 case PM_CASE_KEYWORD:
16487 case PM_TOKEN_CONSTANT:
16488 case PM_TOKEN_IDENTIFIER:
16489 case PM_TOKEN_METHOD_NAME: {
16490 parser_lex(parser);
16497 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16501 case PM_TOKEN_SYMBOL_BEGIN: {
16503 parser_lex(parser);
16505 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16508 pm_parser_err_current(parser, PM_ERR_UNDEF_ARGUMENT);
16520parse_alias_argument(
pm_parser_t *parser,
bool first, uint16_t depth) {
16521 switch (parser->
current.type) {
16522 case PM_CASE_OPERATOR: {
16523 const pm_token_t opening = not_provided(parser);
16524 return parse_operator_symbol(parser, &opening, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
16526 case PM_CASE_KEYWORD:
16527 case PM_TOKEN_CONSTANT:
16528 case PM_TOKEN_IDENTIFIER:
16529 case PM_TOKEN_METHOD_NAME: {
16530 if (first) lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
16531 parser_lex(parser);
16538 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16542 case PM_TOKEN_SYMBOL_BEGIN: {
16544 parser_lex(parser);
16546 return parse_symbol(parser, &lex_mode, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16548 case PM_TOKEN_BACK_REFERENCE:
16549 parser_lex(parser);
16550 return (
pm_node_t *) pm_back_reference_read_node_create(parser, &parser->
previous);
16551 case PM_TOKEN_NUMBERED_REFERENCE:
16552 parser_lex(parser);
16553 return (
pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->
previous);
16554 case PM_TOKEN_GLOBAL_VARIABLE:
16555 parser_lex(parser);
16556 return (
pm_node_t *) pm_global_variable_read_node_create(parser, &parser->
previous);
16558 pm_parser_err_current(parser, PM_ERR_ALIAS_ARGUMENT);
16573 if (!is_numbered_param && ((depth = pm_parser_local_depth_constant_id(parser, name_id)) != -1)) {
16574 return (
pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, (uint32_t) depth,
false);
16578 if (!current_scope->
closed && !(current_scope->
parameters & PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED)) {
16579 if (is_numbered_param) {
16584 uint8_t maximum = (uint8_t) (parser->
previous.
start[1] -
'0');
16585 for (uint8_t number = 1; number <= maximum; number++) {
16586 pm_parser_local_add_constant(parser, pm_numbered_parameter_names[number - 1], 2);
16589 if (!match1(parser, PM_TOKEN_EQUAL)) {
16593 pm_node_t *node = (
pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, 0,
false);
16613 pm_node_flags_t flags = 0;
16615 if (!match1(parser, PM_TOKEN_PARENTHESIS_LEFT) && (parser->
previous.
end[-1] !=
'!') && (parser->
previous.
end[-1] !=
'?')) {
16616 pm_node_t *node = parse_variable(parser);
16617 if (node != NULL)
return node;
16618 flags |= PM_CALL_NODE_FLAGS_VARIABLE_CALL;
16622 pm_node_flag_set((
pm_node_t *)node, flags);
16633parse_method_definition_name(
pm_parser_t *parser) {
16634 switch (parser->
current.type) {
16635 case PM_CASE_KEYWORD:
16636 case PM_TOKEN_CONSTANT:
16637 case PM_TOKEN_METHOD_NAME:
16638 parser_lex(parser);
16640 case PM_TOKEN_IDENTIFIER:
16641 pm_refute_numbered_parameter(parser, parser->
current.start, parser->
current.end);
16642 parser_lex(parser);
16644 case PM_CASE_OPERATOR:
16645 lex_state_set(parser, PM_LEX_STATE_ENDFN);
16646 parser_lex(parser);
16655parse_heredoc_dedent_string(
pm_string_t *
string,
size_t common_whitespace) {
16658 pm_string_ensure_owned(
string);
16664 const uint8_t *source_cursor = (uint8_t *) string->
source;
16665 const uint8_t *source_end = source_cursor + dest_length;
16670 size_t trimmed_whitespace = 0;
16676 while ((source_cursor < source_end) && pm_char_is_inline_whitespace(*source_cursor) && trimmed_whitespace < common_whitespace) {
16677 if (*source_cursor ==
'\t') {
16678 trimmed_whitespace = (trimmed_whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
16679 if (trimmed_whitespace > common_whitespace)
break;
16681 trimmed_whitespace++;
16688 memmove((uint8_t *) string->source, source_cursor, (
size_t) (source_end - source_cursor));
16689 string->length = dest_length;
16699 bool dedent_next =
true;
16704 size_t write_index = 0;
16711 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE)) {
16712 nodes->
nodes[write_index++] = node;
16713 dedent_next =
false;
16719 parse_heredoc_dedent_string(&string_node->
unescaped, common_whitespace);
16723 pm_node_destroy(parser, node);
16725 nodes->
nodes[write_index++] = node;
16729 dedent_next =
true;
16732 nodes->
size = write_index;
16739parse_strings_empty_content(
const uint8_t *location) {
16740 return (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = location, .end = location };
16748 assert(parser->
current.type == PM_TOKEN_STRING_BEGIN);
16749 bool concating =
false;
16751 while (match1(parser, PM_TOKEN_STRING_BEGIN)) {
16757 assert(lex_mode->
mode == PM_LEX_STRING);
16759 bool label_allowed = lex_mode->
as.string.
label_allowed && accepts_label;
16762 parser_lex(parser);
16764 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16765 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16774 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16784 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16785 }
else if (!lex_interpolation) {
16791 if (match1(parser, PM_TOKEN_EOF)) {
16793 content = not_provided(parser);
16796 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_EXPECT_STRING_CONTENT);
16811 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16814 pm_token_t delimiters = not_provided(parser);
16815 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &delimiters, &content, &delimiters, &unescaped);
16816 pm_node_list_append(&parts, part);
16819 part = (
pm_node_t *) pm_string_node_create_current_string(parser, &delimiters, &parser->
current, &delimiters);
16820 pm_node_list_append(&parts, part);
16821 parser_lex(parser);
16822 }
while (match1(parser, PM_TOKEN_STRING_CONTENT));
16824 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16825 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16827 pm_node_list_free(&parts);
16828 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16829 node = (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true));
16830 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16831 }
else if (match1(parser, PM_TOKEN_EOF)) {
16832 pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
16833 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
16834 }
else if (accept1(parser, PM_TOKEN_STRING_END)) {
16835 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped);
16840 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped);
16842 }
else if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16849 parser_lex(parser);
16851 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16852 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
16853 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16859 if (!accept1(parser, PM_TOKEN_STRING_END)) {
16861 if (location > parser->
start && location[-1] ==
'\n') location--;
16862 pm_parser_err(parser, location, location, PM_ERR_STRING_LITERAL_EOF);
16867 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16868 node = (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true));
16869 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16874 pm_token_t string_opening = not_provided(parser);
16875 pm_token_t string_closing = not_provided(parser);
16877 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &string_opening, &parser->
previous, &string_closing, &unescaped);
16878 pm_node_flag_set(part, parse_unescaped_encoding(parser));
16879 pm_node_list_append(&parts, part);
16881 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16882 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16883 pm_node_list_append(&parts, part);
16887 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16888 node = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous);
16889 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16890 }
else if (match1(parser, PM_TOKEN_EOF)) {
16891 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16892 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current);
16894 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16895 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16898 pm_node_list_free(&parts);
16907 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16908 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16909 pm_node_list_append(&parts, part);
16913 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16914 node = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous);
16915 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16916 }
else if (match1(parser, PM_TOKEN_EOF)) {
16917 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16918 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current);
16920 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16921 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16924 pm_node_list_free(&parts);
16927 if (current == NULL) {
16931 if (PM_NODE_TYPE_P(node, PM_SYMBOL_NODE) || PM_NODE_TYPE_P(node, PM_INTERPOLATED_SYMBOL_NODE)) {
16942 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE) && !PM_NODE_TYPE_P(node, PM_INTERPOLATED_STRING_NODE)) {
16943 pm_parser_err_node(parser, node, PM_ERR_STRING_CONCATENATION);
16949 if (!PM_NODE_TYPE_P(current, PM_STRING_NODE) && !PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
16950 pm_parser_err_node(parser, current, PM_ERR_STRING_CONCATENATION);
16957 pm_interpolated_string_node_append(container, current);
16968#define PM_PARSE_PATTERN_SINGLE 0
16969#define PM_PARSE_PATTERN_TOP 1
16970#define PM_PARSE_PATTERN_MULTI 2
16983 if (*location->
start ==
'_')
return;
16985 if (pm_constant_id_list_includes(captures, capture)) {
16986 pm_parser_err(parser, location->
start, location->
end, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
16988 pm_constant_id_list_append(captures, capture);
16999 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
17001 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
17002 node = (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
17008 if (!match2(parser, PM_TOKEN_BRACKET_LEFT, PM_TOKEN_PARENTHESIS_LEFT)) {
17016 if (accept1(parser, PM_TOKEN_BRACKET_LEFT)) {
17018 accept1(parser, PM_TOKEN_NEWLINE);
17020 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17021 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
17022 accept1(parser, PM_TOKEN_NEWLINE);
17023 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET);
17028 parser_lex(parser);
17030 accept1(parser, PM_TOKEN_NEWLINE);
17032 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
17033 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
17034 accept1(parser, PM_TOKEN_NEWLINE);
17035 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
17044 return (
pm_node_t *) pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
17051 switch (PM_NODE_TYPE(inner)) {
17052 case PM_ARRAY_PATTERN_NODE: {
17060 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17061 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17068 case PM_FIND_PATTERN_NODE: {
17076 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17077 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17084 case PM_HASH_PATTERN_NODE: {
17092 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17093 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17107 pm_array_pattern_node_t *pattern_node = pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
17108 pm_array_pattern_node_requireds_append(pattern_node, inner);
17124 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
17126 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &identifier);
17129 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17130 pm_parser_local_add(parser, constant_id, identifier.
start, identifier.
end, 0);
17133 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&identifier));
17134 name = (
pm_node_t *) pm_local_variable_target_node_create(
17136 &PM_LOCATION_TOKEN_VALUE(&identifier),
17138 (uint32_t) (depth == -1 ? 0 : depth)
17143 return pm_splat_node_create(parser, &
operator, name);
17151 assert(parser->
current.type == PM_TOKEN_USTAR_STAR);
17152 parser_lex(parser);
17157 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
17158 return (
pm_node_t *) pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous);
17161 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
17165 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17169 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17170 value = (
pm_node_t *) pm_local_variable_target_node_create(
17172 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17174 (uint32_t) (depth == -1 ? 0 : depth)
17178 return (
pm_node_t *) pm_assoc_splat_node_create(parser, value, &
operator);
17186pm_slice_is_valid_local(
const pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
17187 ptrdiff_t length = end - start;
17188 if (length == 0)
return false;
17191 size_t width = char_is_identifier_start(parser, start, end - start);
17192 if (width == 0)
return false;
17198 if (pm_encoding_utf_8_isupper_char(start, length))
return false;
17203 const uint8_t *cursor = start + width;
17204 while ((width = char_is_identifier(parser, cursor, end - cursor))) cursor += width;
17205 return cursor == end;
17219 if (pm_slice_is_valid_local(parser, value_loc->
start, value_loc->
end)) {
17220 depth = pm_parser_local_depth_constant_id(parser, constant_id);
17222 pm_parser_err(parser, key->base.location.start, key->base.location.end, PM_ERR_PATTERN_HASH_KEY_LOCALS);
17224 if ((value_loc->
end > value_loc->
start) && ((value_loc->
end[-1] ==
'!') || (value_loc->
end[-1] ==
'?'))) {
17225 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);
17230 pm_parser_local_add(parser, constant_id, value_loc->
start, value_loc->
end, 0);
17233 parse_pattern_capture(parser, captures, constant_id, value_loc);
17238 (uint32_t) (depth == -1 ? 0 : depth)
17251 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
17264 switch (PM_NODE_TYPE(first_node)) {
17265 case PM_ASSOC_SPLAT_NODE:
17266 case PM_NO_KEYWORDS_PARAMETER_NODE:
17269 case PM_SYMBOL_NODE: {
17270 if (pm_symbol_node_label_p(first_node)) {
17271 parse_pattern_hash_key(parser, &keys, first_node);
17274 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)) {
17277 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) first_node);
17281 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17285 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, first_node, &
operator, value);
17287 pm_node_list_append(&assocs, assoc);
17296 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;
17297 pm_parser_err_node(parser, first_node, diag_id);
17301 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, first_node, &
operator, value);
17303 pm_node_list_append(&assocs, assoc);
17309 while (accept1(parser, PM_TOKEN_COMMA)) {
17311 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)) {
17313 if (rest != NULL) {
17314 pm_parser_err_token(parser, &parser->
current, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17320 if (match1(parser, PM_TOKEN_USTAR_STAR)) {
17321 pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures);
17323 if (rest == NULL) {
17326 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17327 pm_node_list_append(&assocs, assoc);
17332 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
17333 key = parse_strings(parser, NULL,
true, (uint16_t) (depth + 1));
17335 if (PM_NODE_TYPE_P(key, PM_INTERPOLATED_SYMBOL_NODE)) {
17336 pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
17337 }
else if (!pm_symbol_node_label_p(key)) {
17338 pm_parser_err_node(parser, key, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17341 expect1(parser, PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17345 parse_pattern_hash_key(parser, &keys, key);
17348 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)) {
17349 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) key);
17351 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17355 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
17357 if (rest != NULL) {
17358 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17361 pm_node_list_append(&assocs, assoc);
17368 pm_static_literals_free(&keys);
17377 switch (parser->
current.type) {
17378 case PM_TOKEN_IDENTIFIER:
17379 case PM_TOKEN_METHOD_NAME: {
17380 parser_lex(parser);
17384 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17388 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17389 return (
pm_node_t *) pm_local_variable_target_node_create(
17391 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17393 (uint32_t) (depth == -1 ? 0 : depth)
17396 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
17398 parser_lex(parser);
17400 if (accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17403 return (
pm_node_t *) pm_array_pattern_node_empty_create(parser, &opening, &parser->
previous);
17408 pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
17410 accept1(parser, PM_TOKEN_NEWLINE);
17411 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET);
17414 switch (PM_NODE_TYPE(inner)) {
17415 case PM_ARRAY_PATTERN_NODE: {
17421 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17422 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17429 case PM_FIND_PATTERN_NODE: {
17435 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17436 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17448 pm_array_pattern_node_requireds_append(node, inner);
17451 case PM_TOKEN_BRACE_LEFT: {
17457 parser_lex(parser);
17459 if (accept1(parser, PM_TOKEN_BRACE_RIGHT)) {
17462 node = pm_hash_pattern_node_empty_create(parser, &opening, &parser->
previous);
17466 switch (parser->
current.type) {
17467 case PM_TOKEN_LABEL:
17468 parser_lex(parser);
17469 first_node = (
pm_node_t *) pm_symbol_node_label_create(parser, &parser->
previous);
17471 case PM_TOKEN_USTAR_STAR:
17472 first_node = parse_pattern_keyword_rest(parser, captures);
17474 case PM_TOKEN_STRING_BEGIN:
17475 first_node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, PM_ERR_PATTERN_HASH_KEY_LABEL, (uint16_t) (depth + 1));
17479 parser_lex(parser);
17486 node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
17488 accept1(parser, PM_TOKEN_NEWLINE);
17489 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE);
17495 node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17496 node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17502 case PM_TOKEN_UDOT_DOT:
17503 case PM_TOKEN_UDOT_DOT_DOT: {
17505 parser_lex(parser);
17509 switch (parser->
current.type) {
17510 case PM_CASE_PRIMITIVE: {
17511 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
17512 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
17515 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
17516 pm_node_t *right = (
pm_node_t *) pm_missing_node_create(parser,
operator.start,
operator.end);
17517 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
17521 case PM_CASE_PRIMITIVE: {
17522 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, diag_id, (uint16_t) (depth + 1));
17525 if (pm_symbol_node_label_p(node))
return node;
17528 if (PM_NODE_TYPE(node) == PM_CALL_NODE) {
17529 pm_parser_err_node(parser, node, diag_id);
17531 pm_node_destroy(parser, node);
17536 if (accept2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
17542 switch (parser->
current.type) {
17543 case PM_CASE_PRIMITIVE: {
17544 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
17545 return (
pm_node_t *) pm_range_node_create(parser, node, &
operator, right);
17548 return (
pm_node_t *) pm_range_node_create(parser, node, &
operator, NULL);
17554 case PM_TOKEN_CARET: {
17555 parser_lex(parser);
17560 switch (parser->
current.type) {
17561 case PM_TOKEN_IDENTIFIER: {
17562 parser_lex(parser);
17565 if (variable == NULL) {
17566 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
previous, PM_ERR_NO_LOCAL_VARIABLE);
17567 variable = (
pm_node_t *) pm_local_variable_read_node_missing_create(parser, &parser->
previous, 0);
17570 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17572 case PM_TOKEN_INSTANCE_VARIABLE: {
17573 parser_lex(parser);
17576 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17578 case PM_TOKEN_CLASS_VARIABLE: {
17579 parser_lex(parser);
17582 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17584 case PM_TOKEN_GLOBAL_VARIABLE: {
17585 parser_lex(parser);
17588 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17590 case PM_TOKEN_NUMBERED_REFERENCE: {
17591 parser_lex(parser);
17594 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17596 case PM_TOKEN_BACK_REFERENCE: {
17597 parser_lex(parser);
17600 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17602 case PM_TOKEN_PARENTHESIS_LEFT: {
17607 parser_lex(parser);
17609 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN, (uint16_t) (depth + 1));
17612 accept1(parser, PM_TOKEN_NEWLINE);
17613 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
17614 return (
pm_node_t *) pm_pinned_expression_node_create(parser, expression, &
operator, &lparen, &parser->
previous);
17619 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
17620 pm_node_t *variable = (
pm_node_t *) pm_missing_node_create(parser,
operator.start,
operator.end);
17621 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17625 case PM_TOKEN_UCOLON_COLON: {
17627 parser_lex(parser);
17629 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
17632 return parse_pattern_constant_path(parser, captures, (
pm_node_t *) node, (uint16_t) (depth + 1));
17634 case PM_TOKEN_CONSTANT: {
17636 parser_lex(parser);
17639 return parse_pattern_constant_path(parser, captures, node, (uint16_t) (depth + 1));
17642 pm_parser_err_current(parser, diag_id);
17655 while ((node == NULL) || accept1(parser, PM_TOKEN_PIPE)) {
17658 switch (parser->
current.type) {
17659 case PM_TOKEN_IDENTIFIER:
17660 case PM_TOKEN_BRACKET_LEFT_ARRAY:
17661 case PM_TOKEN_BRACE_LEFT:
17662 case PM_TOKEN_CARET:
17663 case PM_TOKEN_CONSTANT:
17664 case PM_TOKEN_UCOLON_COLON:
17665 case PM_TOKEN_UDOT_DOT:
17666 case PM_TOKEN_UDOT_DOT_DOT:
17667 case PM_CASE_PRIMITIVE: {
17668 if (node == NULL) {
17669 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17671 pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
17672 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17677 case PM_TOKEN_PARENTHESIS_LEFT:
17678 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
17680 parser_lex(parser);
17682 pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
17683 accept1(parser, PM_TOKEN_NEWLINE);
17684 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
17687 if (node == NULL) {
17690 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17696 pm_parser_err_current(parser, diag_id);
17699 if (node == NULL) {
17702 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17712 while (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
17714 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_PATTERN_IDENT_AFTER_HROCKET);
17719 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17723 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17726 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17728 (uint32_t) (depth == -1 ? 0 : depth)
17731 node = (
pm_node_t *) pm_capture_pattern_node_create(parser, node, target, &
operator);
17744 bool leading_rest =
false;
17745 bool trailing_rest =
false;
17747 switch (parser->
current.type) {
17748 case PM_TOKEN_LABEL: {
17749 parser_lex(parser);
17751 node = (
pm_node_t *) parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1));
17753 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17754 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17759 case PM_TOKEN_USTAR_STAR: {
17760 node = parse_pattern_keyword_rest(parser, captures);
17761 node = (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17763 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17764 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17769 case PM_TOKEN_STRING_BEGIN: {
17772 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17774 if (pm_symbol_node_label_p(node)) {
17775 node = (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17777 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17778 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17784 node = parse_pattern_primitives(parser, captures, node, diag_id, (uint16_t) (depth + 1));
17787 case PM_TOKEN_USTAR: {
17788 if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
17789 parser_lex(parser);
17790 node = (
pm_node_t *) parse_pattern_rest(parser, captures);
17791 leading_rest =
true;
17797 node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1));
17803 if (pm_symbol_node_label_p(node)) {
17804 return (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17807 if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser, PM_TOKEN_COMMA)) {
17812 pm_node_list_append(&nodes, node);
17815 while (accept1(parser, PM_TOKEN_COMMA)) {
17817 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)) {
17819 pm_node_list_append(&nodes, node);
17820 trailing_rest =
true;
17824 if (accept1(parser, PM_TOKEN_USTAR)) {
17825 node = (
pm_node_t *) parse_pattern_rest(parser, captures);
17830 if (trailing_rest) {
17831 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
17834 trailing_rest =
true;
17836 node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
17839 pm_node_list_append(&nodes, node);
17846 if (leading_rest && PM_NODE_TYPE_P(nodes.
nodes[nodes.
size - 1], PM_SPLAT_NODE)) {
17847 node = (
pm_node_t *) pm_find_pattern_node_create(parser, &nodes);
17849 if (nodes.
size == 2) {
17850 pm_parser_err_node(parser, node, PM_ERR_PATTERN_FIND_MISSING_INNER);
17853 node = (
pm_node_t *) pm_array_pattern_node_node_list_create(parser, &nodes);
17855 if (leading_rest && trailing_rest) {
17856 pm_parser_err_node(parser, node, PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS);
17861 }
else if (leading_rest) {
17864 node = (
pm_node_t *) pm_array_pattern_node_rest_create(parser, node);
17876parse_negative_numeric(
pm_node_t *node) {
17877 switch (PM_NODE_TYPE(node)) {
17878 case PM_INTEGER_NODE: {
17884 case PM_FLOAT_NODE: {
17890 case PM_RATIONAL_NODE: {
17896 case PM_IMAGINARY_NODE:
17901 assert(
false &&
"unreachable");
17914 case PM_ERR_HASH_KEY: {
17918 case PM_ERR_HASH_VALUE:
17919 case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: {
17923 case PM_ERR_UNARY_RECEIVER: {
17928 case PM_ERR_UNARY_DISALLOWED:
17929 case PM_ERR_EXPECT_ARGUMENT: {
17934 pm_parser_err_previous(parser, diag_id);
17944#define CONTEXT_NONE 0
17945#define CONTEXT_THROUGH_ENSURE 1
17946#define CONTEXT_THROUGH_ELSE 2
17949 int context = CONTEXT_NONE;
17951 while (context_node != NULL) {
17952 switch (context_node->
context) {
17973 if (context == CONTEXT_NONE) {
17974 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_WITHOUT_RESCUE);
17975 }
else if (context == CONTEXT_THROUGH_ENSURE) {
17976 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ENSURE);
17977 }
else if (context == CONTEXT_THROUGH_ELSE) {
17978 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ELSE);
17990 context = CONTEXT_THROUGH_ELSE;
18001 context = CONTEXT_THROUGH_ENSURE;
18005 assert(
false &&
"unreachable");
18035 context_node = context_node->
prev;
18039#undef CONTEXT_ENSURE
18050 while (context_node != NULL) {
18051 switch (context_node->
context) {
18076 pm_parser_err_node(parser, node, PM_ERR_INVALID_YIELD);
18080 assert(
false &&
"unreachable");
18121 context_node = context_node->
prev;
18153parse_regular_expression_error(
const uint8_t *start,
const uint8_t *end,
const char *message,
void *data) {
18157 if (callback_data->
shared) {
18163 PM_PARSER_ERR_FORMAT(callback_data->
parser, location.
start, location.
end, PM_ERR_REGEXP_PARSE_ERROR, message);
18176 .shared = unescaped->
type == PM_STRING_SHARED
18179 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);
18186parse_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) {
18187 switch (parser->
current.type) {
18188 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
18189 parser_lex(parser);
18192 pm_accepts_block_stack_push(parser,
true);
18193 bool parsed_bare_hash =
false;
18195 while (!match2(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_EOF)) {
18196 bool accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
18200 if (accepted_newline && match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
18206 if (accept1(parser, PM_TOKEN_COMMA)) {
18209 if (accepted_newline) {
18210 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
18226 if (match1(parser, PM_TOKEN_BRACKET_RIGHT))
break;
18230 if (accept1(parser, PM_TOKEN_USTAR)) {
18234 if (match3(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_EOF)) {
18235 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
18237 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
18240 element = (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
18241 }
else if (match2(parser, PM_TOKEN_LABEL, PM_TOKEN_USTAR_STAR)) {
18242 if (parsed_bare_hash) {
18243 pm_parser_err_current(parser, PM_ERR_EXPRESSION_BARE_HASH);
18246 element = (
pm_node_t *) pm_keyword_hash_node_create(parser);
18249 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)) {
18250 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
18253 pm_static_literals_free(&hash_keys);
18254 parsed_bare_hash =
true;
18256 element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_ARRAY_EXPRESSION, (uint16_t) (depth + 1));
18258 if (pm_symbol_node_label_p(element) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
18259 if (parsed_bare_hash) {
18260 pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
18265 pm_hash_key_static_literals_add(parser, &hash_keys, element);
18268 if (parser->
previous.
type == PM_TOKEN_EQUAL_GREATER) {
18271 operator = not_provided(parser);
18274 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
18275 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, element, &
operator, value);
18276 pm_keyword_hash_node_elements_append(hash, assoc);
18279 if (accept1(parser, PM_TOKEN_COMMA) && !match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
18280 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
18283 pm_static_literals_free(&hash_keys);
18284 parsed_bare_hash =
true;
18288 pm_array_node_elements_append(array, element);
18289 if (PM_NODE_TYPE_P(element, PM_MISSING_NODE))
break;
18292 accept1(parser, PM_TOKEN_NEWLINE);
18294 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
18300 pm_array_node_close_set(array, &parser->
previous);
18301 pm_accepts_block_stack_pop(parser);
18305 case PM_TOKEN_PARENTHESIS_LEFT:
18306 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
18308 pm_node_flags_t flags = 0;
18311 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18313 parser_lex(parser);
18315 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
18316 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
18317 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
18324 if (match2(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_EOF)) {
18325 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
18327 pop_block_exits(parser, previous_block_exits);
18328 pm_node_list_free(¤t_block_exits);
18330 return (
pm_node_t *) pm_parentheses_node_create(parser, &opening, NULL, &parser->
previous, flags);
18335 pm_accepts_block_stack_push(parser,
true);
18337 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
18338 context_pop(parser);
18343 bool terminator_found =
false;
18345 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
18346 terminator_found =
true;
18347 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
18348 }
else if (accept1(parser, PM_TOKEN_NEWLINE)) {
18349 terminator_found =
true;
18352 if (terminator_found) {
18354 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
18355 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
18356 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
18365 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18366 if (opening.
type == PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
18367 lex_state_set(parser, PM_LEX_STATE_ENDARG);
18370 parser_lex(parser);
18371 pm_accepts_block_stack_pop(parser);
18373 pop_block_exits(parser, previous_block_exits);
18374 pm_node_list_free(¤t_block_exits);
18376 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) || PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
18382 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) && ((
pm_multi_target_node_t *) statement)->lparen_loc.start == NULL) {
18385 multi_target = pm_multi_target_node_create(parser);
18386 pm_multi_target_node_targets_append(parser, multi_target, statement);
18389 pm_location_t lparen_loc = PM_LOCATION_TOKEN_VALUE(&opening);
18398 if (match1(parser, PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
18399 result = parse_targets(parser, (
pm_node_t *) multi_target, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18400 accept1(parser, PM_TOKEN_NEWLINE);
18411 }
else if (binding_power != PM_BINDING_POWER_STATEMENT) {
18414 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
18415 }
else if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
18419 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
18429 pm_statements_node_body_append(parser, statements, statement,
true);
18438 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
18441 pm_statements_node_body_append(parser, statements, statement,
true);
18445 if (!terminator_found && !match1(parser, PM_TOKEN_EOF)) {
18451 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
18452 pm_statements_node_body_append(parser, statements, node,
true);
18459 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) parser->
recovering =
false;
18465 if (PM_NODE_TYPE_P(node, PM_MISSING_NODE))
break;
18469 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18470 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18471 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
break;
18472 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18474 }
else if (!match1(parser, PM_TOKEN_EOF)) {
18481 context_pop(parser);
18482 pm_accepts_block_stack_pop(parser);
18483 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
18492 if (PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
18494 pm_multi_target_node_targets_append(parser, multi_target, statement);
18496 statement = (
pm_node_t *) multi_target;
18500 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE)) {
18502 pm_token_t operator = { .
type = PM_TOKEN_EQUAL, .start = offset, .end = offset };
18508 pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
18512 pop_block_exits(parser, previous_block_exits);
18513 pm_node_list_free(¤t_block_exits);
18515 pm_void_statements_check(parser, statements,
true);
18518 case PM_TOKEN_BRACE_LEFT: {
18529 pm_accepts_block_stack_push(parser,
true);
18530 parser_lex(parser);
18534 if (!match2(parser, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_EOF)) {
18535 if (current_hash_keys != NULL) {
18536 parse_assocs(parser, current_hash_keys, (
pm_node_t *) node, (uint16_t) (depth + 1));
18539 parse_assocs(parser, &hash_keys, (
pm_node_t *) node, (uint16_t) (depth + 1));
18540 pm_static_literals_free(&hash_keys);
18543 accept1(parser, PM_TOKEN_NEWLINE);
18546 pm_accepts_block_stack_pop(parser);
18547 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM);
18548 pm_hash_node_closing_loc_set(node, &parser->
previous);
18552 case PM_TOKEN_CHARACTER_LITERAL: {
18557 .type = PM_TOKEN_STRING_BEGIN,
18558 .start = parser->
current.start,
18559 .end = parser->
current.start + 1
18562 .type = PM_TOKEN_STRING_CONTENT,
18563 .start = parser->
current.start + 1,
18569 pm_node_flag_set(node, parse_unescaped_encoding(parser));
18573 parser_lex(parser);
18577 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
18578 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18583 case PM_TOKEN_CLASS_VARIABLE: {
18584 parser_lex(parser);
18587 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18588 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18593 case PM_TOKEN_CONSTANT: {
18594 parser_lex(parser);
18600 match1(parser, PM_TOKEN_PARENTHESIS_LEFT) ||
18601 (accepts_command_call && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
18602 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
18603 match1(parser, PM_TOKEN_BRACE_LEFT)
18606 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18607 return (
pm_node_t *) pm_call_node_fcall_create(parser, &constant, &arguments);
18612 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
18615 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18620 case PM_TOKEN_UCOLON_COLON: {
18621 parser_lex(parser);
18624 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
18627 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
18628 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18633 case PM_TOKEN_UDOT_DOT:
18634 case PM_TOKEN_UDOT_DOT_DOT: {
18636 parser_lex(parser);
18638 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));
18644 if (match2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
18645 pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
18648 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
18650 case PM_TOKEN_FLOAT:
18651 parser_lex(parser);
18653 case PM_TOKEN_FLOAT_IMAGINARY:
18654 parser_lex(parser);
18655 return (
pm_node_t *) pm_float_node_imaginary_create(parser, &parser->
previous);
18656 case PM_TOKEN_FLOAT_RATIONAL:
18657 parser_lex(parser);
18659 case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY:
18660 parser_lex(parser);
18661 return (
pm_node_t *) pm_float_node_rational_imaginary_create(parser, &parser->
previous);
18662 case PM_TOKEN_NUMBERED_REFERENCE: {
18663 parser_lex(parser);
18666 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18667 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18672 case PM_TOKEN_GLOBAL_VARIABLE: {
18673 parser_lex(parser);
18676 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18677 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18682 case PM_TOKEN_BACK_REFERENCE: {
18683 parser_lex(parser);
18686 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18687 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18692 case PM_TOKEN_IDENTIFIER:
18693 case PM_TOKEN_METHOD_NAME: {
18694 parser_lex(parser);
18696 pm_node_t *node = parse_variable_call(parser);
18698 if (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
18706 if (parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1))) {
18709 pm_node_flag_unset((
pm_node_t *)call, PM_CALL_NODE_FLAGS_VARIABLE_CALL);
18716 const uint8_t *end = pm_arguments_end(&arguments);
18727 (accepts_command_call && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
18728 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
18729 match1(parser, PM_TOKEN_BRACE_LEFT)
18732 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18733 pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
18735 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
18739 parse_target_implicit_parameter(parser, node);
18745 assert(PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE));
18747 if (pm_token_is_numbered_parameter(identifier.
start, identifier.
end)) {
18748 parse_target_implicit_parameter(parser, node);
18751 pm_locals_unread(&pm_parser_scope_find(parser, cast->
depth)->
locals, cast->
name);
18755 pm_node_destroy(parser, node);
18760 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
18761 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18766 case PM_TOKEN_HEREDOC_START: {
18772 size_t common_whitespace = (size_t) -1;
18775 parser_lex(parser);
18781 if (match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18787 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18794 }
else if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) == NULL) {
18802 }
else if (PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18807 pm_node_flag_set(part, parse_unescaped_encoding(parser));
18810 cast->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
18814 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18816 cast->
base.
type = PM_X_STRING_NODE;
18819 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18820 parse_heredoc_dedent_string(&cast->
unescaped, common_whitespace);
18830 pm_node_list_append(&parts, part);
18832 while (!match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18833 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
18834 pm_node_list_append(&parts, part);
18840 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18842 cast->
parts = parts;
18845 pm_interpolated_xstring_node_closing_set(cast, &parser->
previous);
18851 pm_node_list_free(&parts);
18854 pm_interpolated_string_node_closing_set(cast, &parser->
previous);
18862 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18864 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18870 parse_heredoc_dedent(parser, nodes, common_whitespace);
18874 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
18875 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18880 case PM_TOKEN_INSTANCE_VARIABLE: {
18881 parser_lex(parser);
18884 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18885 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18890 case PM_TOKEN_INTEGER: {
18892 parser_lex(parser);
18895 case PM_TOKEN_INTEGER_IMAGINARY: {
18897 parser_lex(parser);
18898 return (
pm_node_t *) pm_integer_node_imaginary_create(parser, base, &parser->
previous);
18900 case PM_TOKEN_INTEGER_RATIONAL: {
18902 parser_lex(parser);
18903 return (
pm_node_t *) pm_integer_node_rational_create(parser, base, &parser->
previous);
18905 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: {
18907 parser_lex(parser);
18908 return (
pm_node_t *) pm_integer_node_rational_imaginary_create(parser, base, &parser->
previous);
18910 case PM_TOKEN_KEYWORD___ENCODING__:
18911 parser_lex(parser);
18912 return (
pm_node_t *) pm_source_encoding_node_create(parser, &parser->
previous);
18913 case PM_TOKEN_KEYWORD___FILE__:
18914 parser_lex(parser);
18916 case PM_TOKEN_KEYWORD___LINE__:
18917 parser_lex(parser);
18919 case PM_TOKEN_KEYWORD_ALIAS: {
18920 if (binding_power != PM_BINDING_POWER_STATEMENT) {
18921 pm_parser_err_current(parser, PM_ERR_STATEMENT_ALIAS);
18924 parser_lex(parser);
18927 pm_node_t *new_name = parse_alias_argument(parser,
true, (uint16_t) (depth + 1));
18928 pm_node_t *old_name = parse_alias_argument(parser,
false, (uint16_t) (depth + 1));
18930 switch (PM_NODE_TYPE(new_name)) {
18931 case PM_BACK_REFERENCE_READ_NODE:
18932 case PM_NUMBERED_REFERENCE_READ_NODE:
18933 case PM_GLOBAL_VARIABLE_READ_NODE: {
18934 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)) {
18935 if (PM_NODE_TYPE_P(old_name, PM_NUMBERED_REFERENCE_READ_NODE)) {
18936 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE);
18939 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18942 return (
pm_node_t *) pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name);
18944 case PM_SYMBOL_NODE:
18945 case PM_INTERPOLATED_SYMBOL_NODE: {
18946 if (!PM_NODE_TYPE_P(old_name, PM_SYMBOL_NODE) && !PM_NODE_TYPE_P(old_name, PM_INTERPOLATED_SYMBOL_NODE)) {
18947 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18952 return (
pm_node_t *) pm_alias_method_node_create(parser, &keyword, new_name, old_name);
18955 case PM_TOKEN_KEYWORD_CASE: {
18956 size_t opening_newline_index = token_newline_index(parser);
18957 parser_lex(parser);
18963 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18965 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18966 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18968 }
else if (match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_END)) {
18970 }
else if (!token_begins_expression_p(parser->
current.type)) {
18973 predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CASE_EXPRESSION_AFTER_CASE, (uint16_t) (depth + 1));
18974 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18977 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
18978 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18979 parser_lex(parser);
18981 pop_block_exits(parser, previous_block_exits);
18982 pm_node_list_free(¤t_block_exits);
18984 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18985 return (
pm_node_t *) pm_case_node_create(parser, &case_keyword, predicate, &parser->
previous);
18990 pm_token_t end_keyword = not_provided(parser);
18993 if (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18994 pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, &end_keyword);
19000 while (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
19001 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
19002 parser_lex(parser);
19005 pm_when_node_t *when_node = pm_when_node_create(parser, &when_keyword);
19008 if (accept1(parser, PM_TOKEN_USTAR)) {
19010 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19012 pm_splat_node_t *splat_node = pm_splat_node_create(parser, &
operator, expression);
19013 pm_when_node_conditions_append(when_node, (
pm_node_t *) splat_node);
19015 if (PM_NODE_TYPE_P(expression, PM_MISSING_NODE))
break;
19017 pm_node_t *condition = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_CASE_EXPRESSION_AFTER_WHEN, (uint16_t) (depth + 1));
19018 pm_when_node_conditions_append(when_node, condition);
19022 if (PM_NODE_TYPE_P(condition, PM_MISSING_NODE))
break;
19026 if (PM_NODE_TYPE_P(condition, PM_STRING_NODE)) {
19027 pm_node_flag_set(condition, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
19028 }
else if (PM_NODE_TYPE_P(condition, PM_SOURCE_FILE_NODE)) {
19029 pm_node_flag_set(condition, PM_NODE_FLAG_STATIC_LITERAL);
19032 pm_when_clause_static_literals_add(parser, &literals, condition);
19034 }
while (accept1(parser, PM_TOKEN_COMMA));
19036 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
19037 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
19038 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
19041 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_WHEN_DELIMITER);
19042 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
19045 if (!match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19047 if (statements != NULL) {
19048 pm_when_node_statements_set(when_node, statements);
19052 pm_case_node_condition_append(case_node, (
pm_node_t *) when_node);
19058 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
19061 pm_static_literals_free(&literals);
19064 pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate, &end_keyword);
19068 if (predicate == NULL) {
19069 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MATCH_MISSING_PREDICATE);
19075 while (match1(parser, PM_TOKEN_KEYWORD_IN)) {
19076 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
19081 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
19083 parser_lex(parser);
19088 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));
19091 pm_constant_id_list_free(&captures);
19096 if (accept1(parser, PM_TOKEN_KEYWORD_IF_MODIFIER)) {
19098 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
19099 pattern = (
pm_node_t *) pm_if_node_modifier_create(parser, pattern, &keyword, predicate);
19100 }
else if (accept1(parser, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) {
19102 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
19103 pattern = (
pm_node_t *) pm_unless_node_modifier_create(parser, pattern, &keyword, predicate);
19110 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
19111 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
19114 then_keyword = not_provided(parser);
19117 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_IN_DELIMITER);
19124 if (match3(parser, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19132 pm_node_t *condition = (
pm_node_t *) pm_in_node_create(parser, pattern, statements, &in_keyword, &then_keyword);
19133 pm_case_match_node_condition_append(case_node, condition);
19139 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
19145 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19146 if (accept1(parser, PM_TOKEN_KEYWORD_ELSE)) {
19150 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19151 else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser,
PM_CONTEXT_ELSE, (uint16_t) (depth + 1)), &parser->
current);
19153 else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->
current);
19156 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
19157 pm_case_node_else_clause_set((
pm_case_node_t *) node, else_node);
19163 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
19164 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM);
19166 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
19172 pop_block_exits(parser, previous_block_exits);
19173 pm_node_list_free(¤t_block_exits);
19177 case PM_TOKEN_KEYWORD_BEGIN: {
19178 size_t opening_newline_index = token_newline_index(parser);
19179 parser_lex(parser);
19182 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19185 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19188 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19189 pm_accepts_block_stack_push(parser,
true);
19190 begin_statements = parse_statements(parser,
PM_CONTEXT_BEGIN, (uint16_t) (depth + 1));
19191 pm_accepts_block_stack_pop(parser);
19192 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19195 pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
19196 parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
19197 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM);
19200 pm_begin_node_end_keyword_set(begin_node, &parser->
previous);
19202 pop_block_exits(parser, previous_block_exits);
19203 pm_node_list_free(¤t_block_exits);
19207 case PM_TOKEN_KEYWORD_BEGIN_UPCASE: {
19209 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19211 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19212 pm_parser_err_current(parser, PM_ERR_STATEMENT_PREEXE_BEGIN);
19215 parser_lex(parser);
19218 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_BEGIN_UPCASE_BRACE);
19222 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM);
19225 pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
19228 flush_block_exits(parser, previous_block_exits);
19229 pm_node_list_free(¤t_block_exits);
19231 return (
pm_node_t *) pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous);
19233 case PM_TOKEN_KEYWORD_BREAK:
19234 case PM_TOKEN_KEYWORD_NEXT:
19235 case PM_TOKEN_KEYWORD_RETURN: {
19236 parser_lex(parser);
19242 token_begins_expression_p(parser->
current.type) ||
19243 match2(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)
19245 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].
left;
19247 if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
19249 parse_arguments(parser, &arguments,
false, PM_TOKEN_EOF, (uint16_t) (depth + 1));
19252 if (!accepts_command_call && arguments.
arguments != NULL) {
19258 switch (keyword.
type) {
19259 case PM_TOKEN_KEYWORD_BREAK: {
19264 case PM_TOKEN_KEYWORD_NEXT: {
19269 case PM_TOKEN_KEYWORD_RETURN: {
19271 parse_return(parser, node);
19275 assert(
false &&
"unreachable");
19279 case PM_TOKEN_KEYWORD_SUPER: {
19280 parser_lex(parser);
19284 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
19289 ((arguments.
block == NULL) || PM_NODE_TYPE_P(arguments.
block, PM_BLOCK_NODE))
19291 return (
pm_node_t *) pm_forwarding_super_node_create(parser, &keyword, &arguments);
19294 return (
pm_node_t *) pm_super_node_create(parser, &keyword, &arguments);
19296 case PM_TOKEN_KEYWORD_YIELD: {
19297 parser_lex(parser);
19301 parse_arguments_list(parser, &arguments,
false, accepts_command_call, (uint16_t) (depth + 1));
19307 if (arguments.
block != NULL) {
19308 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
19309 pm_node_destroy(parser, arguments.
block);
19310 arguments.
block = NULL;
19318 case PM_TOKEN_KEYWORD_CLASS: {
19319 size_t opening_newline_index = token_newline_index(parser);
19320 parser_lex(parser);
19323 pm_do_loop_stack_push(parser,
false);
19326 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19328 if (accept1(parser, PM_TOKEN_LESS_LESS)) {
19330 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));
19332 pm_parser_scope_push(parser,
true);
19333 if (!match2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
19338 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19339 pm_accepts_block_stack_push(parser,
true);
19341 pm_accepts_block_stack_pop(parser);
19344 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
19345 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
19346 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));
19348 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
19351 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
19356 pm_parser_scope_pop(parser);
19357 pm_do_loop_stack_pop(parser);
19359 flush_block_exits(parser, previous_block_exits);
19360 pm_node_list_free(¤t_block_exits);
19362 return (
pm_node_t *) pm_singleton_class_node_create(parser, &locals, &class_keyword, &
operator, expression, statements, &parser->
previous);
19365 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_CLASS_NAME, (uint16_t) (depth + 1));
19367 if (name.
type != PM_TOKEN_CONSTANT) {
19368 pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME);
19374 if (match1(parser, PM_TOKEN_LESS)) {
19375 inheritance_operator = parser->
current;
19376 lex_state_set(parser, PM_LEX_STATE_BEG);
19379 parser_lex(parser);
19381 superclass = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CLASS_SUPERCLASS, (uint16_t) (depth + 1));
19383 inheritance_operator = not_provided(parser);
19387 pm_parser_scope_push(parser,
true);
19389 if (inheritance_operator.
type != PM_TOKEN_NOT_PROVIDED) {
19390 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CLASS_UNEXPECTED_END);
19392 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19396 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19397 pm_accepts_block_stack_push(parser,
true);
19399 pm_accepts_block_stack_pop(parser);
19402 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
19403 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
19404 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));
19406 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
19409 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
19411 if (context_def_p(parser)) {
19412 pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
19418 pm_parser_scope_pop(parser);
19419 pm_do_loop_stack_pop(parser);
19421 if (!PM_NODE_TYPE_P(constant_path, PM_CONSTANT_PATH_NODE) && !(PM_NODE_TYPE_P(constant_path, PM_CONSTANT_READ_NODE))) {
19422 pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
19425 pop_block_exits(parser, previous_block_exits);
19426 pm_node_list_free(¤t_block_exits);
19428 return (
pm_node_t *) pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, &inheritance_operator, superclass, statements, &parser->
previous);
19430 case PM_TOKEN_KEYWORD_DEF: {
19432 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19435 size_t opening_newline_index = token_newline_index(parser);
19445 parser_lex(parser);
19449 bool valid_name =
true;
19451 switch (parser->
current.type) {
19452 case PM_CASE_OPERATOR:
19453 pm_parser_scope_push(parser,
true);
19454 lex_state_set(parser, PM_LEX_STATE_ENDFN);
19455 parser_lex(parser);
19459 case PM_TOKEN_IDENTIFIER: {
19460 parser_lex(parser);
19462 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
19463 receiver = parse_variable_call(parser);
19465 pm_parser_scope_push(parser,
true);
19466 lex_state_set(parser, PM_LEX_STATE_FNAME);
19467 parser_lex(parser);
19470 name = parse_method_definition_name(parser);
19473 pm_parser_scope_push(parser,
true);
19480 case PM_TOKEN_INSTANCE_VARIABLE:
19481 case PM_TOKEN_CLASS_VARIABLE:
19482 case PM_TOKEN_GLOBAL_VARIABLE:
19483 valid_name =
false;
19485 case PM_TOKEN_CONSTANT:
19486 case PM_TOKEN_KEYWORD_NIL:
19487 case PM_TOKEN_KEYWORD_SELF:
19488 case PM_TOKEN_KEYWORD_TRUE:
19489 case PM_TOKEN_KEYWORD_FALSE:
19490 case PM_TOKEN_KEYWORD___FILE__:
19491 case PM_TOKEN_KEYWORD___LINE__:
19492 case PM_TOKEN_KEYWORD___ENCODING__: {
19493 pm_parser_scope_push(parser,
true);
19494 parser_lex(parser);
19498 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
19499 lex_state_set(parser, PM_LEX_STATE_FNAME);
19500 parser_lex(parser);
19503 switch (identifier.
type) {
19504 case PM_TOKEN_CONSTANT:
19505 receiver = (
pm_node_t *) pm_constant_read_node_create(parser, &identifier);
19507 case PM_TOKEN_INSTANCE_VARIABLE:
19508 receiver = (
pm_node_t *) pm_instance_variable_read_node_create(parser, &identifier);
19510 case PM_TOKEN_CLASS_VARIABLE:
19511 receiver = (
pm_node_t *) pm_class_variable_read_node_create(parser, &identifier);
19513 case PM_TOKEN_GLOBAL_VARIABLE:
19514 receiver = (
pm_node_t *) pm_global_variable_read_node_create(parser, &identifier);
19516 case PM_TOKEN_KEYWORD_NIL:
19517 receiver = (
pm_node_t *) pm_nil_node_create(parser, &identifier);
19519 case PM_TOKEN_KEYWORD_SELF:
19520 receiver = (
pm_node_t *) pm_self_node_create(parser, &identifier);
19522 case PM_TOKEN_KEYWORD_TRUE:
19523 receiver = (
pm_node_t *) pm_true_node_create(parser, &identifier);
19525 case PM_TOKEN_KEYWORD_FALSE:
19526 receiver = (
pm_node_t *) pm_false_node_create(parser, &identifier);
19528 case PM_TOKEN_KEYWORD___FILE__:
19529 receiver = (
pm_node_t *) pm_source_file_node_create(parser, &identifier);
19531 case PM_TOKEN_KEYWORD___LINE__:
19532 receiver = (
pm_node_t *) pm_source_line_node_create(parser, &identifier);
19534 case PM_TOKEN_KEYWORD___ENCODING__:
19535 receiver = (
pm_node_t *) pm_source_encoding_node_create(parser, &identifier);
19541 name = parse_method_definition_name(parser);
19551 case PM_TOKEN_PARENTHESIS_LEFT: {
19556 context_pop(parser);
19557 parser_lex(parser);
19560 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEF_RECEIVER, (uint16_t) (depth + 1));
19562 accept1(parser, PM_TOKEN_NEWLINE);
19563 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19566 lex_state_set(parser, PM_LEX_STATE_FNAME);
19567 expect2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON, PM_ERR_DEF_RECEIVER_TERM);
19570 receiver = (
pm_node_t *) pm_parentheses_node_create(parser, &lparen, expression, &rparen, 0);
19574 pm_parser_scope_push(parser,
true);
19576 name = parse_method_definition_name(parser);
19580 pm_parser_scope_push(parser,
true);
19581 name = parse_method_definition_name(parser);
19589 switch (parser->
current.type) {
19590 case PM_TOKEN_PARENTHESIS_LEFT: {
19591 parser_lex(parser);
19594 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19597 params = parse_parameters(parser, PM_BINDING_POWER_DEFINED,
true,
false,
true,
true,
false, (uint16_t) (depth + 1));
19600 lex_state_set(parser, PM_LEX_STATE_BEG);
19603 context_pop(parser);
19604 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19613 case PM_CASE_PARAMETER: {
19616 if (parser->
current.type == PM_TOKEN_LABEL) {
19617 lex_state_set(parser, parser->
lex_state | PM_LEX_STATE_LABEL);
19620 lparen = not_provided(parser);
19621 rparen = not_provided(parser);
19622 params = parse_parameters(parser, PM_BINDING_POWER_DEFINED,
false,
false,
true,
true,
false, (uint16_t) (depth + 1));
19624 context_pop(parser);
19628 lparen = not_provided(parser);
19629 rparen = not_provided(parser);
19632 context_pop(parser);
19641 if (accept1(parser, PM_TOKEN_EQUAL)) {
19642 if (token_is_setter_name(&name)) {
19643 pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
19648 pm_do_loop_stack_push(parser,
false);
19649 statements = (
pm_node_t *) pm_statements_node_create(parser);
19651 bool allow_command_call;
19653 allow_command_call = accepts_command_call;
19656 allow_command_call = binding_power == PM_BINDING_POWER_ASSIGNMENT || binding_power < PM_BINDING_POWER_COMPOSITION;
19659 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_DEFINED + 1, allow_command_call,
false, PM_ERR_DEF_ENDLESS, (uint16_t) (depth + 1));
19661 if (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
19665 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));
19666 context_pop(parser);
19668 statement = (
pm_node_t *) pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value);
19671 pm_statements_node_body_append(parser, (
pm_statements_node_t *) statements, statement,
false);
19672 pm_do_loop_stack_pop(parser);
19673 context_pop(parser);
19674 end_keyword = not_provided(parser);
19676 equal = not_provided(parser);
19678 if (lparen.
type == PM_TOKEN_NOT_PROVIDED) {
19679 lex_state_set(parser, PM_LEX_STATE_BEG);
19681 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_DEF_PARAMS_TERM);
19683 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19686 pm_accepts_block_stack_push(parser,
true);
19687 pm_do_loop_stack_push(parser,
false);
19689 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19690 pm_accepts_block_stack_push(parser,
true);
19692 pm_accepts_block_stack_pop(parser);
19695 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
19696 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
19697 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));
19699 parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword,
false,
false);
19702 pm_accepts_block_stack_pop(parser);
19703 pm_do_loop_stack_pop(parser);
19705 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_DEF_TERM);
19711 pm_parser_scope_pop(parser);
19718 pm_constant_id_t name_id = pm_parser_constant_id_location(parser, name.
start, parse_operator_symbol_name(&name));
19720 flush_block_exits(parser, previous_block_exits);
19721 pm_node_list_free(¤t_block_exits);
19723 return (
pm_node_t *) pm_def_node_create(
19739 case PM_TOKEN_KEYWORD_DEFINED: {
19740 parser_lex(parser);
19748 bool newline = accept1(parser, PM_TOKEN_NEWLINE);
19750 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19753 if (newline && accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19754 expression = (
pm_node_t *) pm_parentheses_node_create(parser, &lparen, NULL, &parser->
previous, 0);
19755 lparen = not_provided(parser);
19756 rparen = not_provided(parser);
19758 expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19761 rparen = not_provided(parser);
19763 accept1(parser, PM_TOKEN_NEWLINE);
19764 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19769 lparen = not_provided(parser);
19770 rparen = not_provided(parser);
19771 expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19774 context_pop(parser);
19775 return (
pm_node_t *) pm_defined_node_create(
19780 &PM_LOCATION_TOKEN_VALUE(&keyword)
19783 case PM_TOKEN_KEYWORD_END_UPCASE: {
19784 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19785 pm_parser_err_current(parser, PM_ERR_STATEMENT_POSTEXE_END);
19788 parser_lex(parser);
19791 if (context_def_p(parser)) {
19792 pm_parser_warn_token(parser, &keyword, PM_WARN_END_IN_METHOD);
19795 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_END_UPCASE_BRACE);
19799 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM);
19800 return (
pm_node_t *) pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous);
19802 case PM_TOKEN_KEYWORD_FALSE:
19803 parser_lex(parser);
19805 case PM_TOKEN_KEYWORD_FOR: {
19806 size_t opening_newline_index = token_newline_index(parser);
19807 parser_lex(parser);
19815 if (accept1(parser, PM_TOKEN_USTAR)) {
19819 if (token_begins_expression_p(parser->
current.type)) {
19820 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19823 index = (
pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
19824 }
else if (token_begins_expression_p(parser->
current.type)) {
19825 index = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
19827 pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX);
19828 index = (
pm_node_t *) pm_missing_node_create(parser, for_keyword.
start, for_keyword.
end);
19832 if (match1(parser, PM_TOKEN_COMMA)) {
19833 index = parse_targets(parser, index, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19835 index = parse_target(parser, index,
false,
false);
19838 context_pop(parser);
19839 pm_do_loop_stack_push(parser,
true);
19841 expect1(parser, PM_TOKEN_KEYWORD_IN, PM_ERR_FOR_IN);
19844 pm_node_t *collection = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_FOR_COLLECTION, (uint16_t) (depth + 1));
19845 pm_do_loop_stack_pop(parser);
19848 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19851 do_keyword = not_provided(parser);
19852 if (!match2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE)) {
19858 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19859 statements = parse_statements(parser,
PM_CONTEXT_FOR, (uint16_t) (depth + 1));
19862 parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword,
false,
false);
19863 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM);
19865 return (
pm_node_t *) pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, &do_keyword, &parser->
previous);
19867 case PM_TOKEN_KEYWORD_IF:
19868 if (parser_end_of_line_p(parser)) {
19869 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
19872 size_t opening_newline_index = token_newline_index(parser);
19873 bool if_after_else = parser->
previous.
type == PM_TOKEN_KEYWORD_ELSE;
19874 parser_lex(parser);
19876 return parse_conditional(parser,
PM_CONTEXT_IF, opening_newline_index, if_after_else, (uint16_t) (depth + 1));
19877 case PM_TOKEN_KEYWORD_UNDEF: {
19878 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19879 pm_parser_err_current(parser, PM_ERR_STATEMENT_UNDEF);
19882 parser_lex(parser);
19884 pm_node_t *name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19886 if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) {
19887 pm_node_destroy(parser, name);
19889 pm_undef_node_append(undef, name);
19891 while (match1(parser, PM_TOKEN_COMMA)) {
19892 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
19893 parser_lex(parser);
19894 name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19896 if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) {
19897 pm_node_destroy(parser, name);
19901 pm_undef_node_append(undef, name);
19907 case PM_TOKEN_KEYWORD_NOT: {
19908 parser_lex(parser);
19917 if (!accepts_command_call && !match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19918 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES)) {
19919 pm_parser_err(parser, parser->
previous.
end, parser->
previous.
end + 1, PM_ERR_EXPECT_LPAREN_AFTER_NOT_LPAREN);
19921 accept1(parser, PM_TOKEN_NEWLINE);
19922 pm_parser_err_current(parser, PM_ERR_EXPECT_LPAREN_AFTER_NOT_OTHER);
19928 accept1(parser, PM_TOKEN_NEWLINE);
19930 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19933 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19934 receiver = (
pm_node_t *) pm_parentheses_node_create(parser, &lparen, NULL, &parser->
previous, 0);
19936 arguments.
opening_loc = PM_LOCATION_TOKEN_VALUE(&lparen);
19937 receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19940 accept1(parser, PM_TOKEN_NEWLINE);
19941 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19946 receiver = parse_expression(parser, PM_BINDING_POWER_NOT,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19949 return (
pm_node_t *) pm_call_node_not_create(parser, receiver, &message, &arguments);
19951 case PM_TOKEN_KEYWORD_UNLESS: {
19952 size_t opening_newline_index = token_newline_index(parser);
19953 parser_lex(parser);
19955 return parse_conditional(parser,
PM_CONTEXT_UNLESS, opening_newline_index,
false, (uint16_t) (depth + 1));
19957 case PM_TOKEN_KEYWORD_MODULE: {
19959 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19961 size_t opening_newline_index = token_newline_index(parser);
19962 parser_lex(parser);
19965 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_MODULE_NAME, (uint16_t) (depth + 1));
19970 if (PM_NODE_TYPE_P(constant_path, PM_MISSING_NODE)) {
19971 pop_block_exits(parser, previous_block_exits);
19972 pm_node_list_free(¤t_block_exits);
19975 return (
pm_node_t *) pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing);
19978 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
19981 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
19982 constant_path = (
pm_node_t *) pm_constant_path_node_create(parser, constant_path, &double_colon, &parser->
previous);
19989 if (name.
type != PM_TOKEN_CONSTANT) {
19990 pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
19993 pm_parser_scope_push(parser,
true);
19994 accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE);
19997 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19998 pm_accepts_block_stack_push(parser,
true);
20000 pm_accepts_block_stack_pop(parser);
20003 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
20004 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
20005 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));
20007 parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword,
false,
false);
20013 pm_parser_scope_pop(parser);
20014 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM);
20016 if (context_def_p(parser)) {
20017 pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
20020 pop_block_exits(parser, previous_block_exits);
20021 pm_node_list_free(¤t_block_exits);
20023 return (
pm_node_t *) pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->
previous);
20025 case PM_TOKEN_KEYWORD_NIL:
20026 parser_lex(parser);
20028 case PM_TOKEN_KEYWORD_REDO: {
20029 parser_lex(parser);
20036 case PM_TOKEN_KEYWORD_RETRY: {
20037 parser_lex(parser);
20040 parse_retry(parser, node);
20044 case PM_TOKEN_KEYWORD_SELF:
20045 parser_lex(parser);
20047 case PM_TOKEN_KEYWORD_TRUE:
20048 parser_lex(parser);
20050 case PM_TOKEN_KEYWORD_UNTIL: {
20051 size_t opening_newline_index = token_newline_index(parser);
20054 pm_do_loop_stack_push(parser,
true);
20056 parser_lex(parser);
20058 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
20060 pm_do_loop_stack_pop(parser);
20061 context_pop(parser);
20064 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
20067 do_keyword = not_provided(parser);
20068 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
20072 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
20073 pm_accepts_block_stack_push(parser,
true);
20074 statements = parse_statements(parser,
PM_CONTEXT_UNTIL, (uint16_t) (depth + 1));
20075 pm_accepts_block_stack_pop(parser);
20076 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
20079 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
20080 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM);
20082 return (
pm_node_t *) pm_until_node_create(parser, &keyword, &do_keyword, &parser->
previous, predicate, statements, 0);
20084 case PM_TOKEN_KEYWORD_WHILE: {
20085 size_t opening_newline_index = token_newline_index(parser);
20088 pm_do_loop_stack_push(parser,
true);
20090 parser_lex(parser);
20092 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
20094 pm_do_loop_stack_pop(parser);
20095 context_pop(parser);
20098 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
20101 do_keyword = not_provided(parser);
20102 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
20106 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
20107 pm_accepts_block_stack_push(parser,
true);
20108 statements = parse_statements(parser,
PM_CONTEXT_WHILE, (uint16_t) (depth + 1));
20109 pm_accepts_block_stack_pop(parser);
20110 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
20113 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
20114 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM);
20116 return (
pm_node_t *) pm_while_node_create(parser, &keyword, &do_keyword, &parser->
previous, predicate, statements, 0);
20118 case PM_TOKEN_PERCENT_LOWER_I: {
20119 parser_lex(parser);
20123 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20124 accept1(parser, PM_TOKEN_WORDS_SEP);
20125 if (match1(parser, PM_TOKEN_STRING_END))
break;
20127 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20130 pm_array_node_elements_append(array, (
pm_node_t *) pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing));
20133 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_LOWER_ELEMENT);
20137 if (match1(parser, PM_TOKEN_EOF)) {
20138 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
20141 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_LOWER_TERM);
20143 pm_array_node_close_set(array, &closing);
20147 case PM_TOKEN_PERCENT_UPPER_I: {
20148 parser_lex(parser);
20156 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20157 switch (parser->
current.type) {
20158 case PM_TOKEN_WORDS_SEP: {
20159 if (current == NULL) {
20165 pm_array_node_elements_append(array, current);
20169 parser_lex(parser);
20172 case PM_TOKEN_STRING_CONTENT: {
20176 if (current == NULL) {
20180 current = (
pm_node_t *) pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing);
20181 parser_lex(parser);
20182 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
20187 parser_lex(parser);
20190 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20199 pm_node_t *second_string = (
pm_node_t *) pm_string_node_create_current_string(parser, &opening, &parser->
previous, &closing);
20200 parser_lex(parser);
20203 pm_interpolated_symbol_node_append(interpolated, first_string);
20204 pm_interpolated_symbol_node_append(interpolated, second_string);
20209 assert(
false &&
"unreachable");
20214 case PM_TOKEN_EMBVAR: {
20215 bool start_location_set =
false;
20216 if (current == NULL) {
20222 current = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
20223 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20232 pm_interpolated_symbol_node_append(interpolated, current);
20234 start_location_set =
true;
20241 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20243 if (!start_location_set) {
20248 case PM_TOKEN_EMBEXPR_BEGIN: {
20249 bool start_location_set =
false;
20250 if (current == NULL) {
20256 current = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
20257 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20267 pm_interpolated_symbol_node_append(interpolated, current);
20269 start_location_set =
true;
20271 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
20275 assert(
false &&
"unreachable");
20278 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20280 if (!start_location_set) {
20286 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_UPPER_ELEMENT);
20287 parser_lex(parser);
20294 pm_array_node_elements_append(array, current);
20298 if (match1(parser, PM_TOKEN_EOF)) {
20299 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_UPPER_TERM);
20302 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_UPPER_TERM);
20304 pm_array_node_close_set(array, &closing);
20308 case PM_TOKEN_PERCENT_LOWER_W: {
20309 parser_lex(parser);
20314 accept1(parser, PM_TOKEN_WORDS_SEP);
20316 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20317 accept1(parser, PM_TOKEN_WORDS_SEP);
20318 if (match1(parser, PM_TOKEN_STRING_END))
break;
20320 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20325 pm_array_node_elements_append(array,
string);
20328 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_LOWER_ELEMENT);
20332 if (match1(parser, PM_TOKEN_EOF)) {
20333 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_LOWER_TERM);
20336 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_LOWER_TERM);
20339 pm_array_node_close_set(array, &closing);
20342 case PM_TOKEN_PERCENT_UPPER_W: {
20343 parser_lex(parser);
20351 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20352 switch (parser->
current.type) {
20353 case PM_TOKEN_WORDS_SEP: {
20358 if (current == NULL) {
20365 pm_array_node_elements_append(array, current);
20369 parser_lex(parser);
20372 case PM_TOKEN_STRING_CONTENT: {
20377 pm_node_flag_set(
string, parse_unescaped_encoding(parser));
20378 parser_lex(parser);
20380 if (current == NULL) {
20386 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
20391 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20397 pm_interpolated_string_node_append(interpolated, current);
20398 pm_interpolated_string_node_append(interpolated,
string);
20401 assert(
false &&
"unreachable");
20406 case PM_TOKEN_EMBVAR: {
20407 if (current == NULL) {
20414 current = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
20415 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20423 pm_interpolated_string_node_append(interpolated, current);
20431 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20435 case PM_TOKEN_EMBEXPR_BEGIN: {
20436 if (current == NULL) {
20443 current = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
20444 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20452 pm_interpolated_string_node_append(interpolated, current);
20454 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
20459 assert(
false &&
"unreachable");
20462 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20467 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_UPPER_ELEMENT);
20468 parser_lex(parser);
20475 pm_array_node_elements_append(array, current);
20479 if (match1(parser, PM_TOKEN_EOF)) {
20480 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_UPPER_TERM);
20483 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_UPPER_TERM);
20486 pm_array_node_close_set(array, &closing);
20489 case PM_TOKEN_REGEXP_BEGIN: {
20491 parser_lex(parser);
20493 if (match1(parser, PM_TOKEN_REGEXP_END)) {
20498 .
type = PM_TOKEN_STRING_CONTENT,
20503 parser_lex(parser);
20506 pm_node_flag_set(node, PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING);
20513 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20521 parser_lex(parser);
20526 if (accept1(parser, PM_TOKEN_REGEXP_END)) {
20533 if (!match1(parser, PM_TOKEN_EQUAL_TILDE)) {
20534 parse_regular_expression_errors(parser, node);
20537 pm_node_flag_set((
pm_node_t *) node, parse_and_validate_regular_expression_encoding(parser, &unescaped, ascii_only, node->base.
flags));
20543 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20553 pm_node_flag_set(part, PM_STRING_FLAGS_FORCED_BINARY_ENCODING);
20556 pm_interpolated_regular_expression_node_append(interpolated, part);
20561 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20567 while (!match2(parser, PM_TOKEN_REGEXP_END, PM_TOKEN_EOF)) {
20568 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20569 pm_interpolated_regular_expression_node_append(interpolated, part);
20574 if (match1(parser, PM_TOKEN_EOF)) {
20575 pm_parser_err_token(parser, &opening, PM_ERR_REGEXP_TERM);
20578 expect1(parser, PM_TOKEN_REGEXP_END, PM_ERR_REGEXP_TERM);
20581 pm_interpolated_regular_expression_node_closing_set(parser, interpolated, &closing);
20584 case PM_TOKEN_BACKTICK:
20585 case PM_TOKEN_PERCENT_LOWER_X: {
20586 parser_lex(parser);
20593 if (match1(parser, PM_TOKEN_STRING_END)) {
20598 .
type = PM_TOKEN_STRING_CONTENT,
20603 parser_lex(parser);
20604 return (
pm_node_t *) pm_xstring_node_create(parser, &opening, &content, &parser->
previous);
20609 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20616 parser_lex(parser);
20618 if (match1(parser, PM_TOKEN_STRING_END)) {
20619 pm_node_t *node = (
pm_node_t *) pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
20620 pm_node_flag_set(node, parse_unescaped_encoding(parser));
20621 parser_lex(parser);
20627 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20633 pm_node_flag_set(part, parse_unescaped_encoding(parser));
20635 pm_interpolated_xstring_node_append(node, part);
20640 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20644 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20645 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20646 pm_interpolated_xstring_node_append(node, part);
20651 if (match1(parser, PM_TOKEN_EOF)) {
20652 pm_parser_err_token(parser, &opening, PM_ERR_XSTRING_TERM);
20655 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_XSTRING_TERM);
20657 pm_interpolated_xstring_node_closing_set(node, &closing);
20661 case PM_TOKEN_USTAR: {
20662 parser_lex(parser);
20667 if (binding_power != PM_BINDING_POWER_STATEMENT) {
20668 pm_parser_err_prefix(parser, diag_id);
20675 if (token_begins_expression_p(parser->
current.type)) {
20676 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
20681 if (match1(parser, PM_TOKEN_COMMA)) {
20682 return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
20684 return parse_target_validate(parser, splat,
true);
20687 case PM_TOKEN_BANG: {
20688 if (binding_power > PM_BINDING_POWER_UNARY) {
20689 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20692 parser_lex(parser);
20695 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));
20696 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"!");
20698 pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
20701 case PM_TOKEN_TILDE: {
20702 if (binding_power > PM_BINDING_POWER_UNARY) {
20703 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20705 parser_lex(parser);
20708 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20709 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"~");
20713 case PM_TOKEN_UMINUS: {
20714 if (binding_power > PM_BINDING_POWER_UNARY) {
20715 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20717 parser_lex(parser);
20720 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20721 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"-@");
20725 case PM_TOKEN_UMINUS_NUM: {
20726 parser_lex(parser);
20729 pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20731 if (accept1(parser, PM_TOKEN_STAR_STAR)) {
20733 pm_node_t *exponent = parse_expression(parser, pm_binding_powers[exponent_operator.
type].right,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
20734 node = (
pm_node_t *) pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0);
20735 node = (
pm_node_t *) pm_call_node_unary_create(parser, &
operator, node,
"-@");
20737 switch (PM_NODE_TYPE(node)) {
20738 case PM_INTEGER_NODE:
20739 case PM_FLOAT_NODE:
20740 case PM_RATIONAL_NODE:
20741 case PM_IMAGINARY_NODE:
20742 parse_negative_numeric(node);
20745 node = (
pm_node_t *) pm_call_node_unary_create(parser, &
operator, node,
"-@");
20752 case PM_TOKEN_MINUS_GREATER: {
20756 size_t opening_newline_index = token_newline_index(parser);
20757 pm_accepts_block_stack_push(parser,
true);
20758 parser_lex(parser);
20761 pm_parser_scope_push(parser,
false);
20765 switch (parser->
current.type) {
20766 case PM_TOKEN_PARENTHESIS_LEFT: {
20768 parser_lex(parser);
20770 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
20771 block_parameters = pm_block_parameters_node_create(parser, NULL, &opening);
20773 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
true, (uint16_t) (depth + 1));
20776 accept1(parser, PM_TOKEN_NEWLINE);
20777 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
20779 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
20782 case PM_CASE_PARAMETER: {
20783 pm_accepts_block_stack_push(parser,
false);
20785 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
false, (uint16_t) (depth + 1));
20786 pm_accepts_block_stack_pop(parser);
20790 block_parameters = NULL;
20799 if (accept1(parser, PM_TOKEN_LAMBDA_BEGIN)) {
20802 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
20806 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20807 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE);
20809 expect1(parser, PM_TOKEN_KEYWORD_DO, PM_ERR_LAMBDA_OPEN);
20812 if (!match3(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20813 pm_accepts_block_stack_push(parser,
true);
20815 pm_accepts_block_stack_pop(parser);
20818 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20819 assert(body == NULL || PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE));
20820 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));
20822 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20825 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END);
20829 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
20832 pm_parser_scope_pop(parser);
20833 pm_accepts_block_stack_pop(parser);
20835 return (
pm_node_t *) pm_lambda_node_create(parser, &locals, &
operator, &opening, &parser->
previous, parameters, body);
20837 case PM_TOKEN_UPLUS: {
20838 if (binding_power > PM_BINDING_POWER_UNARY) {
20839 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20841 parser_lex(parser);
20844 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20845 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"+@");
20849 case PM_TOKEN_STRING_BEGIN:
20850 return parse_strings(parser, NULL, accepts_label, (uint16_t) (depth + 1));
20851 case PM_TOKEN_SYMBOL_BEGIN: {
20853 parser_lex(parser);
20855 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_END, (uint16_t) (depth + 1));
20866 if (diag_id != PM_ERR_CANNOT_PARSE_EXPRESSION) {
20867 pm_parser_err_prefix(parser, diag_id);
20873 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT,
pm_token_type_human(parser->
current.type), context_human(recoverable));
20874 }
else if (diag_id == PM_ERR_CANNOT_PARSE_EXPRESSION) {
20880 pm_parser_err_prefix(parser, diag_id);
20898parse_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) {
20899 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));
20903 if (match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
20907 parser_lex(parser);
20909 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));
20910 context_pop(parser);
20912 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
20924 switch (PM_NODE_TYPE(node)) {
20925 case PM_BEGIN_NODE: {
20930 case PM_LOCAL_VARIABLE_WRITE_NODE: {
20932 pm_locals_read(&pm_parser_scope_find(parser, cast->
depth)->
locals, cast->
name);
20935 case PM_PARENTHESES_NODE: {
20937 if (cast->
body != NULL) parse_assignment_value_local(parser, cast->
body);
20940 case PM_STATEMENTS_NODE: {
20945 parse_assignment_value_local(parser, statement);
20967parse_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) {
20968 bool permitted =
true;
20969 if (previous_binding_power != PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_USTAR)) permitted =
false;
20971 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));
20972 if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE);
20974 parse_assignment_value_local(parser, value);
20975 bool single_value =
true;
20977 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && (PM_NODE_TYPE_P(value, PM_SPLAT_NODE) || match1(parser, PM_TOKEN_COMMA))) {
20978 single_value =
false;
20983 pm_array_node_elements_append(array, value);
20986 while (accept1(parser, PM_TOKEN_COMMA)) {
20987 pm_node_t *element = parse_starred_expression(parser, binding_power,
false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1));
20989 pm_array_node_elements_append(array, element);
20990 if (PM_NODE_TYPE_P(element, PM_MISSING_NODE))
break;
20992 parse_assignment_value_local(parser, element);
20998 if ((single_value || (binding_power == (PM_BINDING_POWER_MULTI_ASSIGNMENT + 1))) && match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
21002 parser_lex(parser);
21004 bool accepts_command_call_inner =
false;
21008 if (PM_NODE_TYPE_P(value, PM_CALL_NODE)) {
21011 accepts_command_call_inner =
true;
21015 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));
21016 context_pop(parser);
21018 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
21034 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_ARGUMENTS);
21039 if (call_node->
block != NULL) {
21040 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_BLOCK);
21042 call_node->
block = NULL;
21071static inline const uint8_t *
21072pm_named_capture_escape_hex(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
21075 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
21076 uint8_t value = escape_hexadecimal_digit(*cursor);
21079 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
21080 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(*cursor));
21084 pm_buffer_append_byte(unescaped, value);
21086 pm_buffer_append_string(unescaped,
"\\x", 2);
21092static inline const uint8_t *
21093pm_named_capture_escape_octal(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
21094 uint8_t value = (uint8_t) (*cursor -
'0');
21097 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
21098 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
21101 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
21102 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
21107 pm_buffer_append_byte(unescaped, value);
21111static inline const uint8_t *
21112pm_named_capture_escape_unicode(
pm_parser_t *parser,
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
21113 const uint8_t *start = cursor - 1;
21116 if (cursor >= end) {
21117 pm_buffer_append_string(unescaped,
"\\u", 2);
21121 if (*cursor !=
'{') {
21122 size_t length = pm_strspn_hexadecimal_digit(cursor, MIN(end - cursor, 4));
21123 uint32_t value = escape_unicode(parser, cursor, length);
21125 if (!pm_buffer_append_unicode_codepoint(unescaped, value)) {
21126 pm_buffer_append_string(unescaped, (
const char *) start, (
size_t) ((cursor + length) - start));
21129 return cursor + length;
21134 while (cursor < end && *cursor ==
' ') cursor++;
21136 if (cursor >= end)
break;
21137 if (*cursor ==
'}') {
21142 size_t length = pm_strspn_hexadecimal_digit(cursor, end - cursor);
21143 uint32_t value = escape_unicode(parser, cursor, length);
21145 (void) pm_buffer_append_unicode_codepoint(unescaped, value);
21153pm_named_capture_escape(
pm_parser_t *parser,
pm_buffer_t *unescaped,
const uint8_t *source,
const size_t length,
const uint8_t *cursor) {
21154 const uint8_t *end = source + length;
21155 pm_buffer_append_string(unescaped, (
const char *) source, (
size_t) (cursor - source));
21158 if (++cursor >= end) {
21159 pm_buffer_append_byte(unescaped,
'\\');
21165 cursor = pm_named_capture_escape_hex(unescaped, cursor, end);
21167 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
21168 cursor = pm_named_capture_escape_octal(unescaped, cursor, end);
21171 cursor = pm_named_capture_escape_unicode(parser, unescaped, cursor, end);
21174 pm_buffer_append_byte(unescaped,
'\\');
21178 const uint8_t *next_cursor = pm_memchr(cursor,
'\\', (
size_t) (end - cursor), parser->
encoding_changed, parser->
encoding);
21179 if (next_cursor == NULL)
break;
21181 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (next_cursor - cursor));
21182 cursor = next_cursor;
21185 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (end - cursor));
21193parse_regular_expression_named_capture(
const pm_string_t *capture,
void *data) {
21214 pm_named_capture_escape(parser, &unescaped, source, length, cursor);
21224 if (!pm_slice_is_valid_local(parser, source, source + length)) {
21229 if (callback_data->
shared) {
21233 name = pm_parser_constant_id_location(parser, location.
start, location.
end);
21239 void *memory =
xmalloc(length);
21240 if (memory == NULL) abort();
21242 memcpy(memory, source, length);
21243 name = pm_parser_constant_id_owned(parser, (uint8_t *) memory, length);
21248 if (name != 0 && !pm_constant_id_list_includes(names, name)) {
21249 pm_constant_id_list_append(names, name);
21252 if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
21255 if (pm_local_is_keyword((
const char *) source, length)) {
21262 pm_parser_local_add(parser, name, location.
start, location.
end, 0);
21267 if (callback_data->
match == NULL) {
21268 callback_data->
match = pm_match_write_node_create(parser, call);
21273 pm_node_t *target = (
pm_node_t *) pm_local_variable_target_node_create(parser, &location, name, depth == -1 ? 0 : (uint32_t) depth);
21274 pm_node_list_append(&callback_data->
match->
targets, target);
21290 .shared = content->
type == PM_STRING_SHARED
21297 .shared = content->
type == PM_STRING_SHARED
21300 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);
21301 pm_constant_id_list_free(&callback_data.
names);
21303 if (callback_data.
match != NULL) {
21311parse_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) {
21314 switch (token.type) {
21315 case PM_TOKEN_EQUAL: {
21316 switch (PM_NODE_TYPE(node)) {
21317 case PM_CALL_NODE: {
21323 if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21328 case PM_CASE_WRITABLE: {
21332 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
21336 parser_lex(parser);
21337 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));
21339 if (PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) && previous_binding_power != PM_BINDING_POWER_STATEMENT) {
21340 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_MULTI_WRITE);
21343 return parse_write(parser, node, &token, value);
21345 case PM_SPLAT_NODE: {
21347 pm_multi_target_node_targets_append(parser, multi_target, node);
21349 parser_lex(parser);
21350 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));
21351 return parse_write(parser, (
pm_node_t *) multi_target, &token, value);
21353 case PM_SOURCE_ENCODING_NODE:
21354 case PM_FALSE_NODE:
21355 case PM_SOURCE_FILE_NODE:
21356 case PM_SOURCE_LINE_NODE:
21359 case PM_TRUE_NODE: {
21362 parser_lex(parser);
21363 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));
21364 return parse_unwriteable_write(parser, node, &token, value);
21370 parser_lex(parser);
21371 pm_parser_err_token(parser, &token, PM_ERR_EXPRESSION_NOT_WRITABLE);
21375 case PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL: {
21376 switch (PM_NODE_TYPE(node)) {
21377 case PM_BACK_REFERENCE_READ_NODE:
21378 case PM_NUMBERED_REFERENCE_READ_NODE:
21379 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21381 case PM_GLOBAL_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));
21385 pm_node_t *result = (
pm_node_t *) pm_global_variable_and_write_node_create(parser, node, &token, value);
21387 pm_node_destroy(parser, node);
21390 case PM_CLASS_VARIABLE_READ_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 pm_node_destroy(parser, node);
21399 case PM_CONSTANT_PATH_NODE: {
21400 parser_lex(parser);
21402 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));
21405 return parse_shareable_constant_write(parser, write);
21407 case PM_CONSTANT_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);
21414 return parse_shareable_constant_write(parser, write);
21416 case PM_INSTANCE_VARIABLE_READ_NODE: {
21417 parser_lex(parser);
21419 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));
21422 pm_node_destroy(parser, node);
21425 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21427 parser_lex(parser);
21429 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));
21430 pm_node_t *result = (
pm_node_t *) pm_local_variable_and_write_node_create(parser, node, &token, value, name, 0);
21432 parse_target_implicit_parameter(parser, node);
21433 pm_node_destroy(parser, node);
21436 case PM_LOCAL_VARIABLE_READ_NODE: {
21439 parse_target_implicit_parameter(parser, node);
21443 parser_lex(parser);
21445 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));
21448 pm_node_destroy(parser, node);
21451 case PM_CALL_NODE: {
21457 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21459 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21462 parser_lex(parser);
21464 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));
21465 pm_node_t *result = (
pm_node_t *) pm_local_variable_and_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21467 pm_node_destroy(parser, (
pm_node_t *) cast);
21473 parser_lex(parser);
21478 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21479 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));
21480 return (
pm_node_t *) pm_index_and_write_node_create(parser, cast, &token, value);
21484 if (pm_call_node_writable_p(parser, cast)) {
21485 parse_write_name(parser, &cast->
name);
21487 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21490 parse_call_operator_write(parser, cast, &token);
21491 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));
21492 return (
pm_node_t *) pm_call_and_write_node_create(parser, cast, &token, value);
21494 case PM_MULTI_WRITE_NODE: {
21495 parser_lex(parser);
21496 pm_parser_err_token(parser, &token, PM_ERR_AMPAMPEQ_MULTI_ASSIGN);
21500 parser_lex(parser);
21505 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
21509 case PM_TOKEN_PIPE_PIPE_EQUAL: {
21510 switch (PM_NODE_TYPE(node)) {
21511 case PM_BACK_REFERENCE_READ_NODE:
21512 case PM_NUMBERED_REFERENCE_READ_NODE:
21513 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21515 case PM_GLOBAL_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));
21519 pm_node_t *result = (
pm_node_t *) pm_global_variable_or_write_node_create(parser, node, &token, value);
21521 pm_node_destroy(parser, node);
21524 case PM_CLASS_VARIABLE_READ_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 pm_node_destroy(parser, node);
21533 case PM_CONSTANT_PATH_NODE: {
21534 parser_lex(parser);
21536 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));
21539 return parse_shareable_constant_write(parser, write);
21541 case PM_CONSTANT_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);
21548 return parse_shareable_constant_write(parser, write);
21550 case PM_INSTANCE_VARIABLE_READ_NODE: {
21551 parser_lex(parser);
21553 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));
21556 pm_node_destroy(parser, node);
21559 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21561 parser_lex(parser);
21563 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));
21564 pm_node_t *result = (
pm_node_t *) pm_local_variable_or_write_node_create(parser, node, &token, value, name, 0);
21566 parse_target_implicit_parameter(parser, node);
21567 pm_node_destroy(parser, node);
21570 case PM_LOCAL_VARIABLE_READ_NODE: {
21573 parse_target_implicit_parameter(parser, node);
21577 parser_lex(parser);
21579 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));
21582 pm_node_destroy(parser, node);
21585 case PM_CALL_NODE: {
21591 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21593 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21596 parser_lex(parser);
21598 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));
21599 pm_node_t *result = (
pm_node_t *) pm_local_variable_or_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21601 pm_node_destroy(parser, (
pm_node_t *) cast);
21607 parser_lex(parser);
21612 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21613 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));
21614 return (
pm_node_t *) pm_index_or_write_node_create(parser, cast, &token, value);
21618 if (pm_call_node_writable_p(parser, cast)) {
21619 parse_write_name(parser, &cast->
name);
21621 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21624 parse_call_operator_write(parser, cast, &token);
21625 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));
21626 return (
pm_node_t *) pm_call_or_write_node_create(parser, cast, &token, value);
21628 case PM_MULTI_WRITE_NODE: {
21629 parser_lex(parser);
21630 pm_parser_err_token(parser, &token, PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN);
21634 parser_lex(parser);
21639 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
21643 case PM_TOKEN_AMPERSAND_EQUAL:
21644 case PM_TOKEN_CARET_EQUAL:
21645 case PM_TOKEN_GREATER_GREATER_EQUAL:
21646 case PM_TOKEN_LESS_LESS_EQUAL:
21647 case PM_TOKEN_MINUS_EQUAL:
21648 case PM_TOKEN_PERCENT_EQUAL:
21649 case PM_TOKEN_PIPE_EQUAL:
21650 case PM_TOKEN_PLUS_EQUAL:
21651 case PM_TOKEN_SLASH_EQUAL:
21652 case PM_TOKEN_STAR_EQUAL:
21653 case PM_TOKEN_STAR_STAR_EQUAL: {
21654 switch (PM_NODE_TYPE(node)) {
21655 case PM_BACK_REFERENCE_READ_NODE:
21656 case PM_NUMBERED_REFERENCE_READ_NODE:
21657 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21659 case PM_GLOBAL_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));
21663 pm_node_t *result = (
pm_node_t *) pm_global_variable_operator_write_node_create(parser, node, &token, value);
21665 pm_node_destroy(parser, node);
21668 case PM_CLASS_VARIABLE_READ_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 pm_node_destroy(parser, node);
21677 case PM_CONSTANT_PATH_NODE: {
21678 parser_lex(parser);
21680 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21683 return parse_shareable_constant_write(parser, write);
21685 case PM_CONSTANT_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);
21692 return parse_shareable_constant_write(parser, write);
21694 case PM_INSTANCE_VARIABLE_READ_NODE: {
21695 parser_lex(parser);
21697 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));
21700 pm_node_destroy(parser, node);
21703 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21705 parser_lex(parser);
21707 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));
21708 pm_node_t *result = (
pm_node_t *) pm_local_variable_operator_write_node_create(parser, node, &token, value, name, 0);
21710 parse_target_implicit_parameter(parser, node);
21711 pm_node_destroy(parser, node);
21714 case PM_LOCAL_VARIABLE_READ_NODE: {
21717 parse_target_implicit_parameter(parser, node);
21721 parser_lex(parser);
21723 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));
21724 pm_node_t *result = (
pm_node_t *) pm_local_variable_operator_write_node_create(parser, node, &token, value, cast->
name, cast->
depth);
21726 pm_node_destroy(parser, node);
21729 case PM_CALL_NODE: {
21730 parser_lex(parser);
21736 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21738 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21741 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));
21742 pm_node_t *result = (
pm_node_t *) pm_local_variable_operator_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21744 pm_node_destroy(parser, (
pm_node_t *) cast);
21751 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21752 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));
21753 return (
pm_node_t *) pm_index_operator_write_node_create(parser, cast, &token, value);
21757 if (pm_call_node_writable_p(parser, cast)) {
21758 parse_write_name(parser, &cast->
name);
21760 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21763 parse_call_operator_write(parser, cast, &token);
21764 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));
21765 return (
pm_node_t *) pm_call_operator_write_node_create(parser, cast, &token, value);
21767 case PM_MULTI_WRITE_NODE: {
21768 parser_lex(parser);
21769 pm_parser_err_token(parser, &token, PM_ERR_OPERATOR_MULTI_ASSIGN);
21773 parser_lex(parser);
21782 case PM_TOKEN_AMPERSAND_AMPERSAND:
21783 case PM_TOKEN_KEYWORD_AND: {
21784 parser_lex(parser);
21786 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));
21787 return (
pm_node_t *) pm_and_node_create(parser, node, &token, right);
21789 case PM_TOKEN_KEYWORD_OR:
21790 case PM_TOKEN_PIPE_PIPE: {
21791 parser_lex(parser);
21793 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));
21794 return (
pm_node_t *) pm_or_node_create(parser, node, &token, right);
21796 case PM_TOKEN_EQUAL_TILDE: {
21804 parser_lex(parser);
21805 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21808 pm_call_node_t *call = pm_call_node_binary_create(parser, node, &token, argument, 0);
21814 if (PM_NODE_TYPE_P(node, PM_INTERPOLATED_REGULAR_EXPRESSION_NODE)) {
21821 bool interpolated =
false;
21822 size_t total_length = 0;
21826 if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
21829 interpolated =
true;
21834 if (!interpolated && total_length > 0) {
21835 void *memory =
xmalloc(total_length);
21836 if (!memory) abort();
21838 uint8_t *cursor = memory;
21848 pm_string_owned_init(&owned, (uint8_t *) memory, total_length);
21850 result = parse_regular_expression_named_captures(parser, &owned, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
21853 }
else if (PM_NODE_TYPE_P(node, PM_REGULAR_EXPRESSION_NODE)) {
21857 result = parse_regular_expression_named_captures(parser, content, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
21862 case PM_TOKEN_UAMPERSAND:
21863 case PM_TOKEN_USTAR:
21864 case PM_TOKEN_USTAR_STAR:
21867 case PM_TOKEN_BANG_EQUAL:
21868 case PM_TOKEN_BANG_TILDE:
21869 case PM_TOKEN_EQUAL_EQUAL:
21870 case PM_TOKEN_EQUAL_EQUAL_EQUAL:
21871 case PM_TOKEN_LESS_EQUAL_GREATER:
21872 case PM_TOKEN_CARET:
21873 case PM_TOKEN_PIPE:
21874 case PM_TOKEN_AMPERSAND:
21875 case PM_TOKEN_GREATER_GREATER:
21876 case PM_TOKEN_LESS_LESS:
21877 case PM_TOKEN_MINUS:
21878 case PM_TOKEN_PLUS:
21879 case PM_TOKEN_PERCENT:
21880 case PM_TOKEN_SLASH:
21881 case PM_TOKEN_STAR:
21882 case PM_TOKEN_STAR_STAR: {
21883 parser_lex(parser);
21885 switch (PM_NODE_TYPE(node)) {
21886 case PM_RESCUE_MODIFIER_NODE: {
21889 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21893 case PM_AND_NODE: {
21895 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21896 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21902 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21903 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21911 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21912 return (
pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument, 0);
21914 case PM_TOKEN_GREATER:
21915 case PM_TOKEN_GREATER_EQUAL:
21916 case PM_TOKEN_LESS:
21917 case PM_TOKEN_LESS_EQUAL: {
21918 if (PM_NODE_TYPE_P(node, PM_CALL_NODE) && PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_COMPARISON)) {
21919 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_COMPARISON_AFTER_COMPARISON);
21922 parser_lex(parser);
21923 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21924 return (
pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON);
21926 case PM_TOKEN_AMPERSAND_DOT:
21927 case PM_TOKEN_DOT: {
21928 parser_lex(parser);
21933 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
21934 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21935 return (
pm_node_t *) pm_call_node_shorthand_create(parser, node, &
operator, &arguments);
21938 switch (PM_NODE_TYPE(node)) {
21939 case PM_RESCUE_MODIFIER_NODE: {
21942 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21946 case PM_AND_NODE: {
21948 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21949 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21955 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21956 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21966 switch (parser->
current.type) {
21967 case PM_CASE_OPERATOR:
21968 case PM_CASE_KEYWORD:
21969 case PM_TOKEN_CONSTANT:
21970 case PM_TOKEN_IDENTIFIER:
21971 case PM_TOKEN_METHOD_NAME: {
21972 parser_lex(parser);
21982 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21983 pm_call_node_t *call = pm_call_node_call_create(parser, node, &
operator, &message, &arguments);
21986 (previous_binding_power == PM_BINDING_POWER_STATEMENT) &&
21989 match1(parser, PM_TOKEN_COMMA)
21991 return parse_targets_validate(parser, (
pm_node_t *) call, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21996 case PM_TOKEN_DOT_DOT:
21997 case PM_TOKEN_DOT_DOT_DOT: {
21998 parser_lex(parser);
22001 if (token_begins_expression_p(parser->
current.type)) {
22002 right = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22005 return (
pm_node_t *) pm_range_node_create(parser, node, &token, right);
22007 case PM_TOKEN_KEYWORD_IF_MODIFIER: {
22009 parser_lex(parser);
22011 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
22012 return (
pm_node_t *) pm_if_node_modifier_create(parser, node, &keyword, predicate);
22014 case PM_TOKEN_KEYWORD_UNLESS_MODIFIER: {
22016 parser_lex(parser);
22018 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
22019 return (
pm_node_t *) pm_unless_node_modifier_create(parser, node, &keyword, predicate);
22021 case PM_TOKEN_KEYWORD_UNTIL_MODIFIER: {
22022 parser_lex(parser);
22024 pm_statements_node_body_append(parser, statements, node,
true);
22026 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
22027 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);
22029 case PM_TOKEN_KEYWORD_WHILE_MODIFIER: {
22030 parser_lex(parser);
22032 pm_statements_node_body_append(parser, statements, node,
true);
22034 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
22035 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);
22037 case PM_TOKEN_QUESTION_MARK: {
22040 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
22043 parser_lex(parser);
22045 pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_TRUE, (uint16_t) (depth + 1));
22057 context_pop(parser);
22058 pop_block_exits(parser, previous_block_exits);
22059 pm_node_list_free(¤t_block_exits);
22061 return (
pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
22064 accept1(parser, PM_TOKEN_NEWLINE);
22065 expect1(parser, PM_TOKEN_COLON, PM_ERR_TERNARY_COLON);
22068 pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_FALSE, (uint16_t) (depth + 1));
22070 context_pop(parser);
22071 pop_block_exits(parser, previous_block_exits);
22072 pm_node_list_free(¤t_block_exits);
22074 return (
pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
22076 case PM_TOKEN_COLON_COLON: {
22077 parser_lex(parser);
22080 switch (parser->
current.type) {
22081 case PM_TOKEN_CONSTANT: {
22082 parser_lex(parser);
22086 (parser->
current.type == PM_TOKEN_PARENTHESIS_LEFT) ||
22087 (accepts_command_call && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)))
22098 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
22099 path = (
pm_node_t *) pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
22102 path = (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
22106 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
22107 return parse_targets_validate(parser, path, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22112 case PM_CASE_OPERATOR:
22113 case PM_CASE_KEYWORD:
22114 case PM_TOKEN_IDENTIFIER:
22115 case PM_TOKEN_METHOD_NAME: {
22116 parser_lex(parser);
22122 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
22123 pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
22126 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
22127 return parse_targets_validate(parser, (
pm_node_t *) call, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22132 case PM_TOKEN_PARENTHESIS_LEFT: {
22136 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
22138 return (
pm_node_t *) pm_call_node_shorthand_create(parser, node, &delimiter, &arguments);
22141 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
22142 return (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
22146 case PM_TOKEN_KEYWORD_RESCUE_MODIFIER: {
22148 parser_lex(parser);
22149 accept1(parser, PM_TOKEN_NEWLINE);
22151 pm_node_t *value = parse_expression(parser, binding_power,
true,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
22152 context_pop(parser);
22154 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, node, &token, value);
22156 case PM_TOKEN_BRACKET_LEFT: {
22157 parser_lex(parser);
22162 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
22163 pm_accepts_block_stack_push(parser,
true);
22164 parse_arguments(parser, &arguments,
false, PM_TOKEN_BRACKET_RIGHT, (uint16_t) (depth + 1));
22165 pm_accepts_block_stack_pop(parser);
22166 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_EXPECT_RBRACKET);
22173 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
22174 pm_call_node_t *aref = pm_call_node_aref_create(parser, node, &arguments);
22175 return parse_targets_validate(parser, (
pm_node_t *) aref, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22182 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
22183 block = parse_block(parser, (uint16_t) (depth + 1));
22184 pm_arguments_validate_block(parser, &arguments, block);
22185 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
22186 block = parse_block(parser, (uint16_t) (depth + 1));
22189 if (block != NULL) {
22190 if (arguments.
block != NULL) {
22191 pm_parser_err_node(parser, (
pm_node_t *) block, PM_ERR_ARGUMENT_AFTER_BLOCK);
22193 arguments.
arguments = pm_arguments_node_create(parser);
22195 pm_arguments_node_arguments_append(arguments.
arguments, arguments.
block);
22201 return (
pm_node_t *) pm_call_node_aref_create(parser, node, &arguments);
22203 case PM_TOKEN_KEYWORD_IN: {
22209 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
22210 parser_lex(parser);
22213 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));
22216 pm_constant_id_list_free(&captures);
22218 return (
pm_node_t *) pm_match_predicate_node_create(parser, node, pattern, &
operator);
22220 case PM_TOKEN_EQUAL_GREATER: {
22226 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
22227 parser_lex(parser);
22230 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));
22233 pm_constant_id_list_free(&captures);
22235 return (
pm_node_t *) pm_match_required_node_create(parser, node, pattern, &
operator);
22238 assert(
false &&
"unreachable");
22243#undef PM_PARSE_PATTERN_SINGLE
22244#undef PM_PARSE_PATTERN_TOP
22245#undef PM_PARSE_PATTERN_MULTI
22255 (node->
block == NULL || PM_NODE_TYPE_P(node->
block, PM_BLOCK_ARGUMENT_NODE)) &&
22269parse_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) {
22271 pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
22275 pm_node_t *node = parse_expression_prefix(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
22277 switch (PM_NODE_TYPE(node)) {
22278 case PM_MISSING_NODE:
22282 case PM_PRE_EXECUTION_NODE:
22283 case PM_POST_EXECUTION_NODE:
22284 case PM_ALIAS_GLOBAL_VARIABLE_NODE:
22285 case PM_ALIAS_METHOD_NODE:
22286 case PM_MULTI_WRITE_NODE:
22287 case PM_UNDEF_NODE:
22290 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
22300 if ((pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_COMPOSITION) && pm_call_node_command_p((
pm_call_node_t *) node)) {
22304 case PM_SYMBOL_NODE:
22308 if (pm_symbol_node_label_p(node)) {
22319 pm_token_type_t current_token_type;
22322 current_token_type = parser->
current.type,
22323 current_binding_powers = pm_binding_powers[current_token_type],
22324 binding_power <= current_binding_powers.
left &&
22325 current_binding_powers.
binary
22327 node = parse_expression_infix(parser, node, binding_power, current_binding_powers.
right, accepts_command_call, (uint16_t) (depth + 1));
22335 switch (PM_NODE_TYPE(node)) {
22336 case PM_MULTI_WRITE_NODE:
22339 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
22343 case PM_CLASS_VARIABLE_WRITE_NODE:
22344 case PM_CONSTANT_PATH_WRITE_NODE:
22345 case PM_CONSTANT_WRITE_NODE:
22346 case PM_GLOBAL_VARIABLE_WRITE_NODE:
22347 case PM_INSTANCE_VARIABLE_WRITE_NODE:
22348 case PM_LOCAL_VARIABLE_WRITE_NODE:
22351 if (PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
22359 if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
22369 if (current_binding_powers.
nonassoc) {
22372 if (match1(parser, current_token_type)) {
22384 if (PM_NODE_TYPE_P(node, PM_RANGE_NODE) && ((
pm_range_node_t *) node)->right == NULL) {
22385 if (match4(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_DOT, PM_TOKEN_AMPERSAND_DOT)) {
22390 if (PM_BINDING_POWER_TERM <= pm_binding_powers[parser->
current.type].left) {
22393 }
else if (current_binding_powers.
left <= pm_binding_powers[parser->
current.type].left) {
22398 if (accepts_command_call) {
22407 switch (node->
type) {
22408 case PM_CALL_NODE: {
22422 cast->
block == NULL &&
22432 cast->
block != NULL && PM_NODE_TYPE_P(cast->
block, PM_BLOCK_NODE)
22435 accepts_command_call =
false;
22440 case PM_CONSTANT_PATH_NODE:
22443 accepts_command_call =
false;
22458 if (PM_PARSER_COMMAND_LINE_OPTION_P(parser)) {
22459 if (statements == NULL) {
22460 statements = pm_statements_node_create(parser);
22464 pm_arguments_node_arguments_append(
22466 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2))
22469 pm_statements_node_body_append(parser, statements, (
pm_node_t *) pm_call_node_fcall_synthesized_create(
22472 pm_parser_constant_id_constant(parser,
"print", 5)
22476 if (PM_PARSER_COMMAND_LINE_OPTION_N(parser)) {
22477 if (PM_PARSER_COMMAND_LINE_OPTION_A(parser)) {
22478 if (statements == NULL) {
22479 statements = pm_statements_node_create(parser);
22483 pm_arguments_node_arguments_append(
22485 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$;", 2))
22488 pm_global_variable_read_node_t *receiver = pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2));
22489 pm_call_node_t *call = pm_call_node_call_synthesized_create(parser, (
pm_node_t *) receiver,
"split", arguments);
22493 pm_parser_constant_id_constant(parser,
"$F", 2),
22497 pm_statements_node_body_prepend(statements, (
pm_node_t *) write);
22501 pm_arguments_node_arguments_append(
22503 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$/", 2))
22506 if (PM_PARSER_COMMAND_LINE_OPTION_L(parser)) {
22508 pm_keyword_hash_node_elements_append(keywords, (
pm_node_t *) pm_assoc_node_create(
22510 (
pm_node_t *) pm_symbol_node_synthesized_create(parser,
"chomp"),
22512 (
pm_node_t *) pm_true_node_synthesized_create(parser)
22515 pm_arguments_node_arguments_append(arguments, (
pm_node_t *) keywords);
22516 pm_node_flag_set((
pm_node_t *) arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS);
22520 pm_statements_node_body_append(parser, wrapped_statements, (
pm_node_t *) pm_while_node_synthesized_create(
22522 (
pm_node_t *) pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser,
"gets", 4)),
22526 statements = wrapped_statements;
22541 pm_parser_scope_push(parser,
true);
22545 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
22547 parser_lex(parser);
22554 assert(statements->
body.
size > 0);
22555 pm_void_statement_check(parser, statements->
body.
nodes[statements->
body.
size - 1]);
22560 pm_parser_scope_pop(parser);
22565 statements = wrap_statements(parser, statements);
22567 flush_block_exits(parser, previous_block_exits);
22570 pm_node_list_free(¤t_block_exits);
22575 if (statements == NULL) {
22576 statements = pm_statements_node_create(parser);
22577 pm_statements_node_location_set(statements, parser->
start, parser->
start);
22580 return (
pm_node_t *) pm_program_node_create(parser, &locals, statements);
22597pm_strnstr(
const char *big,
const char *little,
size_t big_length) {
22598 size_t little_length = strlen(little);
22600 for (
const char *big_end = big + big_length; big < big_end; big++) {
22601 if (*big == *little && memcmp(big, little, little_length) == 0)
return big;
22608#define pm_parser_warn_shebang_carriage_return(parser, start, length) ((void) 0)
22616pm_parser_warn_shebang_carriage_return(
pm_parser_t *parser,
const uint8_t *start,
size_t length) {
22617 if (length > 2 && start[length - 2] ==
'\r' && start[length - 1] ==
'\n') {
22618 pm_parser_warn(parser, start, start + length, PM_WARN_SHEBANG_CARRIAGE_RETURN);
22629 const char *switches = pm_strnstr(engine,
" -", length);
22630 if (switches == NULL)
return;
22635 (
const uint8_t *) (switches + 1),
22636 length - ((
size_t) (switches - engine)) - 1,
22640 size_t encoding_length;
22643 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22655 assert(source != NULL);
22659 .lex_state = PM_LEX_STATE_BEG,
22660 .enclosure_nesting = 0,
22661 .lambda_enclosure_nesting = -1,
22662 .brace_nesting = 0,
22663 .do_loop_stack = 0,
22664 .accepts_block_stack = 0,
22667 .stack = {{ .mode = PM_LEX_DEFAULT }},
22671 .end = source + size,
22672 .previous = { .type = PM_TOKEN_EOF, .start = source, .end = source },
22673 .current = { .type = PM_TOKEN_EOF, .start = source, .end = source },
22674 .next_start = NULL,
22675 .heredoc_end = NULL,
22676 .data_loc = { .start = NULL, .end = NULL },
22677 .comment_list = { 0 },
22678 .magic_comment_list = { 0 },
22679 .warning_list = { 0 },
22680 .error_list = { 0 },
22681 .current_scope = NULL,
22682 .current_context = NULL,
22684 .encoding_changed_callback = NULL,
22685 .encoding_comment_start = source,
22686 .lex_callback = NULL,
22688 .constant_pool = { 0 },
22689 .newline_list = { 0 },
22693 .explicit_encoding = NULL,
22695 .parsing_eval =
false,
22696 .partial_script =
false,
22697 .command_start =
true,
22698 .recovering =
false,
22699 .encoding_locked =
false,
22700 .encoding_changed =
false,
22701 .pattern_matching_newlines =
false,
22702 .in_keyword_arg =
false,
22703 .current_block_exits = NULL,
22704 .semantic_token_seen =
false,
22706 .current_regular_expression_ascii_only =
false,
22707 .warn_mismatched_indentation =
true
22724 uint32_t constant_size = ((uint32_t) size) / 95;
22725 pm_constant_pool_init(&parser->
constant_pool, constant_size < 4 ? 4 : constant_size);
22730 size_t newline_size = size / 22;
22731 pm_newline_list_init(&parser->
newline_list, source, newline_size < 4 ? 4 : newline_size);
22734 if (options != NULL) {
22743 if (encoding_length > 0) {
22745 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22767 for (
size_t scope_index = 0; scope_index < options->
scopes_count; scope_index++) {
22769 pm_parser_scope_push(parser, scope_index == 0);
22775 for (
size_t local_index = 0; local_index < scope->
locals_count; local_index++) {
22781 void *allocated =
xmalloc(length);
22782 if (allocated == NULL)
continue;
22784 memcpy(allocated, source, length);
22785 pm_parser_local_add_owned(parser, (uint8_t *) allocated, length);
22796 pm_accepts_block_stack_push(parser,
true);
22799 if (size >= 3 && source[0] == 0xef && source[1] == 0xbb && source[2] == 0xbf) {
22812 bool search_shebang = PM_PARSER_COMMAND_LINE_OPTION_X(parser);
22829 const uint8_t *newline = next_newline(parser->
start, parser->
end - parser->
start);
22830 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - parser->
start);
22832 if (length > 2 && parser->
current.end[0] ==
'#' && parser->
current.end[1] ==
'!') {
22833 const char *engine;
22835 if ((engine = pm_strnstr((
const char *) parser->
start,
"ruby", length)) != NULL) {
22836 if (newline != NULL) {
22840 pm_parser_warn_shebang_carriage_return(parser, parser->
start, length + 1);
22845 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) parser->
start)));
22848 search_shebang =
false;
22850 search_shebang =
true;
22856 if (search_shebang) {
22859 bool found_shebang =
false;
22863 const uint8_t *cursor = parser->
start;
22867 const uint8_t *newline = next_newline(cursor, parser->
end - cursor);
22869 while (newline != NULL) {
22870 pm_newline_list_append(&parser->
newline_list, newline);
22872 cursor = newline + 1;
22873 newline = next_newline(cursor, parser->
end - cursor);
22875 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - cursor);
22876 if (length > 2 && cursor[0] ==
'#' && cursor[1] ==
'!') {
22877 const char *engine;
22878 if ((engine = pm_strnstr((
const char *) cursor,
"ruby", length)) != NULL) {
22879 found_shebang =
true;
22881 if (newline != NULL) {
22882 pm_parser_warn_shebang_carriage_return(parser, cursor, length + 1);
22887 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) cursor)));
22895 if (found_shebang) {
22897 parser->
current = (
pm_token_t) { .type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
22899 pm_parser_err(parser, parser->
start, parser->
start, PM_ERR_SCRIPT_NOT_FOUND);
22926 for (node = list->
head; node != NULL; node = next) {
22938pm_magic_comment_list_free(
pm_list_t *list) {
22941 for (node = list->
head; node != NULL; node = next) {
22955 pm_diagnostic_list_free(&parser->
error_list);
22967 pm_parser_scope_pop(parser);
22971 lex_mode_pop(parser);
22980 return parse_program(parser);
22990#define LINE_SIZE 4096
22991 char line[LINE_SIZE];
22993 while (memset(line,
'\n', LINE_SIZE), stream_fgets(line, LINE_SIZE, stream) != NULL) {
22994 size_t length = LINE_SIZE;
22995 while (length > 0 && line[length - 1] ==
'\n') length--;
22997 if (length == LINE_SIZE) {
23002 pm_buffer_append_string(buffer, line, length);
23008 pm_buffer_append_string(buffer, line, length);
23016 if (strncmp(line,
"__END__", 7) == 0)
return false;
23019 if (strncmp(line,
"__END__\n", 8) == 0)
return false;
23022 if (strncmp(line,
"__END__\r\n", 9) == 0)
return false;
23028 if (stream_feof(stream)) {
23047pm_parse_stream_unterminated_heredoc_p(
pm_parser_t *parser) {
23050 for (; diagnostic != NULL; diagnostic = (
pm_diagnostic_t *) diagnostic->node.next) {
23051 if (diagnostic->diag_id == PM_ERR_HEREDOC_TERM) {
23069 bool eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof);
23075 pm_node_destroy(parser, node);
23076 eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof);
23090pm_parse_success_p(
const uint8_t *source,
size_t size,
const char *data) {
23092 pm_options_read(&options, data);
23098 pm_node_destroy(&parser, node);
23107#undef PM_CASE_KEYWORD
23108#undef PM_CASE_OPERATOR
23109#undef PM_CASE_WRITABLE
23110#undef PM_STRING_EMPTY
23111#undef PM_LOCATION_NODE_BASE_VALUE
23112#undef PM_LOCATION_NODE_VALUE
23113#undef PM_LOCATION_NULL_VALUE
23114#undef PM_LOCATION_TOKEN_VALUE
23119#ifndef PRISM_EXCLUDE_SERIALIZATION
23123 pm_buffer_append_string(buffer,
"PRISM", 5);
23127 pm_buffer_append_byte(buffer, PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS ? 1 : 0);
23135 pm_serialize_header(buffer);
23137 pm_buffer_append_byte(buffer,
'\0');
23145pm_serialize_parse(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
23147 pm_options_read(&options, data);
23154 pm_serialize_header(buffer);
23156 pm_buffer_append_byte(buffer,
'\0');
23158 pm_node_destroy(&parser, node);
23171 pm_options_read(&options, data);
23175 pm_serialize_header(buffer);
23177 pm_buffer_append_byte(buffer,
'\0');
23179 pm_node_destroy(&parser, node);
23189pm_serialize_parse_comments(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
23191 pm_options_read(&options, data);
23197 pm_serialize_header(buffer);
23199 pm_buffer_append_varsint(buffer, parser.
start_line);
23202 pm_node_destroy(&parser, node);
23216 PM_SLICE_TYPE_ERROR = -1,
23219 PM_SLICE_TYPE_NONE,
23222 PM_SLICE_TYPE_LOCAL,
23225 PM_SLICE_TYPE_CONSTANT,
23228 PM_SLICE_TYPE_METHOD_NAME
23235pm_slice_type(
const uint8_t *source,
size_t length,
const char *encoding_name) {
23237 const pm_encoding_t *encoding = pm_encoding_find((
const uint8_t *) encoding_name, (
const uint8_t *) (encoding_name + strlen(encoding_name)));
23238 if (encoding == NULL)
return PM_SLICE_TYPE_ERROR;
23241 if (length == 0)
return PM_SLICE_TYPE_NONE;
23244 if ((width = encoding->
alpha_char(source, (ptrdiff_t) length)) != 0) {
23246 }
else if (*source ==
'_') {
23249 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, (ptrdiff_t) length)) > 0)) {
23253 return PM_SLICE_TYPE_NONE;
23257 const uint8_t *end = source + length;
23258 pm_slice_type_t result = encoding->
isupper_char(source, end - source) ? PM_SLICE_TYPE_CONSTANT : PM_SLICE_TYPE_LOCAL;
23264 while (source < end) {
23265 if ((width = encoding->
alnum_char(source, end - source)) != 0) {
23268 }
else if (*source ==
'_') {
23271 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, end - source)) > 0)) {
23281 if (*source ==
'!' || *source ==
'?' || *source ==
'=') {
23283 result = PM_SLICE_TYPE_METHOD_NAME;
23287 return source == end ? result : PM_SLICE_TYPE_NONE;
23294pm_string_query_local(
const uint8_t *source,
size_t length,
const char *encoding_name) {
23295 switch (pm_slice_type(source, length, encoding_name)) {
23296 case PM_SLICE_TYPE_ERROR:
23298 case PM_SLICE_TYPE_NONE:
23299 case PM_SLICE_TYPE_CONSTANT:
23300 case PM_SLICE_TYPE_METHOD_NAME:
23302 case PM_SLICE_TYPE_LOCAL:
23306 assert(
false &&
"unreachable");
23314pm_string_query_constant(
const uint8_t *source,
size_t length,
const char *encoding_name) {
23315 switch (pm_slice_type(source, length, encoding_name)) {
23316 case PM_SLICE_TYPE_ERROR:
23318 case PM_SLICE_TYPE_NONE:
23319 case PM_SLICE_TYPE_LOCAL:
23320 case PM_SLICE_TYPE_METHOD_NAME:
23322 case PM_SLICE_TYPE_CONSTANT:
23326 assert(
false &&
"unreachable");
23334pm_string_query_method_name(
const uint8_t *source,
size_t length,
const char *encoding_name) {
23335#define B(p) ((p) ? PM_STRING_QUERY_TRUE : PM_STRING_QUERY_FALSE)
23336#define C1(c) (*source == c)
23337#define C2(s) (memcmp(source, s, 2) == 0)
23338#define C3(s) (memcmp(source, s, 3) == 0)
23340 switch (pm_slice_type(source, length, encoding_name)) {
23341 case PM_SLICE_TYPE_ERROR:
23343 case PM_SLICE_TYPE_NONE:
23345 case PM_SLICE_TYPE_LOCAL:
23347 return B((length != 2) || (source[0] !=
'_') || (source[1] ==
'0') || !pm_char_is_decimal_digit(source[1]));
23348 case PM_SLICE_TYPE_CONSTANT:
23350 case PM_SLICE_TYPE_METHOD_NAME:
23357 return B(C1(
'&') || C1(
'`') || C1(
'!') || C1(
'^') || C1(
'>') || C1(
'<') || C1(
'-') || C1(
'%') || C1(
'|') || C1(
'+') || C1(
'/') || C1(
'*') || C1(
'~'));
23359 return B(C2(
"!=") || C2(
"!~") || C2(
"[]") || C2(
"==") || C2(
"=~") || C2(
">=") || C2(
">>") || C2(
"<=") || C2(
"<<") || C2(
"**"));
23361 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 equal_loc
CallNode::equal_loc.
pm_location_t call_operator_loc
CallNode::call_operator_loc.
pm_location_t message_loc
CallNode::message_loc.
struct pm_arguments_node * arguments
CallNode::arguments.
struct pm_node * block
CallNode::block.
struct pm_node_list conditions
CaseMatchNode::conditions.
struct pm_node_list conditions
CaseNode::conditions.
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.