15#define PM_TAB_WHITESPACE_SIZE 8
18#define MIN(a,b) (((a)<(b))?(a):(b))
19#define MAX(a,b) (((a)>(b))?(a):(b))
30lex_mode_incrementor(
const uint8_t start) {
47lex_mode_terminator(
const uint8_t start) {
89lex_mode_push_list(
pm_parser_t *parser,
bool interpolation, uint8_t delimiter) {
90 uint8_t incrementor = lex_mode_incrementor(delimiter);
91 uint8_t terminator = lex_mode_terminator(delimiter);
97 .interpolation = interpolation,
98 .incrementor = incrementor,
99 .terminator = terminator
106 memcpy(breakpoints,
"\\ \t\f\r\v\n\0\0\0",
sizeof(lex_mode.
as.list.
breakpoints));
111 if (terminator !=
'\0') {
112 breakpoints[index++] = terminator;
118 breakpoints[index++] =
'#';
122 if (incrementor !=
'\0') {
123 breakpoints[index++] = incrementor;
127 return lex_mode_push(parser, lex_mode);
137 return lex_mode_push_list(parser,
false,
'\0');
144lex_mode_push_regexp(
pm_parser_t *parser, uint8_t incrementor, uint8_t terminator) {
146 .
mode = PM_LEX_REGEXP,
149 .incrementor = incrementor,
150 .terminator = terminator
158 memcpy(breakpoints,
"\r\n\\#\0\0",
sizeof(lex_mode.
as.regexp.
breakpoints));
162 if (terminator !=
'\0') {
163 breakpoints[index++] = terminator;
167 if (incrementor !=
'\0') {
168 breakpoints[index++] = incrementor;
172 return lex_mode_push(parser, lex_mode);
179lex_mode_push_string(
pm_parser_t *parser,
bool interpolation,
bool label_allowed, uint8_t incrementor, uint8_t terminator) {
181 .
mode = PM_LEX_STRING,
184 .interpolation = interpolation,
185 .label_allowed = label_allowed,
186 .incrementor = incrementor,
187 .terminator = terminator
194 memcpy(breakpoints,
"\r\n\\\0\0\0",
sizeof(lex_mode.
as.string.
breakpoints));
199 if (terminator !=
'\0') {
200 breakpoints[index++] = terminator;
206 breakpoints[index++] =
'#';
211 if (incrementor !=
'\0') {
212 breakpoints[index++] = incrementor;
216 return lex_mode_push(parser, lex_mode);
226 return lex_mode_push_string(parser,
false,
false,
'\0',
'\0');
258 PM_IGNORED_NEWLINE_NONE = 0,
259 PM_IGNORED_NEWLINE_ALL,
260 PM_IGNORED_NEWLINE_PATTERN
261} pm_ignored_newline_type_t;
263static inline pm_ignored_newline_type_t
265 bool ignored = lex_state_p(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_CLASS | PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT) && !lex_state_p(parser, PM_LEX_STATE_LABELED);
268 return PM_IGNORED_NEWLINE_ALL;
269 }
else if ((parser->
lex_state & ~((
unsigned int) PM_LEX_STATE_LABEL)) == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)) {
270 return PM_IGNORED_NEWLINE_PATTERN;
272 return PM_IGNORED_NEWLINE_NONE;
278 return lex_state_p(parser, PM_LEX_STATE_BEG_ANY) || ((parser->
lex_state & (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)) == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED));
283 return lex_state_p(parser, PM_LEX_STATE_ARG_ANY);
287lex_state_spcarg_p(
pm_parser_t *parser,
bool space_seen) {
291 return lex_state_arg_p(parser) && space_seen && !pm_char_is_whitespace(*parser->
current.end);
296 return lex_state_p(parser, PM_LEX_STATE_END_ANY);
304 return lex_state_p(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT);
316#ifndef PM_DEBUG_LOGGING
321#define PM_DEBUG_LOGGING 0
327 fprintf(stderr,
"STATE: ");
330 if (parser->
lex_state == PM_LEX_STATE_NONE) {
331 fprintf(stderr,
"NONE\n");
335#define CHECK_STATE(state) \
336 if (parser->lex_state & state) { \
337 if (!first) fprintf(stderr, "|"); \
338 fprintf(stderr, "%s", #state); \
342 CHECK_STATE(PM_LEX_STATE_BEG)
343 CHECK_STATE(PM_LEX_STATE_END)
344 CHECK_STATE(PM_LEX_STATE_ENDARG)
345 CHECK_STATE(PM_LEX_STATE_ENDFN)
346 CHECK_STATE(PM_LEX_STATE_ARG)
347 CHECK_STATE(PM_LEX_STATE_CMDARG)
348 CHECK_STATE(PM_LEX_STATE_MID)
349 CHECK_STATE(PM_LEX_STATE_FNAME)
350 CHECK_STATE(PM_LEX_STATE_DOT)
351 CHECK_STATE(PM_LEX_STATE_CLASS)
352 CHECK_STATE(PM_LEX_STATE_LABEL)
353 CHECK_STATE(PM_LEX_STATE_LABELED)
354 CHECK_STATE(PM_LEX_STATE_FITEM)
358 fprintf(stderr,
"\n");
363 fprintf(stderr,
"Caller: %s:%d\nPrevious: ", caller_name, line_number);
365 lex_state_set(parser, state);
366 fprintf(stderr,
"Now: ");
368 fprintf(stderr,
"\n");
371#define lex_state_set(parser, state) debug_lex_state_set(parser, state, __func__, __LINE__)
379#define PM_PARSER_COMMAND_LINE_OPTION(parser, option) ((parser)->command_line & (option))
382#define PM_PARSER_COMMAND_LINE_OPTION_A(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_A)
385#define PM_PARSER_COMMAND_LINE_OPTION_E(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_E)
388#define PM_PARSER_COMMAND_LINE_OPTION_L(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_L)
391#define PM_PARSER_COMMAND_LINE_OPTION_N(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_N)
394#define PM_PARSER_COMMAND_LINE_OPTION_P(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_P)
397#define PM_PARSER_COMMAND_LINE_OPTION_X(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_X)
408 pm_diagnostic_list_append(&parser->
error_list, start, end, diag_id);
414#define PM_PARSER_ERR_FORMAT(parser, start, end, diag_id, ...) \
415 pm_diagnostic_list_append_format(&parser->error_list, start, end, diag_id, __VA_ARGS__)
423 pm_parser_err(parser, parser->
current.start, parser->
current.end, diag_id);
430#define PM_PARSER_ERR_LOCATION_FORMAT(parser, location, diag_id, ...) \
431 PM_PARSER_ERR_FORMAT(parser, (location)->start, (location)->end, diag_id, __VA_ARGS__)
446#define PM_PARSER_ERR_NODE_FORMAT(parser, node, diag_id, ...) \
447 PM_PARSER_ERR_FORMAT(parser, (node)->location.start, (node)->location.end, diag_id, __VA_ARGS__)
453#define PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, diag_id) \
454 PM_PARSER_ERR_NODE_FORMAT(parser, node, diag_id, (int) ((node)->location.end - (node)->location.start), (const char *) (node)->location.start)
471 pm_parser_err(parser, token->start, token->end, diag_id);
478#define PM_PARSER_ERR_TOKEN_FORMAT(parser, token, diag_id, ...) \
479 PM_PARSER_ERR_FORMAT(parser, (token).start, (token).end, diag_id, __VA_ARGS__)
485#define PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, token, diag_id) \
486 PM_PARSER_ERR_TOKEN_FORMAT(parser, token, diag_id, (int) ((token).end - (token).start), (const char *) (token).start)
493 pm_diagnostic_list_append(&parser->
warning_list, start, end, diag_id);
502 pm_parser_warn(parser, token->start, token->end, diag_id);
517#define PM_PARSER_WARN_FORMAT(parser, start, end, diag_id, ...) \
518 pm_diagnostic_list_append_format(&parser->warning_list, start, end, diag_id, __VA_ARGS__)
524#define PM_PARSER_WARN_TOKEN_FORMAT(parser, token, diag_id, ...) \
525 PM_PARSER_WARN_FORMAT(parser, (token).start, (token).end, diag_id, __VA_ARGS__)
531#define PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, token, diag_id) \
532 PM_PARSER_WARN_TOKEN_FORMAT(parser, token, diag_id, (int) ((token).end - (token).start), (const char *) (token).start)
538#define PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, ...) \
539 PM_PARSER_WARN_FORMAT(parser, (node)->location.start, (node)->location.end, diag_id, __VA_ARGS__)
547pm_parser_err_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
548 PM_PARSER_ERR_FORMAT(
551 ident_start + ident_length,
554 (
const char *) ident_start
566pm_parser_scope_push(
pm_parser_t *parser,
bool closed) {
568 if (scope == NULL)
return false;
573 .parameters = PM_SCOPE_PARAMETERS_NONE,
574 .implicit_parameters = { 0 },
592 if (scope->
previous == NULL)
return true;
593 if (scope->
closed)
return false;
594 }
while ((scope = scope->
previous) != NULL);
596 assert(
false &&
"unreachable");
604pm_parser_scope_find(
pm_parser_t *parser, uint32_t depth) {
607 while (depth-- > 0) {
608 assert(scope != NULL);
616 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS,
617 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT,
618 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL
619} pm_scope_forwarding_param_check_result_t;
621static pm_scope_forwarding_param_check_result_t
622pm_parser_scope_forwarding_param_check(
pm_parser_t *parser,
const uint8_t mask) {
624 bool conflict =
false;
626 while (scope != NULL) {
630 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT;
632 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS;
643 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL;
648 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_BLOCK)) {
649 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
652 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
653 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_AMPERSAND);
655 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
656 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_AMPERSAND);
663 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS)) {
664 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
667 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
668 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR);
670 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
671 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR);
678 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_ALL)) {
679 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
682 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
687 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
688 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
695 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS)) {
696 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
699 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
700 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR_STAR);
702 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
703 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR_STAR);
712pm_parser_scope_shareable_constant_get(
pm_parser_t *parser) {
736#define PM_LOCALS_HASH_THRESHOLD 9
751 name = ((name >> 16) ^ name) * 0x45d9f3b;
752 name = ((name >> 16) ^ name) * 0x45d9f3b;
753 name = (name >> 16) ^ name;
763 uint32_t next_capacity = locals->
capacity == 0 ? 4 : (locals->
capacity * 2);
764 assert(next_capacity > locals->
capacity);
767 if (next_locals == NULL) abort();
769 if (next_capacity < PM_LOCALS_HASH_THRESHOLD) {
770 if (locals->
size > 0) {
776 bool hash_needed = (locals->
capacity <= PM_LOCALS_HASH_THRESHOLD);
777 uint32_t mask = next_capacity - 1;
779 for (uint32_t index = 0; index < locals->
capacity; index++) {
783 if (hash_needed) local->
hash = pm_locals_hash(local->
name);
785 uint32_t hash = local->
hash;
787 next_locals[hash & mask] = *local;
792 pm_locals_free(locals);
793 locals->
locals = next_locals;
815 pm_locals_resize(locals);
818 if (locals->
capacity < PM_LOCALS_HASH_THRESHOLD) {
819 for (uint32_t index = 0; index < locals->
capacity; index++) {
825 .location = { .start = start, .end = end },
826 .index = locals->
size++,
831 }
else if (local->
name == name) {
836 uint32_t mask = locals->
capacity - 1;
837 uint32_t hash = pm_locals_hash(name);
838 uint32_t initial_hash = hash;
846 .location = { .start = start, .end = end },
847 .index = locals->
size++,
852 }
else if (local->
name == name) {
857 }
while ((hash & mask) != initial_hash);
860 assert(
false &&
"unreachable");
870 if (locals->
capacity < PM_LOCALS_HASH_THRESHOLD) {
871 for (uint32_t index = 0; index < locals->
size; index++) {
873 if (local->
name == name)
return index;
876 uint32_t mask = locals->
capacity - 1;
877 uint32_t hash = pm_locals_hash(name);
878 uint32_t initial_hash = hash & mask;
885 }
else if (local->
name == name) {
890 }
while ((hash & mask) != initial_hash);
902 uint32_t index = pm_locals_find(locals, name);
903 assert(index != UINT32_MAX);
906 assert(local->
reads < UINT32_MAX);
917 uint32_t index = pm_locals_find(locals, name);
918 assert(index != UINT32_MAX);
921 assert(local->
reads > 0);
931 uint32_t index = pm_locals_find(locals, name);
932 assert(index != UINT32_MAX);
947 pm_constant_id_list_init_capacity(list, locals->
size);
952 uint32_t capacity = locals->
capacity < PM_LOCALS_HASH_THRESHOLD ? locals->
size : locals->
capacity;
956 bool warn_unused = !toplevel || (!parser->parsing_eval && !PM_PARSER_COMMAND_LINE_OPTION_E(parser));
958 for (uint32_t index = 0; index < capacity; index++) {
962 pm_constant_id_list_insert(list, (
size_t) local->
index, local->
name);
964 if (warn_unused && local->
reads == 0 && ((parser->start_line >= 0) || (pm_newline_list_line(&parser->newline_list, local->
location.
start, parser->start_line) >= 0))) {
965 pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, local->
name);
967 if (constant->
length >= 1 && *constant->
start !=
'_') {
968 PM_PARSER_WARN_FORMAT(
972 PM_WARN_UNUSED_LOCAL_VARIABLE,
974 (
const char *) constant->
start
990pm_parser_constant_id_location(
pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
991 return pm_constant_pool_insert_shared(&parser->
constant_pool, start, (
size_t) (end - start));
998pm_parser_constant_id_owned(
pm_parser_t *parser, uint8_t *start,
size_t length) {
999 return pm_constant_pool_insert_owned(&parser->
constant_pool, start, length);
1006pm_parser_constant_id_constant(
pm_parser_t *parser,
const char *start,
size_t length) {
1007 return pm_constant_pool_insert_constant(&parser->
constant_pool, (
const uint8_t *) start, length);
1015 return pm_parser_constant_id_location(parser, token->start, token->end);
1024 return token->type == PM_TOKEN_NOT_PROVIDED ? 0 : pm_parser_constant_id_token(parser, token);
1036 while (node != NULL) {
1037 switch (PM_NODE_TYPE(node)) {
1038 case PM_RETURN_NODE:
1043 case PM_MATCH_REQUIRED_NODE:
1044 return void_node != NULL ? void_node : node;
1045 case PM_MATCH_PREDICATE_NODE:
1047 case PM_BEGIN_NODE: {
1053 if (vn != NULL)
return vn;
1058 if (vn != NULL)
return vn;
1066 if (vn == NULL)
return NULL;
1067 if (void_node == NULL) void_node = vn;
1070 pm_node_t *vn = pm_check_value_expression(parser, (
pm_node_t *) rescue_clause->statements);
1075 if (void_node == NULL) {
1091 case PM_ENSURE_NODE: {
1096 case PM_PARENTHESES_NODE: {
1101 case PM_STATEMENTS_NODE: {
1115 if (void_node == NULL) {
1121 case PM_UNLESS_NODE: {
1130 if (void_node == NULL) {
1136 case PM_ELSE_NODE: {
1151 case PM_LOCAL_VARIABLE_WRITE_NODE: {
1155 for (uint32_t depth = 0; depth < cast->
depth; depth++) scope = scope->
previous;
1170 pm_node_t *void_node = pm_check_value_expression(parser, node);
1171 if (void_node != NULL) {
1172 pm_parser_err_node(parser, void_node, PM_ERR_VOID_EXPRESSION);
1181 const char *
type = NULL;
1184 switch (PM_NODE_TYPE(node)) {
1185 case PM_BACK_REFERENCE_READ_NODE:
1186 case PM_CLASS_VARIABLE_READ_NODE:
1187 case PM_GLOBAL_VARIABLE_READ_NODE:
1188 case PM_INSTANCE_VARIABLE_READ_NODE:
1189 case PM_LOCAL_VARIABLE_READ_NODE:
1190 case PM_NUMBERED_REFERENCE_READ_NODE:
1191 type =
"a variable";
1194 case PM_CALL_NODE: {
1199 switch (message->
length) {
1201 switch (message->
start[0]) {
1218 switch (message->
start[1]) {
1220 if (message->
start[0] ==
'<' || message->
start[0] ==
'>' || message->
start[0] ==
'!' || message->
start[0] ==
'=') {
1226 if (message->
start[0] ==
'+' || message->
start[0] ==
'-') {
1232 if (message->
start[0] ==
'*') {
1240 if (memcmp(message->
start,
"<=>", 3) == 0) {
1249 case PM_CONSTANT_PATH_NODE:
1253 case PM_CONSTANT_READ_NODE:
1254 type =
"a constant";
1257 case PM_DEFINED_NODE:
1266 case PM_IMAGINARY_NODE:
1267 case PM_INTEGER_NODE:
1268 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
1269 case PM_INTERPOLATED_STRING_NODE:
1270 case PM_RATIONAL_NODE:
1271 case PM_REGULAR_EXPRESSION_NODE:
1272 case PM_SOURCE_ENCODING_NODE:
1273 case PM_SOURCE_FILE_NODE:
1274 case PM_SOURCE_LINE_NODE:
1275 case PM_STRING_NODE:
1276 case PM_SYMBOL_NODE:
1284 case PM_RANGE_NODE: {
1287 if (PM_NODE_FLAG_P(cast, PM_RANGE_FLAGS_EXCLUDE_END)) {
1310 PM_PARSER_WARN_NODE_FORMAT(parser, node, PM_WARN_VOID_STATEMENT, length,
type);
1321 const size_t size = node->
body.
size - (last_value ? 1 : 0);
1322 for (
size_t index = 0; index < size; index++) {
1323 pm_void_statement_check(parser, node->
body.
nodes[index]);
1333 PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL,
1334 PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP,
1335 PM_CONDITIONAL_PREDICATE_TYPE_NOT
1336} pm_conditional_predicate_type_t;
1344 case PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL:
1345 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"condition");
1347 case PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP:
1348 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"flip-flop");
1350 case PM_CONDITIONAL_PREDICATE_TYPE_NOT:
1360pm_conditional_predicate_warn_write_literal_p(
const pm_node_t *node) {
1361 switch (PM_NODE_TYPE(node)) {
1362 case PM_ARRAY_NODE: {
1363 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1366 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1367 if (!pm_conditional_predicate_warn_write_literal_p(cast->
elements.
nodes[index]))
return false;
1372 case PM_HASH_NODE: {
1373 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1376 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1378 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE))
return false;
1381 if (!pm_conditional_predicate_warn_write_literal_p(assoc->
key) || !pm_conditional_predicate_warn_write_literal_p(assoc->
value))
return false;
1388 case PM_IMAGINARY_NODE:
1389 case PM_INTEGER_NODE:
1391 case PM_RATIONAL_NODE:
1392 case PM_REGULAR_EXPRESSION_NODE:
1393 case PM_SOURCE_ENCODING_NODE:
1394 case PM_SOURCE_FILE_NODE:
1395 case PM_SOURCE_LINE_NODE:
1396 case PM_STRING_NODE:
1397 case PM_SYMBOL_NODE:
1411 if (pm_conditional_predicate_warn_write_literal_p(node)) {
1430 switch (PM_NODE_TYPE(node)) {
1433 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1434 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1439 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1440 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1443 case PM_PARENTHESES_NODE: {
1446 if ((cast->
body != NULL) && PM_NODE_TYPE_P(cast->
body, PM_STATEMENTS_NODE)) {
1448 if (statements->body.size == 1) pm_conditional_predicate(parser, statements->body.nodes[0],
type);
1453 case PM_BEGIN_NODE: {
1461 case PM_RANGE_NODE: {
1464 if (cast->
left != NULL) pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1465 if (cast->
right != NULL) pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1473 node->
type = PM_FLIP_FLOP_NODE;
1477 case PM_REGULAR_EXPRESSION_NODE:
1482 node->
type = PM_MATCH_LAST_LINE_NODE;
1484 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1485 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"regex ");
1489 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
1494 node->
type = PM_INTERPOLATED_MATCH_LAST_LINE_NODE;
1496 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1497 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"regex ");
1501 case PM_INTEGER_NODE:
1502 if (
type == PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP) {
1503 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1504 pm_parser_warn_node(parser, node, PM_WARN_INTEGER_IN_FLIP_FLOP);
1507 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1510 case PM_STRING_NODE:
1511 case PM_SOURCE_FILE_NODE:
1512 case PM_INTERPOLATED_STRING_NODE:
1513 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"string ");
1515 case PM_SYMBOL_NODE:
1516 case PM_INTERPOLATED_SYMBOL_NODE:
1517 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"symbol ");
1519 case PM_SOURCE_LINE_NODE:
1520 case PM_SOURCE_ENCODING_NODE:
1522 case PM_RATIONAL_NODE:
1523 case PM_IMAGINARY_NODE:
1524 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1526 case PM_CLASS_VARIABLE_WRITE_NODE:
1529 case PM_CONSTANT_WRITE_NODE:
1532 case PM_GLOBAL_VARIABLE_WRITE_NODE:
1535 case PM_INSTANCE_VARIABLE_WRITE_NODE:
1538 case PM_LOCAL_VARIABLE_WRITE_NODE:
1541 case PM_MULTI_WRITE_NODE:
1562#define PM_LOCATION_NULL_VALUE(parser) ((pm_location_t) { .start = (parser)->start, .end = (parser)->start })
1563#define PM_LOCATION_TOKEN_VALUE(token) ((pm_location_t) { .start = (token)->start, .end = (token)->end })
1564#define PM_LOCATION_NODE_VALUE(node) ((pm_location_t) { .start = (node)->location.start, .end = (node)->location.end })
1565#define PM_LOCATION_NODE_BASE_VALUE(node) ((pm_location_t) { .start = (node)->base.location.start, .end = (node)->base.location.end })
1566#define PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE ((pm_location_t) { .start = NULL, .end = NULL })
1567#define PM_OPTIONAL_LOCATION_TOKEN_VALUE(token) ((token)->type == PM_TOKEN_NOT_PROVIDED ? PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE : PM_LOCATION_TOKEN_VALUE(token))
1595static inline const uint8_t *
1597 if (arguments->
block != NULL) {
1638 pm_parser_err_node(parser, (
pm_node_t *) block, PM_ERR_ARGUMENT_UNEXPECTED_BLOCK);
1652char_is_identifier_start(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
1653 if (n <= 0)
return 0;
1660 }
else if (*b ==
'_') {
1662 }
else if (*b >= 0x80) {
1667 }
else if (*b < 0x80) {
1670 return pm_encoding_utf_8_char_width(b, n);
1679char_is_identifier_utf8(
const uint8_t *b, ptrdiff_t n) {
1682 }
else if (*b < 0x80) {
1685 return pm_encoding_utf_8_char_width(b, n);
1695char_is_identifier(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
1703 }
else if (*b ==
'_') {
1705 }
else if (*b >= 0x80) {
1711 return char_is_identifier_utf8(b, n);
1718#define BIT(c, idx) (((c) / 32 - 1 == idx) ? (1U << ((c) % 32)) : 0)
1719#define PUNCT(idx) ( \
1720 BIT('~', idx) | BIT('*', idx) | BIT('$', idx) | BIT('?', idx) | \
1721 BIT('!', idx) | BIT('@', idx) | BIT('/', idx) | BIT('\\', idx) | \
1722 BIT(';', idx) | BIT(',', idx) | BIT('.', idx) | BIT('=', idx) | \
1723 BIT(':', idx) | BIT('<', idx) | BIT('>', idx) | BIT('\"', idx) | \
1724 BIT('&', idx) | BIT('`', idx) | BIT('\'', idx) | BIT('+', idx) | \
1727const unsigned int pm_global_name_punctuation_hash[(0x7e - 0x20 + 31) / 32] = { PUNCT(0), PUNCT(1), PUNCT(2) };
1733char_is_global_name_punctuation(const uint8_t b) {
1734 const unsigned int i = (const unsigned int) b;
1735 if (i <= 0x20 || 0x7e < i) return false;
1737 return (pm_global_name_punctuation_hash[(i - 0x20) / 32] >> (i % 32)) & 1;
1741token_is_setter_name(pm_token_t *token) {
1743 (token->type == PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL) ||
1744 ((token->type == PM_TOKEN_IDENTIFIER) &&
1745 (token->end - token->start >= 2) &&
1746 (token->end[-1] == '='))
1754pm_local_is_keyword(const char *source, size_t length) {
1755#define KEYWORD(name) if (memcmp(source, name, length) == 0) return true
1759 switch (source[0]) {
1760 case 'd': KEYWORD("do"); return false;
1761 case 'i': KEYWORD("if"); KEYWORD("in"); return false;
1762 case 'o': KEYWORD("or"); return false;
1763 default: return false;
1766 switch (source[0]) {
1767 case 'a': KEYWORD("and"); return false;
1768 case 'd': KEYWORD("def"); return false;
1769 case 'e': KEYWORD("end"); return false;
1770 case 'f': KEYWORD("for"); return false;
1771 case 'n': KEYWORD("nil"); KEYWORD("not"); return false;
1772 default: return false;
1775 switch (source[0]) {
1776 case 'c': KEYWORD("case"); return false;
1777 case 'e': KEYWORD("else"); return false;
1778 case 'n': KEYWORD("next"); return false;
1779 case 'r': KEYWORD("redo"); return false;
1780 case 's': KEYWORD("self"); return false;
1781 case 't': KEYWORD("then"); KEYWORD("true"); return false;
1782 case 'w': KEYWORD("when"); return false;
1783 default: return false;
1786 switch (source[0]) {
1787 case 'a': KEYWORD("alias"); return false;
1788 case 'b': KEYWORD("begin"); KEYWORD("break"); return false;
1789 case 'c': KEYWORD("class"); return false;
1790 case 'e': KEYWORD("elsif"); return false;
1791 case 'f': KEYWORD("false"); return false;
1792 case 'r': KEYWORD("retry"); return false;
1793 case 's': KEYWORD("super"); return false;
1794 case 'u': KEYWORD("undef"); KEYWORD("until"); return false;
1795 case 'w': KEYWORD("while"); return false;
1796 case 'y': KEYWORD("yield"); return false;
1797 default: return false;
1800 switch (source[0]) {
1801 case 'e': KEYWORD("ensure"); return false;
1802 case 'm': KEYWORD("module"); return false;
1803 case 'r': KEYWORD("rescue"); KEYWORD("return"); return false;
1804 case 'u': KEYWORD("unless"); return false;
1805 default: return false;
1808 KEYWORD("__LINE__");
1809 KEYWORD("__FILE__");
1812 KEYWORD("__ENCODING__");
1821/******************************************************************************/
1822/* Node flag handling functions */
1823/******************************************************************************/
1829pm_node_flag_set(pm_node_t *node, pm_node_flags_t flag) {
1830 node->flags |= flag;
1837pm_node_flag_unset(pm_node_t *node, pm_node_flags_t flag) {
1838 node->flags &= (pm_node_flags_t) ~flag;
1845pm_node_flag_set_repeated_parameter(pm_node_t *node) {
1846 assert(PM_NODE_TYPE(node) == PM_BLOCK_LOCAL_VARIABLE_NODE ||
1847 PM_NODE_TYPE(node) == PM_BLOCK_PARAMETER_NODE ||
1848 PM_NODE_TYPE(node) == PM_KEYWORD_REST_PARAMETER_NODE ||
1849 PM_NODE_TYPE(node) == PM_OPTIONAL_KEYWORD_PARAMETER_NODE ||
1850 PM_NODE_TYPE(node) == PM_OPTIONAL_PARAMETER_NODE ||
1851 PM_NODE_TYPE(node) == PM_REQUIRED_KEYWORD_PARAMETER_NODE ||
1852 PM_NODE_TYPE(node) == PM_REQUIRED_PARAMETER_NODE ||
1853 PM_NODE_TYPE(node) == PM_REST_PARAMETER_NODE);
1855 pm_node_flag_set(node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER);
1858/******************************************************************************/
1859/* Node creation functions */
1860/******************************************************************************/
1867#define PM_REGULAR_EXPRESSION_ENCODING_MASK ~(PM_REGULAR_EXPRESSION_FLAGS_EUC_JP | PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J | PM_REGULAR_EXPRESSION_FLAGS_UTF_8)
1872static inline pm_node_flags_t
1873pm_regular_expression_flags_create(pm_parser_t *parser, const pm_token_t *closing) {
1874 pm_node_flags_t flags = 0;
1876 if (closing->type == PM_TOKEN_REGEXP_END) {
1877 pm_buffer_t unknown_flags = { 0 };
1879 for (const uint8_t *flag = closing->start + 1; flag < closing->end; flag++) {
1881 case 'i': flags |= PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE; break;
1882 case 'm': flags |= PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE; break;
1883 case 'x': flags |= PM_REGULAR_EXPRESSION_FLAGS_EXTENDED; break;
1884 case 'o': flags |= PM_REGULAR_EXPRESSION_FLAGS_ONCE; break;
1886 case 'e': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_EUC_JP); break;
1887 case 'n': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT); break;
1888 case 's': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J); break;
1889 case 'u': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_UTF_8); break;
1891 default: pm_buffer_append_byte(&unknown_flags, *flag);
1895 size_t unknown_flags_length = pm_buffer_length(&unknown_flags);
1896 if (unknown_flags_length != 0) {
1897 const char *word = unknown_flags_length >= 2 ? "options" : "option";
1898 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, PM_ERR_REGEXP_UNKNOWN_OPTIONS, word, unknown_flags_length, pm_buffer_value(&unknown_flags));
1900 pm_buffer_free(&unknown_flags);
1906#undef PM_REGULAR_EXPRESSION_ENCODING_MASK
1908static pm_statements_node_t *
1909pm_statements_node_create(pm_parser_t *parser);
1912pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline);
1915pm_statements_node_body_length(pm_statements_node_t *node);
1922pm_node_alloc(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, size_t size) {
1923 void *memory = xcalloc(1, size);
1924 if (memory == NULL) {
1925 fprintf(stderr, "Failed to allocate %d bytes\n", (int) size);
1931#define PM_NODE_ALLOC(parser, type) (type *) pm_node_alloc(parser, sizeof(type))
1932#define PM_NODE_IDENTIFY(parser) (++parser->node_id)
1937static pm_missing_node_t *
1938pm_missing_node_create(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
1939 pm_missing_node_t *node = PM_NODE_ALLOC(parser, pm_missing_node_t);
1941 *node = (pm_missing_node_t) {{
1942 .type = PM_MISSING_NODE,
1943 .node_id = PM_NODE_IDENTIFY(parser),
1944 .location = { .start = start, .end = end }
1953static pm_alias_global_variable_node_t *
1954pm_alias_global_variable_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
1955 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
1956 pm_alias_global_variable_node_t *node = PM_NODE_ALLOC(parser, pm_alias_global_variable_node_t);
1958 *node = (pm_alias_global_variable_node_t) {
1960 .type = PM_ALIAS_GLOBAL_VARIABLE_NODE,
1961 .node_id = PM_NODE_IDENTIFY(parser),
1963 .start = keyword->start,
1964 .end = old_name->location.end
1967 .new_name = new_name,
1968 .old_name = old_name,
1969 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
1978static pm_alias_method_node_t *
1979pm_alias_method_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
1980 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
1981 pm_alias_method_node_t *node = PM_NODE_ALLOC(parser, pm_alias_method_node_t);
1983 *node = (pm_alias_method_node_t) {
1985 .type = PM_ALIAS_METHOD_NODE,
1986 .node_id = PM_NODE_IDENTIFY(parser),
1988 .start = keyword->start,
1989 .end = old_name->location.end
1992 .new_name = new_name,
1993 .old_name = old_name,
1994 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
2003static pm_alternation_pattern_node_t *
2004pm_alternation_pattern_node_create(pm_parser_t *parser, pm_node_t *left, pm_node_t *right, const pm_token_t *operator) {
2005 pm_alternation_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_alternation_pattern_node_t);
2007 *node = (pm_alternation_pattern_node_t) {
2009 .type = PM_ALTERNATION_PATTERN_NODE,
2010 .node_id = PM_NODE_IDENTIFY(parser),
2012 .start = left->location.start,
2013 .end = right->location.end
2018 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2027static pm_and_node_t *
2028pm_and_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
2029 pm_assert_value_expression(parser, left);
2031 pm_and_node_t *node = PM_NODE_ALLOC(parser, pm_and_node_t);
2033 *node = (pm_and_node_t) {
2035 .type = PM_AND_NODE,
2036 .node_id = PM_NODE_IDENTIFY(parser),
2038 .start = left->location.start,
2039 .end = right->location.end
2043 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2053static pm_arguments_node_t *
2054pm_arguments_node_create(pm_parser_t *parser) {
2055 pm_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_arguments_node_t);
2057 *node = (pm_arguments_node_t) {
2059 .type = PM_ARGUMENTS_NODE,
2060 .node_id = PM_NODE_IDENTIFY(parser),
2061 .location = PM_LOCATION_NULL_VALUE(parser)
2073pm_arguments_node_size(pm_arguments_node_t *node) {
2074 return node->arguments.size;
2081pm_arguments_node_arguments_append(pm_arguments_node_t *node, pm_node_t *argument) {
2082 if (pm_arguments_node_size(node) == 0) {
2083 node->base.location.start = argument->location.start;
2086 node->base.location.end = argument->location.end;
2087 pm_node_list_append(&node->arguments, argument);
2089 if (PM_NODE_TYPE_P(argument, PM_SPLAT_NODE)) {
2090 if (PM_NODE_FLAG_P(node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
2091 pm_node_flag_set((pm_node_t *) node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS);
2093 pm_node_flag_set((pm_node_t *) node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT);
2101static pm_array_node_t *
2102pm_array_node_create(pm_parser_t *parser, const pm_token_t *opening) {
2103 pm_array_node_t *node = PM_NODE_ALLOC(parser, pm_array_node_t);
2105 *node = (pm_array_node_t) {
2107 .type = PM_ARRAY_NODE,
2108 .flags = PM_NODE_FLAG_STATIC_LITERAL,
2109 .node_id = PM_NODE_IDENTIFY(parser),
2110 .location = PM_LOCATION_TOKEN_VALUE(opening)
2112 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2113 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2124pm_array_node_elements_append(pm_array_node_t *node, pm_node_t *element) {
2125 if (!node->elements.size && !node->opening_loc.start) {
2126 node->base.location.start = element->location.start;
2129 pm_node_list_append(&node->elements, element);
2130 node->base.location.end = element->location.end;
2132 // If the element is not a static literal, then the array is not a static
2133 // literal. Turn that flag off.
2134 if (PM_NODE_TYPE_P(element, PM_ARRAY_NODE) || PM_NODE_TYPE_P(element, PM_HASH_NODE) || PM_NODE_TYPE_P(element, PM_RANGE_NODE) || !PM_NODE_FLAG_P(element, PM_NODE_FLAG_STATIC_LITERAL)) {
2135 pm_node_flag_unset((pm_node_t *)node, PM_NODE_FLAG_STATIC_LITERAL);
2138 if (PM_NODE_TYPE_P(element, PM_SPLAT_NODE)) {
2139 pm_node_flag_set((pm_node_t *)node, PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT);
2147pm_array_node_close_set(pm_array_node_t *node, const pm_token_t *closing) {
2148 assert(closing->type == PM_TOKEN_BRACKET_RIGHT || closing->type == PM_TOKEN_STRING_END || closing->type == PM_TOKEN_MISSING || closing->type == PM_TOKEN_NOT_PROVIDED);
2149 node->base.location.end = closing->end;
2150 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
2157static pm_array_pattern_node_t *
2158pm_array_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *nodes) {
2159 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2161 *node = (pm_array_pattern_node_t) {
2163 .type = PM_ARRAY_PATTERN_NODE,
2164 .node_id = PM_NODE_IDENTIFY(parser),
2166 .start = nodes->nodes[0]->location.start,
2167 .end = nodes->nodes[nodes->size - 1]->location.end
2174 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2175 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
2178 // For now we're going to just copy over each pointer manually. This could be
2179 // much more efficient, as we could instead resize the node list.
2180 bool found_rest = false;
2183 PM_NODE_LIST_FOREACH(nodes, index, child) {
2184 if (!found_rest && (PM_NODE_TYPE_P(child, PM_SPLAT_NODE) || PM_NODE_TYPE_P(child, PM_IMPLICIT_REST_NODE))) {
2187 } else if (found_rest) {
2188 pm_node_list_append(&node->posts, child);
2190 pm_node_list_append(&node->requireds, child);
2200static pm_array_pattern_node_t *
2201pm_array_pattern_node_rest_create(pm_parser_t *parser, pm_node_t *rest) {
2202 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2204 *node = (pm_array_pattern_node_t) {
2206 .type = PM_ARRAY_PATTERN_NODE,
2207 .node_id = PM_NODE_IDENTIFY(parser),
2208 .location = rest->location,
2214 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2215 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
2225static pm_array_pattern_node_t *
2226pm_array_pattern_node_constant_create(pm_parser_t *parser, pm_node_t *constant, const pm_token_t *opening, const pm_token_t *closing) {
2227 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2229 *node = (pm_array_pattern_node_t) {
2231 .type = PM_ARRAY_PATTERN_NODE,
2232 .node_id = PM_NODE_IDENTIFY(parser),
2234 .start = constant->location.start,
2238 .constant = constant,
2240 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2241 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
2253static pm_array_pattern_node_t *
2254pm_array_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
2255 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2257 *node = (pm_array_pattern_node_t) {
2259 .type = PM_ARRAY_PATTERN_NODE,
2260 .node_id = PM_NODE_IDENTIFY(parser),
2262 .start = opening->start,
2268 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2269 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
2278pm_array_pattern_node_requireds_append(pm_array_pattern_node_t *node, pm_node_t *inner) {
2279 pm_node_list_append(&node->requireds, inner);
2285static pm_assoc_node_t *
2286pm_assoc_node_create(pm_parser_t *parser, pm_node_t *key, const pm_token_t *operator, pm_node_t *value) {
2287 pm_assoc_node_t *node = PM_NODE_ALLOC(parser, pm_assoc_node_t);
2290 if (value != NULL && value->location.end > key->location.end) {
2291 end = value->location.end;
2292 } else if (operator->type != PM_TOKEN_NOT_PROVIDED) {
2293 end = operator->end;
2295 end = key->location.end;
2298 // Hash string keys will be frozen, so we can mark them as frozen here so
2299 // that the compiler picks them up and also when we check for static literal
2300 // on the keys it gets factored in.
2301 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
2302 key->flags |= PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL;
2305 // If the key and value of this assoc node are both static literals, then
2306 // we can mark this node as a static literal.
2307 pm_node_flags_t flags = 0;
2309 !PM_NODE_TYPE_P(key, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(key, PM_HASH_NODE) && !PM_NODE_TYPE_P(key, PM_RANGE_NODE) &&
2310 value && !PM_NODE_TYPE_P(value, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(value, PM_HASH_NODE) && !PM_NODE_TYPE_P(value, PM_RANGE_NODE)
2312 flags = key->flags & value->flags & PM_NODE_FLAG_STATIC_LITERAL;
2315 *node = (pm_assoc_node_t) {
2317 .type = PM_ASSOC_NODE,
2319 .node_id = PM_NODE_IDENTIFY(parser),
2321 .start = key->location.start,
2326 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
2336static pm_assoc_splat_node_t *
2337pm_assoc_splat_node_create(pm_parser_t *parser, pm_node_t *value, const pm_token_t *operator) {
2338 assert(operator->type == PM_TOKEN_USTAR_STAR);
2339 pm_assoc_splat_node_t *node = PM_NODE_ALLOC(parser, pm_assoc_splat_node_t);
2341 *node = (pm_assoc_splat_node_t) {
2343 .type = PM_ASSOC_SPLAT_NODE,
2344 .node_id = PM_NODE_IDENTIFY(parser),
2346 .start = operator->start,
2347 .end = value == NULL ? operator->end : value->location.end
2351 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2360static pm_back_reference_read_node_t *
2361pm_back_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
2362 assert(name->type == PM_TOKEN_BACK_REFERENCE);
2363 pm_back_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_back_reference_read_node_t);
2365 *node = (pm_back_reference_read_node_t) {
2367 .type = PM_BACK_REFERENCE_READ_NODE,
2368 .node_id = PM_NODE_IDENTIFY(parser),
2369 .location = PM_LOCATION_TOKEN_VALUE(name),
2371 .name = pm_parser_constant_id_token(parser, name)
2380static pm_begin_node_t *
2381pm_begin_node_create(pm_parser_t *parser, const pm_token_t *begin_keyword, pm_statements_node_t *statements) {
2382 pm_begin_node_t *node = PM_NODE_ALLOC(parser, pm_begin_node_t);
2384 *node = (pm_begin_node_t) {
2386 .type = PM_BEGIN_NODE,
2387 .node_id = PM_NODE_IDENTIFY(parser),
2389 .start = begin_keyword->start,
2390 .end = statements == NULL ? begin_keyword->end : statements->base.location.end
2393 .begin_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(begin_keyword),
2394 .statements = statements,
2395 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
2405pm_begin_node_rescue_clause_set(pm_begin_node_t *node, pm_rescue_node_t *rescue_clause) {
2406 // If the begin keyword doesn't exist, we set the start on the begin_node
2407 if (!node->begin_keyword_loc.start) {
2408 node->base.location.start = rescue_clause->base.location.start;
2410 node->base.location.end = rescue_clause->base.location.end;
2411 node->rescue_clause = rescue_clause;
2418pm_begin_node_else_clause_set(pm_begin_node_t *node, pm_else_node_t *else_clause) {
2419 node->base.location.end = else_clause->base.location.end;
2420 node->else_clause = else_clause;
2427pm_begin_node_ensure_clause_set(pm_begin_node_t *node, pm_ensure_node_t *ensure_clause) {
2428 node->base.location.end = ensure_clause->base.location.end;
2429 node->ensure_clause = ensure_clause;
2436pm_begin_node_end_keyword_set(pm_begin_node_t *node, const pm_token_t *end_keyword) {
2437 assert(end_keyword->type == PM_TOKEN_KEYWORD_END || end_keyword->type == PM_TOKEN_MISSING);
2439 node->base.location.end = end_keyword->end;
2440 node->end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword);
2446static pm_block_argument_node_t *
2447pm_block_argument_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
2448 pm_block_argument_node_t *node = PM_NODE_ALLOC(parser, pm_block_argument_node_t);
2450 *node = (pm_block_argument_node_t) {
2452 .type = PM_BLOCK_ARGUMENT_NODE,
2453 .node_id = PM_NODE_IDENTIFY(parser),
2455 .start = operator->start,
2456 .end = expression == NULL ? operator->end : expression->location.end
2459 .expression = expression,
2460 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2469static pm_block_node_t *
2470pm_block_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const pm_token_t *opening, pm_node_t *parameters, pm_node_t *body, const pm_token_t *closing) {
2471 pm_block_node_t *node = PM_NODE_ALLOC(parser, pm_block_node_t);
2473 *node = (pm_block_node_t) {
2475 .type = PM_BLOCK_NODE,
2476 .node_id = PM_NODE_IDENTIFY(parser),
2477 .location = { .start = opening->start, .end = closing->end },
2480 .parameters = parameters,
2482 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2483 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
2492static pm_block_parameter_node_t *
2493pm_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator) {
2494 assert(operator->type == PM_TOKEN_NOT_PROVIDED || operator->type == PM_TOKEN_UAMPERSAND || operator->type == PM_TOKEN_AMPERSAND);
2495 pm_block_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_block_parameter_node_t);
2497 *node = (pm_block_parameter_node_t) {
2499 .type = PM_BLOCK_PARAMETER_NODE,
2500 .node_id = PM_NODE_IDENTIFY(parser),
2502 .start = operator->start,
2503 .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
2506 .name = pm_parser_optional_constant_id_token(parser, name),
2507 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
2508 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2517static pm_block_parameters_node_t *
2518pm_block_parameters_node_create(pm_parser_t *parser, pm_parameters_node_t *parameters, const pm_token_t *opening) {
2519 pm_block_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_block_parameters_node_t);
2521 const uint8_t *start;
2522 if (opening->type != PM_TOKEN_NOT_PROVIDED) {
2523 start = opening->start;
2524 } else if (parameters != NULL) {
2525 start = parameters->base.location.start;
2531 if (parameters != NULL) {
2532 end = parameters->base.location.end;
2533 } else if (opening->type != PM_TOKEN_NOT_PROVIDED) {
2539 *node = (pm_block_parameters_node_t) {
2541 .type = PM_BLOCK_PARAMETERS_NODE,
2542 .node_id = PM_NODE_IDENTIFY(parser),
2548 .parameters = parameters,
2549 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2550 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2561pm_block_parameters_node_closing_set(pm_block_parameters_node_t *node, const pm_token_t *closing) {
2562 assert(closing->type == PM_TOKEN_PIPE || closing->type == PM_TOKEN_PARENTHESIS_RIGHT || closing->type == PM_TOKEN_MISSING);
2564 node->base.location.end = closing->end;
2565 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
2571static pm_block_local_variable_node_t *
2572pm_block_local_variable_node_create(pm_parser_t *parser, const pm_token_t *name) {
2573 pm_block_local_variable_node_t *node = PM_NODE_ALLOC(parser, pm_block_local_variable_node_t);
2575 *node = (pm_block_local_variable_node_t) {
2577 .type = PM_BLOCK_LOCAL_VARIABLE_NODE,
2578 .node_id = PM_NODE_IDENTIFY(parser),
2579 .location = PM_LOCATION_TOKEN_VALUE(name),
2581 .name = pm_parser_constant_id_token(parser, name)
2591pm_block_parameters_node_append_local(pm_block_parameters_node_t *node, const pm_block_local_variable_node_t *local) {
2592 pm_node_list_append(&node->locals, (pm_node_t *) local);
2594 if (node->base.location.start == NULL) node->base.location.start = local->base.location.start;
2595 node->base.location.end = local->base.location.end;
2601static pm_break_node_t *
2602pm_break_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
2603 assert(keyword->type == PM_TOKEN_KEYWORD_BREAK);
2604 pm_break_node_t *node = PM_NODE_ALLOC(parser, pm_break_node_t);
2606 *node = (pm_break_node_t) {
2608 .type = PM_BREAK_NODE,
2609 .node_id = PM_NODE_IDENTIFY(parser),
2611 .start = keyword->start,
2612 .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
2615 .arguments = arguments,
2616 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
2622// There are certain flags that we want to use internally but don't want to
2623// expose because they are not relevant beyond parsing. Therefore we'll define
2624// them here and not define them in config.yml/a header file.
2625static const pm_node_flags_t PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY = 0x4;
2626static const pm_node_flags_t PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY = 0x40;
2627static const pm_node_flags_t PM_CALL_NODE_FLAGS_COMPARISON = 0x80;
2628static const pm_node_flags_t PM_CALL_NODE_FLAGS_INDEX = 0x100;
2635static pm_call_node_t *
2636pm_call_node_create(pm_parser_t *parser, pm_node_flags_t flags) {
2637 pm_call_node_t *node = PM_NODE_ALLOC(parser, pm_call_node_t);
2639 *node = (pm_call_node_t) {
2641 .type = PM_CALL_NODE,
2643 .node_id = PM_NODE_IDENTIFY(parser),
2644 .location = PM_LOCATION_NULL_VALUE(parser),
2647 .call_operator_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2648 .message_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2649 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2651 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2663static inline pm_node_flags_t
2664pm_call_node_ignore_visibility_flag(const pm_node_t *receiver) {
2665 return PM_NODE_TYPE_P(receiver, PM_SELF_NODE) ? PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY : 0;
2672static pm_call_node_t *
2673pm_call_node_aref_create(pm_parser_t *parser, pm_node_t *receiver, pm_arguments_t *arguments) {
2674 pm_assert_value_expression(parser, receiver);
2676 pm_node_flags_t flags = pm_call_node_ignore_visibility_flag(receiver);
2677 if (arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_ARGUMENT_NODE)) {
2678 flags |= PM_CALL_NODE_FLAGS_INDEX;
2681 pm_call_node_t *node = pm_call_node_create(parser, flags);
2683 node->base.location.start = receiver->location.start;
2684 node->base.location.end = pm_arguments_end(arguments);
2686 node->receiver = receiver;
2687 node->message_loc.start = arguments->opening_loc.start;
2688 node->message_loc.end = arguments->closing_loc.end;
2690 node->opening_loc = arguments->opening_loc;
2691 node->arguments = arguments->arguments;
2692 node->closing_loc = arguments->closing_loc;
2693 node->block = arguments->block;
2695 node->name = pm_parser_constant_id_constant(parser, "[]", 2);
2702static pm_call_node_t *
2703pm_call_node_binary_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_node_t *argument, pm_node_flags_t flags) {
2704 pm_assert_value_expression(parser, receiver);
2705 pm_assert_value_expression(parser, argument);
2707 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver) | flags);
2709 node->base.location.start = MIN(receiver->location.start, argument->location.start);
2710 node->base.location.end = MAX(receiver->location.end, argument->location.end);
2712 node->receiver = receiver;
2713 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2715 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
2716 pm_arguments_node_arguments_append(arguments, argument);
2717 node->arguments = arguments;
2719 node->name = pm_parser_constant_id_token(parser, operator);
2726static pm_call_node_t *
2727pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_token_t *message, pm_arguments_t *arguments) {
2728 pm_assert_value_expression(parser, receiver);
2730 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2732 node->base.location.start = receiver->location.start;
2733 const uint8_t *end = pm_arguments_end(arguments);
2737 node->base.location.end = end;
2739 node->receiver = receiver;
2740 node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2741 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2742 node->opening_loc = arguments->opening_loc;
2743 node->arguments = arguments->arguments;
2744 node->closing_loc = arguments->closing_loc;
2745 node->block = arguments->block;
2747 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2748 pm_node_flag_set((pm_node_t *)node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2751 node->name = pm_parser_constant_id_token(parser, message);
2758static pm_call_node_t *
2759pm_call_node_call_synthesized_create(pm_parser_t *parser, pm_node_t *receiver, const char *message, pm_arguments_node_t *arguments) {
2760 pm_call_node_t *node = pm_call_node_create(parser, 0);
2761 node->base.location.start = parser->start;
2762 node->base.location.end = parser->end;
2764 node->receiver = receiver;
2765 node->call_operator_loc = (pm_location_t) { .start = NULL, .end = NULL };
2766 node->message_loc = (pm_location_t) { .start = NULL, .end = NULL };
2767 node->arguments = arguments;
2769 node->name = pm_parser_constant_id_constant(parser, message, strlen(message));
2777static pm_call_node_t *
2778pm_call_node_fcall_create(pm_parser_t *parser, pm_token_t *message, pm_arguments_t *arguments) {
2779 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2781 node->base.location.start = message->start;
2782 node->base.location.end = pm_arguments_end(arguments);
2784 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2785 node->opening_loc = arguments->opening_loc;
2786 node->arguments = arguments->arguments;
2787 node->closing_loc = arguments->closing_loc;
2788 node->block = arguments->block;
2790 node->name = pm_parser_constant_id_token(parser, message);
2798static pm_call_node_t *
2799pm_call_node_fcall_synthesized_create(pm_parser_t *parser, pm_arguments_node_t *arguments, pm_constant_id_t name) {
2800 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2802 node->base.location = PM_LOCATION_NULL_VALUE(parser);
2803 node->arguments = arguments;
2812static pm_call_node_t *
2813pm_call_node_not_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *message, pm_arguments_t *arguments) {
2814 pm_assert_value_expression(parser, receiver);
2815 if (receiver != NULL) pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
2817 pm_call_node_t *node = pm_call_node_create(parser, receiver == NULL ? 0 : pm_call_node_ignore_visibility_flag(receiver));
2819 node->base.location.start = message->start;
2820 if (arguments->closing_loc.start != NULL) {
2821 node->base.location.end = arguments->closing_loc.end;
2823 assert(receiver != NULL);
2824 node->base.location.end = receiver->location.end;
2827 node->receiver = receiver;
2828 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2829 node->opening_loc = arguments->opening_loc;
2830 node->arguments = arguments->arguments;
2831 node->closing_loc = arguments->closing_loc;
2833 node->name = pm_parser_constant_id_constant(parser, "!", 1);
2840static pm_call_node_t *
2841pm_call_node_shorthand_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_arguments_t *arguments) {
2842 pm_assert_value_expression(parser, receiver);
2844 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2846 node->base.location.start = receiver->location.start;
2847 node->base.location.end = pm_arguments_end(arguments);
2849 node->receiver = receiver;
2850 node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2851 node->opening_loc = arguments->opening_loc;
2852 node->arguments = arguments->arguments;
2853 node->closing_loc = arguments->closing_loc;
2854 node->block = arguments->block;
2856 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2857 pm_node_flag_set((pm_node_t *)node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2860 node->name = pm_parser_constant_id_constant(parser, "call", 4);
2867static pm_call_node_t *
2868pm_call_node_unary_create(pm_parser_t *parser, pm_token_t *operator, pm_node_t *receiver, const char *name) {
2869 pm_assert_value_expression(parser, receiver);
2871 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2873 node->base.location.start = operator->start;
2874 node->base.location.end = receiver->location.end;
2876 node->receiver = receiver;
2877 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2879 node->name = pm_parser_constant_id_constant(parser, name, strlen(name));
2887static pm_call_node_t *
2888pm_call_node_variable_call_create(pm_parser_t *parser, pm_token_t *message) {
2889 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2891 node->base.location = PM_LOCATION_TOKEN_VALUE(message);
2892 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2894 node->name = pm_parser_constant_id_token(parser, message);
2903pm_call_node_writable_p(const pm_parser_t *parser, const pm_call_node_t *node) {
2905 (node->message_loc.start != NULL) &&
2906 (node->message_loc.end[-1] != '!') &&
2907 (node->message_loc.end[-1] != '?') &&
2908 char_is_identifier_start(parser, node->message_loc.start, parser->end - node->message_loc.start) &&
2909 (node->opening_loc.start == NULL) &&
2910 (node->arguments == NULL) &&
2911 (node->block == NULL)
2919pm_call_write_read_name_init(pm_parser_t *parser, pm_constant_id_t *read_name, pm_constant_id_t *write_name) {
2920 pm_constant_t *write_constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *write_name);
2922 if (write_constant->length > 0) {
2923 size_t length = write_constant->length - 1;
2925 void *memory = xmalloc(length);
2926 memcpy(memory, write_constant->start, length);
2928 *read_name = pm_constant_pool_insert_owned(&parser->constant_pool, (uint8_t *) memory, length);
2930 // We can get here if the message was missing because of a syntax error.
2931 *read_name = pm_parser_constant_id_constant(parser, "", 0);
2938static pm_call_and_write_node_t *
2939pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2940 assert(target->block == NULL);
2941 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
2942 pm_call_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_and_write_node_t);
2944 *node = (pm_call_and_write_node_t) {
2946 .type = PM_CALL_AND_WRITE_NODE,
2947 .flags = target->base.flags,
2948 .node_id = PM_NODE_IDENTIFY(parser),
2950 .start = target->base.location.start,
2951 .end = value->location.end
2954 .receiver = target->receiver,
2955 .call_operator_loc = target->call_operator_loc,
2956 .message_loc = target->message_loc,
2958 .write_name = target->name,
2959 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2963 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
2965 // Here we're going to free the target, since it is no longer necessary.
2966 // However, we don't want to call `pm_node_destroy` because we want to keep
2967 // around all of its children since we just reused them.
2978pm_index_arguments_check(pm_parser_t *parser, const pm_arguments_node_t *arguments, const pm_node_t *block) {
2979 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) {
2980 if (arguments != NULL && PM_NODE_FLAG_P(arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) {
2982 PM_NODE_LIST_FOREACH(&arguments->arguments, index, node) {
2983 if (PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE)) {
2984 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_INDEX_KEYWORDS);
2990 if (block != NULL) {
2991 pm_parser_err_node(parser, block, PM_ERR_UNEXPECTED_INDEX_BLOCK);
2999static pm_index_and_write_node_t *
3000pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3001 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3002 pm_index_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_and_write_node_t);
3004 pm_index_arguments_check(parser, target->arguments, target->block);
3006 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3007 *node = (pm_index_and_write_node_t) {
3009 .type = PM_INDEX_AND_WRITE_NODE,
3010 .flags = target->base.flags,
3011 .node_id = PM_NODE_IDENTIFY(parser),
3013 .start = target->base.location.start,
3014 .end = value->location.end
3017 .receiver = target->receiver,
3018 .call_operator_loc = target->call_operator_loc,
3019 .opening_loc = target->opening_loc,
3020 .arguments = target->arguments,
3021 .closing_loc = target->closing_loc,
3022 .block = (pm_block_argument_node_t *) target->block,
3023 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3027 // Here we're going to free the target, since it is no longer necessary.
3028 // However, we don't want to call `pm_node_destroy` because we want to keep
3029 // around all of its children since we just reused them.
3038static pm_call_operator_write_node_t *
3039pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3040 assert(target->block == NULL);
3041 pm_call_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_operator_write_node_t);
3043 *node = (pm_call_operator_write_node_t) {
3045 .type = PM_CALL_OPERATOR_WRITE_NODE,
3046 .flags = target->base.flags,
3047 .node_id = PM_NODE_IDENTIFY(parser),
3049 .start = target->base.location.start,
3050 .end = value->location.end
3053 .receiver = target->receiver,
3054 .call_operator_loc = target->call_operator_loc,
3055 .message_loc = target->message_loc,
3057 .write_name = target->name,
3058 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
3059 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3063 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3065 // Here we're going to free the target, since it is no longer necessary.
3066 // However, we don't want to call `pm_node_destroy` because we want to keep
3067 // around all of its children since we just reused them.
3076static pm_index_operator_write_node_t *
3077pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3078 pm_index_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_operator_write_node_t);
3080 pm_index_arguments_check(parser, target->arguments, target->block);
3082 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3083 *node = (pm_index_operator_write_node_t) {
3085 .type = PM_INDEX_OPERATOR_WRITE_NODE,
3086 .flags = target->base.flags,
3087 .node_id = PM_NODE_IDENTIFY(parser),
3089 .start = target->base.location.start,
3090 .end = value->location.end
3093 .receiver = target->receiver,
3094 .call_operator_loc = target->call_operator_loc,
3095 .opening_loc = target->opening_loc,
3096 .arguments = target->arguments,
3097 .closing_loc = target->closing_loc,
3098 .block = (pm_block_argument_node_t *) target->block,
3099 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
3100 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3104 // Here we're going to free the target, since it is no longer necessary.
3105 // However, we don't want to call `pm_node_destroy` because we want to keep
3106 // around all of its children since we just reused them.
3115static pm_call_or_write_node_t *
3116pm_call_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3117 assert(target->block == NULL);
3118 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3119 pm_call_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_or_write_node_t);
3121 *node = (pm_call_or_write_node_t) {
3123 .type = PM_CALL_OR_WRITE_NODE,
3124 .flags = target->base.flags,
3125 .node_id = PM_NODE_IDENTIFY(parser),
3127 .start = target->base.location.start,
3128 .end = value->location.end
3131 .receiver = target->receiver,
3132 .call_operator_loc = target->call_operator_loc,
3133 .message_loc = target->message_loc,
3135 .write_name = target->name,
3136 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3140 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3142 // Here we're going to free the target, since it is no longer necessary.
3143 // However, we don't want to call `pm_node_destroy` because we want to keep
3144 // around all of its children since we just reused them.
3153static pm_index_or_write_node_t *
3154pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3155 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3156 pm_index_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_or_write_node_t);
3158 pm_index_arguments_check(parser, target->arguments, target->block);
3160 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3161 *node = (pm_index_or_write_node_t) {
3163 .type = PM_INDEX_OR_WRITE_NODE,
3164 .flags = target->base.flags,
3165 .node_id = PM_NODE_IDENTIFY(parser),
3167 .start = target->base.location.start,
3168 .end = value->location.end
3171 .receiver = target->receiver,
3172 .call_operator_loc = target->call_operator_loc,
3173 .opening_loc = target->opening_loc,
3174 .arguments = target->arguments,
3175 .closing_loc = target->closing_loc,
3176 .block = (pm_block_argument_node_t *) target->block,
3177 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3181 // Here we're going to free the target, since it is no longer necessary.
3182 // However, we don't want to call `pm_node_destroy` because we want to keep
3183 // around all of its children since we just reused them.
3193static pm_call_target_node_t *
3194pm_call_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3195 pm_call_target_node_t *node = PM_NODE_ALLOC(parser, pm_call_target_node_t);
3197 *node = (pm_call_target_node_t) {
3199 .type = PM_CALL_TARGET_NODE,
3200 .flags = target->base.flags,
3201 .node_id = PM_NODE_IDENTIFY(parser),
3202 .location = target->base.location
3204 .receiver = target->receiver,
3205 .call_operator_loc = target->call_operator_loc,
3206 .name = target->name,
3207 .message_loc = target->message_loc
3210 // Here we're going to free the target, since it is no longer necessary.
3211 // However, we don't want to call `pm_node_destroy` because we want to keep
3212 // around all of its children since we just reused them.
3222static pm_index_target_node_t *
3223pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3224 pm_index_target_node_t *node = PM_NODE_ALLOC(parser, pm_index_target_node_t);
3225 pm_node_flags_t flags = target->base.flags;
3227 pm_index_arguments_check(parser, target->arguments, target->block);
3229 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3230 *node = (pm_index_target_node_t) {
3232 .type = PM_INDEX_TARGET_NODE,
3233 .flags = flags | PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE,
3234 .node_id = PM_NODE_IDENTIFY(parser),
3235 .location = target->base.location
3237 .receiver = target->receiver,
3238 .opening_loc = target->opening_loc,
3239 .arguments = target->arguments,
3240 .closing_loc = target->closing_loc,
3241 .block = (pm_block_argument_node_t *) target->block,
3244 // Here we're going to free the target, since it is no longer necessary.
3245 // However, we don't want to call `pm_node_destroy` because we want to keep
3246 // around all of its children since we just reused them.
3255static pm_capture_pattern_node_t *
3256pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_local_variable_target_node_t *target, const pm_token_t *operator) {
3257 pm_capture_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_capture_pattern_node_t);
3259 *node = (pm_capture_pattern_node_t) {
3261 .type = PM_CAPTURE_PATTERN_NODE,
3262 .node_id = PM_NODE_IDENTIFY(parser),
3264 .start = value->location.start,
3265 .end = target->base.location.end
3270 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
3279static pm_case_node_t *
3280pm_case_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3281 pm_case_node_t *node = PM_NODE_ALLOC(parser, pm_case_node_t);
3283 *node = (pm_case_node_t) {
3285 .type = PM_CASE_NODE,
3286 .node_id = PM_NODE_IDENTIFY(parser),
3288 .start = case_keyword->start,
3289 .end = end_keyword->end
3292 .predicate = predicate,
3293 .else_clause = NULL,
3294 .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
3295 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3306pm_case_node_condition_append(pm_case_node_t *node, pm_node_t *condition) {
3307 assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
3309 pm_node_list_append(&node->conditions, condition);
3310 node->base.location.end = condition->location.end;
3317pm_case_node_else_clause_set(pm_case_node_t *node, pm_else_node_t *else_clause) {
3318 node->else_clause = else_clause;
3319 node->base.location.end = else_clause->base.location.end;
3326pm_case_node_end_keyword_loc_set(pm_case_node_t *node, const pm_token_t *end_keyword) {
3327 node->base.location.end = end_keyword->end;
3328 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
3334static pm_case_match_node_t *
3335pm_case_match_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3336 pm_case_match_node_t *node = PM_NODE_ALLOC(parser, pm_case_match_node_t);
3338 *node = (pm_case_match_node_t) {
3340 .type = PM_CASE_MATCH_NODE,
3341 .node_id = PM_NODE_IDENTIFY(parser),
3343 .start = case_keyword->start,
3344 .end = end_keyword->end
3347 .predicate = predicate,
3348 .else_clause = NULL,
3349 .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
3350 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3361pm_case_match_node_condition_append(pm_case_match_node_t *node, pm_node_t *condition) {
3362 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
3364 pm_node_list_append(&node->conditions, condition);
3365 node->base.location.end = condition->location.end;
3372pm_case_match_node_else_clause_set(pm_case_match_node_t *node, pm_else_node_t *else_clause) {
3373 node->else_clause = else_clause;
3374 node->base.location.end = else_clause->base.location.end;
3381pm_case_match_node_end_keyword_loc_set(pm_case_match_node_t *node, const pm_token_t *end_keyword) {
3382 node->base.location.end = end_keyword->end;
3383 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
3389static pm_class_node_t *
3390pm_class_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const pm_token_t *class_keyword, pm_node_t *constant_path, const pm_token_t *name, const pm_token_t *inheritance_operator, pm_node_t *superclass, pm_node_t *body, const pm_token_t *end_keyword) {
3391 pm_class_node_t *node = PM_NODE_ALLOC(parser, pm_class_node_t);
3393 *node = (pm_class_node_t) {
3395 .type = PM_CLASS_NODE,
3396 .node_id = PM_NODE_IDENTIFY(parser),
3397 .location = { .start = class_keyword->start, .end = end_keyword->end },
3400 .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
3401 .constant_path = constant_path,
3402 .inheritance_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(inheritance_operator),
3403 .superclass = superclass,
3405 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3406 .name = pm_parser_constant_id_token(parser, name)
3415static pm_class_variable_and_write_node_t *
3416pm_class_variable_and_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3417 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3418 pm_class_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_and_write_node_t);
3420 *node = (pm_class_variable_and_write_node_t) {
3422 .type = PM_CLASS_VARIABLE_AND_WRITE_NODE,
3423 .node_id = PM_NODE_IDENTIFY(parser),
3425 .start = target->base.location.start,
3426 .end = value->location.end
3429 .name = target->name,
3430 .name_loc = target->base.location,
3431 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3441static pm_class_variable_operator_write_node_t *
3442pm_class_variable_operator_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3443 pm_class_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_operator_write_node_t);
3445 *node = (pm_class_variable_operator_write_node_t) {
3447 .type = PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE,
3448 .node_id = PM_NODE_IDENTIFY(parser),
3450 .start = target->base.location.start,
3451 .end = value->location.end
3454 .name = target->name,
3455 .name_loc = target->base.location,
3456 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3458 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3467static pm_class_variable_or_write_node_t *
3468pm_class_variable_or_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3469 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3470 pm_class_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_or_write_node_t);
3472 *node = (pm_class_variable_or_write_node_t) {
3474 .type = PM_CLASS_VARIABLE_OR_WRITE_NODE,
3475 .node_id = PM_NODE_IDENTIFY(parser),
3477 .start = target->base.location.start,
3478 .end = value->location.end
3481 .name = target->name,
3482 .name_loc = target->base.location,
3483 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3493static pm_class_variable_read_node_t *
3494pm_class_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
3495 assert(token->type == PM_TOKEN_CLASS_VARIABLE);
3496 pm_class_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_read_node_t);
3498 *node = (pm_class_variable_read_node_t) {
3500 .type = PM_CLASS_VARIABLE_READ_NODE,
3501 .node_id = PM_NODE_IDENTIFY(parser),
3502 .location = PM_LOCATION_TOKEN_VALUE(token)
3504 .name = pm_parser_constant_id_token(parser, token)
3516static inline pm_node_flags_t
3517pm_implicit_array_write_flags(const pm_node_t *node, pm_node_flags_t flags) {
3518 if (PM_NODE_TYPE_P(node, PM_ARRAY_NODE) && ((const pm_array_node_t *) node)->opening_loc.start == NULL) {
3527static pm_class_variable_write_node_t *
3528pm_class_variable_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *read_node, pm_token_t *operator, pm_node_t *value) {
3529 pm_class_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_write_node_t);
3531 *node = (pm_class_variable_write_node_t) {
3533 .type = PM_CLASS_VARIABLE_WRITE_NODE,
3534 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3535 .node_id = PM_NODE_IDENTIFY(parser),
3537 .start = read_node->base.location.start,
3538 .end = value->location.end
3541 .name = read_node->name,
3542 .name_loc = PM_LOCATION_NODE_VALUE((pm_node_t *) read_node),
3543 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3553static pm_constant_path_and_write_node_t *
3554pm_constant_path_and_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3555 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3556 pm_constant_path_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_and_write_node_t);
3558 *node = (pm_constant_path_and_write_node_t) {
3560 .type = PM_CONSTANT_PATH_AND_WRITE_NODE,
3561 .node_id = PM_NODE_IDENTIFY(parser),
3563 .start = target->base.location.start,
3564 .end = value->location.end
3568 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3578static pm_constant_path_operator_write_node_t *
3579pm_constant_path_operator_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3580 pm_constant_path_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_operator_write_node_t);
3582 *node = (pm_constant_path_operator_write_node_t) {
3584 .type = PM_CONSTANT_PATH_OPERATOR_WRITE_NODE,
3585 .node_id = PM_NODE_IDENTIFY(parser),
3587 .start = target->base.location.start,
3588 .end = value->location.end
3592 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3594 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3603static pm_constant_path_or_write_node_t *
3604pm_constant_path_or_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3605 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3606 pm_constant_path_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_or_write_node_t);
3608 *node = (pm_constant_path_or_write_node_t) {
3610 .type = PM_CONSTANT_PATH_OR_WRITE_NODE,
3611 .node_id = PM_NODE_IDENTIFY(parser),
3613 .start = target->base.location.start,
3614 .end = value->location.end
3618 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3628static pm_constant_path_node_t *
3629pm_constant_path_node_create(pm_parser_t *parser, pm_node_t *parent, const pm_token_t *delimiter, const pm_token_t *name_token) {
3630 pm_assert_value_expression(parser, parent);
3631 pm_constant_path_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_node_t);
3633 pm_constant_id_t name = PM_CONSTANT_ID_UNSET;
3634 if (name_token->type == PM_TOKEN_CONSTANT) {
3635 name = pm_parser_constant_id_token(parser, name_token);
3638 *node = (pm_constant_path_node_t) {
3640 .type = PM_CONSTANT_PATH_NODE,
3641 .node_id = PM_NODE_IDENTIFY(parser),
3643 .start = parent == NULL ? delimiter->start : parent->location.start,
3644 .end = name_token->end
3649 .delimiter_loc = PM_LOCATION_TOKEN_VALUE(delimiter),
3650 .name_loc = PM_LOCATION_TOKEN_VALUE(name_token)
3659static pm_constant_path_write_node_t *
3660pm_constant_path_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3661 pm_constant_path_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_write_node_t);
3663 *node = (pm_constant_path_write_node_t) {
3665 .type = PM_CONSTANT_PATH_WRITE_NODE,
3666 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3667 .node_id = PM_NODE_IDENTIFY(parser),
3669 .start = target->base.location.start,
3670 .end = value->location.end
3674 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3684static pm_constant_and_write_node_t *
3685pm_constant_and_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3686 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3687 pm_constant_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_and_write_node_t);
3689 *node = (pm_constant_and_write_node_t) {
3691 .type = PM_CONSTANT_AND_WRITE_NODE,
3692 .node_id = PM_NODE_IDENTIFY(parser),
3694 .start = target->base.location.start,
3695 .end = value->location.end
3698 .name = target->name,
3699 .name_loc = target->base.location,
3700 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3710static pm_constant_operator_write_node_t *
3711pm_constant_operator_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3712 pm_constant_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_operator_write_node_t);
3714 *node = (pm_constant_operator_write_node_t) {
3716 .type = PM_CONSTANT_OPERATOR_WRITE_NODE,
3717 .node_id = PM_NODE_IDENTIFY(parser),
3719 .start = target->base.location.start,
3720 .end = value->location.end
3723 .name = target->name,
3724 .name_loc = target->base.location,
3725 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3727 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3736static pm_constant_or_write_node_t *
3737pm_constant_or_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3738 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3739 pm_constant_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_or_write_node_t);
3741 *node = (pm_constant_or_write_node_t) {
3743 .type = PM_CONSTANT_OR_WRITE_NODE,
3744 .node_id = PM_NODE_IDENTIFY(parser),
3746 .start = target->base.location.start,
3747 .end = value->location.end
3750 .name = target->name,
3751 .name_loc = target->base.location,
3752 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3762static pm_constant_read_node_t *
3763pm_constant_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
3764 assert(name->type == PM_TOKEN_CONSTANT || name->type == PM_TOKEN_MISSING);
3765 pm_constant_read_node_t *node = PM_NODE_ALLOC(parser, pm_constant_read_node_t);
3767 *node = (pm_constant_read_node_t) {
3769 .type = PM_CONSTANT_READ_NODE,
3770 .node_id = PM_NODE_IDENTIFY(parser),
3771 .location = PM_LOCATION_TOKEN_VALUE(name)
3773 .name = pm_parser_constant_id_token(parser, name)
3782static pm_constant_write_node_t *
3783pm_constant_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3784 pm_constant_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_write_node_t);
3786 *node = (pm_constant_write_node_t) {
3788 .type = PM_CONSTANT_WRITE_NODE,
3789 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3790 .node_id = PM_NODE_IDENTIFY(parser),
3792 .start = target->base.location.start,
3793 .end = value->location.end
3796 .name = target->name,
3797 .name_loc = target->base.location,
3798 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3809pm_def_node_receiver_check(pm_parser_t *parser, const pm_node_t *node) {
3810 switch (PM_NODE_TYPE(node)) {
3811 case PM_BEGIN_NODE: {
3812 const pm_begin_node_t *cast = (pm_begin_node_t *) node;
3813 if (cast->statements != NULL) pm_def_node_receiver_check(parser, (pm_node_t *) cast->statements);
3816 case PM_PARENTHESES_NODE: {
3817 const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node;
3818 if (cast->body != NULL) pm_def_node_receiver_check(parser, cast->body);
3821 case PM_STATEMENTS_NODE: {
3822 const pm_statements_node_t *cast = (const pm_statements_node_t *) node;
3823 pm_def_node_receiver_check(parser, cast->body.nodes[cast->body.size - 1]);
3828 case PM_IMAGINARY_NODE:
3829 case PM_INTEGER_NODE:
3830 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
3831 case PM_INTERPOLATED_STRING_NODE:
3832 case PM_INTERPOLATED_SYMBOL_NODE:
3833 case PM_INTERPOLATED_X_STRING_NODE:
3834 case PM_RATIONAL_NODE:
3835 case PM_REGULAR_EXPRESSION_NODE:
3836 case PM_SOURCE_ENCODING_NODE:
3837 case PM_SOURCE_FILE_NODE:
3838 case PM_SOURCE_LINE_NODE:
3839 case PM_STRING_NODE:
3840 case PM_SYMBOL_NODE:
3841 case PM_X_STRING_NODE:
3842 pm_parser_err_node(parser, node, PM_ERR_SINGLETON_FOR_LITERALS);
3852static pm_def_node_t *
3854 pm_parser_t *parser,
3855 pm_constant_id_t name,
3856 const pm_token_t *name_loc,
3857 pm_node_t *receiver,
3858 pm_parameters_node_t *parameters,
3860 pm_constant_id_list_t *locals,
3861 const pm_token_t *def_keyword,
3862 const pm_token_t *operator,
3863 const pm_token_t *lparen,
3864 const pm_token_t *rparen,
3865 const pm_token_t *equal,
3866 const pm_token_t *end_keyword
3868 pm_def_node_t *node = PM_NODE_ALLOC(parser, pm_def_node_t);
3871 if (end_keyword->type == PM_TOKEN_NOT_PROVIDED) {
3872 end = body->location.end;
3874 end = end_keyword->end;
3877 if (receiver != NULL) {
3878 pm_def_node_receiver_check(parser, receiver);
3881 *node = (pm_def_node_t) {
3883 .type = PM_DEF_NODE,
3884 .node_id = PM_NODE_IDENTIFY(parser),
3885 .location = { .start = def_keyword->start, .end = end },
3888 .name_loc = PM_LOCATION_TOKEN_VALUE(name_loc),
3889 .receiver = receiver,
3890 .parameters = parameters,
3893 .def_keyword_loc = PM_LOCATION_TOKEN_VALUE(def_keyword),
3894 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3895 .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
3896 .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
3897 .equal_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(equal),
3898 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
3907static pm_defined_node_t *
3908pm_defined_node_create(pm_parser_t *parser, const pm_token_t *lparen, pm_node_t *value, const pm_token_t *rparen, const pm_location_t *keyword_loc) {
3909 pm_defined_node_t *node = PM_NODE_ALLOC(parser, pm_defined_node_t);
3911 *node = (pm_defined_node_t) {
3913 .type = PM_DEFINED_NODE,
3914 .node_id = PM_NODE_IDENTIFY(parser),
3916 .start = keyword_loc->start,
3917 .end = (rparen->type == PM_TOKEN_NOT_PROVIDED ? value->location.end : rparen->end)
3920 .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
3922 .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
3923 .keyword_loc = *keyword_loc
3932static pm_else_node_t *
3933pm_else_node_create(pm_parser_t *parser, const pm_token_t *else_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
3934 pm_else_node_t *node = PM_NODE_ALLOC(parser, pm_else_node_t);
3935 const uint8_t *end = NULL;
3936 if ((end_keyword->type == PM_TOKEN_NOT_PROVIDED) && (statements != NULL)) {
3937 end = statements->base.location.end;
3939 end = end_keyword->end;
3942 *node = (pm_else_node_t) {
3944 .type = PM_ELSE_NODE,
3945 .node_id = PM_NODE_IDENTIFY(parser),
3947 .start = else_keyword->start,
3951 .else_keyword_loc = PM_LOCATION_TOKEN_VALUE(else_keyword),
3952 .statements = statements,
3953 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
3962static pm_embedded_statements_node_t *
3963pm_embedded_statements_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
3964 pm_embedded_statements_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_statements_node_t);
3966 *node = (pm_embedded_statements_node_t) {
3968 .type = PM_EMBEDDED_STATEMENTS_NODE,
3969 .node_id = PM_NODE_IDENTIFY(parser),
3971 .start = opening->start,
3975 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
3976 .statements = statements,
3977 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
3986static pm_embedded_variable_node_t *
3987pm_embedded_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
3988 pm_embedded_variable_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_variable_node_t);
3990 *node = (pm_embedded_variable_node_t) {
3992 .type = PM_EMBEDDED_VARIABLE_NODE,
3993 .node_id = PM_NODE_IDENTIFY(parser),
3995 .start = operator->start,
3996 .end = variable->location.end
3999 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4000 .variable = variable
4009static pm_ensure_node_t *
4010pm_ensure_node_create(pm_parser_t *parser, const pm_token_t *ensure_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
4011 pm_ensure_node_t *node = PM_NODE_ALLOC(parser, pm_ensure_node_t);
4013 *node = (pm_ensure_node_t) {
4015 .type = PM_ENSURE_NODE,
4016 .node_id = PM_NODE_IDENTIFY(parser),
4018 .start = ensure_keyword->start,
4019 .end = end_keyword->end
4022 .ensure_keyword_loc = PM_LOCATION_TOKEN_VALUE(ensure_keyword),
4023 .statements = statements,
4024 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
4033static pm_false_node_t *
4034pm_false_node_create(pm_parser_t *parser, const pm_token_t *token) {
4035 assert(token->type == PM_TOKEN_KEYWORD_FALSE);
4036 pm_false_node_t *node = PM_NODE_ALLOC(parser, pm_false_node_t);
4038 *node = (pm_false_node_t) {{
4039 .type = PM_FALSE_NODE,
4040 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4041 .node_id = PM_NODE_IDENTIFY(parser),
4042 .location = PM_LOCATION_TOKEN_VALUE(token)
4052static pm_find_pattern_node_t *
4053pm_find_pattern_node_create(pm_parser_t *parser, pm_node_list_t *nodes) {
4054 pm_find_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_find_pattern_node_t);
4056 pm_node_t *left = nodes->nodes[0];
4057 assert(PM_NODE_TYPE_P(left, PM_SPLAT_NODE));
4058 pm_splat_node_t *left_splat_node = (pm_splat_node_t *) left;
4062 if (nodes->size == 1) {
4063 right = (pm_node_t *) pm_missing_node_create(parser, left->location.end, left->location.end);
4065 right = nodes->nodes[nodes->size - 1];
4066 assert(PM_NODE_TYPE_P(right, PM_SPLAT_NODE));
4069#if PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS
4070 // FindPatternNode#right is typed as SplatNode in this case, so replace the potential MissingNode with a SplatNode.
4071 // The resulting AST will anyway be ignored, but this file still needs to compile.
4072 pm_splat_node_t *right_splat_node = PM_NODE_TYPE_P(right, PM_SPLAT_NODE) ? (pm_splat_node_t *) right : left_splat_node;
4074 pm_node_t *right_splat_node = right;
4076 *node = (pm_find_pattern_node_t) {
4078 .type = PM_FIND_PATTERN_NODE,
4079 .node_id = PM_NODE_IDENTIFY(parser),
4081 .start = left->location.start,
4082 .end = right->location.end,
4086 .left = left_splat_node,
4087 .right = right_splat_node,
4089 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4090 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4093 // For now we're going to just copy over each pointer manually. This could be
4094 // much more efficient, as we could instead resize the node list to only point
4096 for (size_t index = 1; index < nodes->size - 1; index++) {
4097 pm_node_list_append(&node->requireds, nodes->nodes[index]);
4108pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
4109 ptrdiff_t diff = token->end - token->start;
4110 if (diff <= 0) return 0.0;
4112 // First, get a buffer of the content.
4113 size_t length = (size_t) diff;
4114 char *buffer = xmalloc(sizeof(char) * (length + 1));
4115 memcpy((void *) buffer, token->start, length);
4117 // Next, determine if we need to replace the decimal point because of
4118 // locale-specific options, and then normalize them if we have to.
4119 char decimal_point = *localeconv()->decimal_point;
4120 if (decimal_point != '.') {
4121 for (size_t index = 0; index < length; index++) {
4122 if (buffer[index] == '.') buffer[index] = decimal_point;
4126 // Next, handle underscores by removing them from the buffer.
4127 for (size_t index = 0; index < length; index++) {
4128 if (buffer[index] == '_') {
4129 memmove((void *) (buffer + index), (void *) (buffer + index + 1), length - index);
4134 // Null-terminate the buffer so that strtod cannot read off the end.
4135 buffer[length] = '\0';
4137 // Now, call strtod to parse the value. Note that CRuby has their own
4138 // version of strtod which avoids locales. We're okay using the locale-aware
4139 // version because we've already validated through the parser that the token
4140 // is in a valid format.
4143 double value = strtod(buffer, &eptr);
4145 // This should never happen, because we've already checked that the token
4146 // is in a valid format. However it's good to be safe.
4147 if ((eptr != buffer + length) || (errno != 0 && errno != ERANGE)) {
4148 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, (*token), PM_ERR_FLOAT_PARSE);
4149 xfree((void *) buffer);
4153 // If errno is set, then it should only be ERANGE. At this point we need to
4154 // check if it's infinity (it should be).
4155 if (errno == ERANGE && PRISM_ISINF(value)) {
4157 const char *ellipsis;
4163 warn_width = (int) length;
4167 pm_diagnostic_list_append_format(&parser->warning_list, token->start, token->end, PM_WARN_FLOAT_OUT_OF_RANGE, warn_width, (const char *) token->start, ellipsis);
4168 value = (value < 0.0) ? -HUGE_VAL : HUGE_VAL;
4171 // Finally we can free the buffer and return the value.
4172 xfree((void *) buffer);
4179static pm_float_node_t *
4180pm_float_node_create(pm_parser_t *parser, const pm_token_t *token) {
4181 assert(token->type == PM_TOKEN_FLOAT);
4182 pm_float_node_t *node = PM_NODE_ALLOC(parser, pm_float_node_t);
4184 *node = (pm_float_node_t) {
4186 .type = PM_FLOAT_NODE,
4187 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4188 .node_id = PM_NODE_IDENTIFY(parser),
4189 .location = PM_LOCATION_TOKEN_VALUE(token)
4191 .value = pm_double_parse(parser, token)
4200static pm_imaginary_node_t *
4201pm_float_node_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4202 assert(token->type == PM_TOKEN_FLOAT_IMAGINARY);
4204 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4205 *node = (pm_imaginary_node_t) {
4207 .type = PM_IMAGINARY_NODE,
4208 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4209 .node_id = PM_NODE_IDENTIFY(parser),
4210 .location = PM_LOCATION_TOKEN_VALUE(token)
4212 .numeric = (pm_node_t *) pm_float_node_create(parser, &((pm_token_t) {
4213 .type = PM_TOKEN_FLOAT,
4214 .start = token->start,
4215 .end = token->end - 1
4225static pm_rational_node_t *
4226pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
4227 assert(token->type == PM_TOKEN_FLOAT_RATIONAL);
4229 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
4230 *node = (pm_rational_node_t) {
4232 .type = PM_RATIONAL_NODE,
4233 .flags = PM_INTEGER_BASE_FLAGS_DECIMAL | PM_NODE_FLAG_STATIC_LITERAL,
4234 .node_id = PM_NODE_IDENTIFY(parser),
4235 .location = PM_LOCATION_TOKEN_VALUE(token)
4238 .denominator = { 0 }
4241 const uint8_t *start = token->start;
4242 const uint8_t *end = token->end - 1; // r
4244 while (start < end && *start == '0') start++; // 0.1 -> .1
4245 while (end > start && end[-1] == '0') end--; // 1.0 -> 1.
4247 size_t length = (size_t) (end - start);
4249 node->denominator.value = 1;
4253 const uint8_t *point = memchr(start, '.', length);
4254 assert(point && "should have a decimal point");
4256 uint8_t *digits = xmalloc(length);
4257 if (digits == NULL) {
4258 fputs("[pm_float_node_rational_create] Failed to allocate memory", stderr);
4262 memcpy(digits, start, (unsigned long) (point - start));
4263 memcpy(digits + (point - start), point + 1, (unsigned long) (end - point - 1));
4264 pm_integer_parse(&node->numerator, PM_INTEGER_BASE_DEFAULT, digits, digits + length - 1);
4267 if (end - point > 1) memset(digits + 1, '0', (size_t) (end - point - 1));
4268 pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + (end - point));
4271 pm_integers_reduce(&node->numerator, &node->denominator);
4279static pm_imaginary_node_t *
4280pm_float_node_rational_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4281 assert(token->type == PM_TOKEN_FLOAT_RATIONAL_IMAGINARY);
4283 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4284 *node = (pm_imaginary_node_t) {
4286 .type = PM_IMAGINARY_NODE,
4287 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4288 .node_id = PM_NODE_IDENTIFY(parser),
4289 .location = PM_LOCATION_TOKEN_VALUE(token)
4291 .numeric = (pm_node_t *) pm_float_node_rational_create(parser, &((pm_token_t) {
4292 .type = PM_TOKEN_FLOAT_RATIONAL,
4293 .start = token->start,
4294 .end = token->end - 1
4304static pm_for_node_t *
4306 pm_parser_t *parser,
4308 pm_node_t *collection,
4309 pm_statements_node_t *statements,
4310 const pm_token_t *for_keyword,
4311 const pm_token_t *in_keyword,
4312 const pm_token_t *do_keyword,
4313 const pm_token_t *end_keyword
4315 pm_for_node_t *node = PM_NODE_ALLOC(parser, pm_for_node_t);
4317 *node = (pm_for_node_t) {
4319 .type = PM_FOR_NODE,
4320 .node_id = PM_NODE_IDENTIFY(parser),
4322 .start = for_keyword->start,
4323 .end = end_keyword->end
4327 .collection = collection,
4328 .statements = statements,
4329 .for_keyword_loc = PM_LOCATION_TOKEN_VALUE(for_keyword),
4330 .in_keyword_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
4331 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
4332 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
4341static pm_forwarding_arguments_node_t *
4342pm_forwarding_arguments_node_create(pm_parser_t *parser, const pm_token_t *token) {
4343 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4344 pm_forwarding_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_arguments_node_t);
4346 *node = (pm_forwarding_arguments_node_t) {{
4347 .type = PM_FORWARDING_ARGUMENTS_NODE,
4348 .node_id = PM_NODE_IDENTIFY(parser),
4349 .location = PM_LOCATION_TOKEN_VALUE(token)
4358static pm_forwarding_parameter_node_t *
4359pm_forwarding_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
4360 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4361 pm_forwarding_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_parameter_node_t);
4363 *node = (pm_forwarding_parameter_node_t) {{
4364 .type = PM_FORWARDING_PARAMETER_NODE,
4365 .node_id = PM_NODE_IDENTIFY(parser),
4366 .location = PM_LOCATION_TOKEN_VALUE(token)
4375static pm_forwarding_super_node_t *
4376pm_forwarding_super_node_create(pm_parser_t *parser, const pm_token_t *token, pm_arguments_t *arguments) {
4377 assert(arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_NODE));
4378 assert(token->type == PM_TOKEN_KEYWORD_SUPER);
4379 pm_forwarding_super_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_super_node_t);
4381 pm_block_node_t *block = NULL;
4382 if (arguments->block != NULL) {
4383 block = (pm_block_node_t *) arguments->block;
4386 *node = (pm_forwarding_super_node_t) {
4388 .type = PM_FORWARDING_SUPER_NODE,
4389 .node_id = PM_NODE_IDENTIFY(parser),
4391 .start = token->start,
4392 .end = block != NULL ? block->base.location.end : token->end
4405static pm_hash_pattern_node_t *
4406pm_hash_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4407 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4409 *node = (pm_hash_pattern_node_t) {
4411 .type = PM_HASH_PATTERN_NODE,
4412 .node_id = PM_NODE_IDENTIFY(parser),
4414 .start = opening->start,
4419 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4420 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
4431static pm_hash_pattern_node_t *
4432pm_hash_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *elements, pm_node_t *rest) {
4433 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4435 const uint8_t *start;
4438 if (elements->size > 0) {
4440 start = elements->nodes[0]->location.start;
4441 end = rest->location.end;
4443 start = elements->nodes[0]->location.start;
4444 end = elements->nodes[elements->size - 1]->location.end;
4447 assert(rest != NULL);
4448 start = rest->location.start;
4449 end = rest->location.end;
4452 *node = (pm_hash_pattern_node_t) {
4454 .type = PM_HASH_PATTERN_NODE,
4455 .node_id = PM_NODE_IDENTIFY(parser),
4464 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4465 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4469 PM_NODE_LIST_FOREACH(elements, index, element) {
4470 pm_node_list_append(&node->elements, element);
4479static pm_constant_id_t
4480pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
4481 switch (PM_NODE_TYPE(target)) {
4482 case PM_GLOBAL_VARIABLE_READ_NODE:
4483 return ((pm_global_variable_read_node_t *) target)->name;
4484 case PM_BACK_REFERENCE_READ_NODE:
4485 return ((pm_back_reference_read_node_t *) target)->name;
4486 case PM_NUMBERED_REFERENCE_READ_NODE:
4487 // This will only ever happen in the event of a syntax error, but we
4488 // still need to provide something for the node.
4489 return pm_parser_constant_id_location(parser, target->location.start, target->location.end);
4491 assert(false && "unreachable");
4492 return (pm_constant_id_t) -1;
4499static pm_global_variable_and_write_node_t *
4500pm_global_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4501 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4502 pm_global_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_and_write_node_t);
4504 *node = (pm_global_variable_and_write_node_t) {
4506 .type = PM_GLOBAL_VARIABLE_AND_WRITE_NODE,
4507 .node_id = PM_NODE_IDENTIFY(parser),
4509 .start = target->location.start,
4510 .end = value->location.end
4513 .name = pm_global_variable_write_name(parser, target),
4514 .name_loc = target->location,
4515 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4525static pm_global_variable_operator_write_node_t *
4526pm_global_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4527 pm_global_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_operator_write_node_t);
4529 *node = (pm_global_variable_operator_write_node_t) {
4531 .type = PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE,
4532 .node_id = PM_NODE_IDENTIFY(parser),
4534 .start = target->location.start,
4535 .end = value->location.end
4538 .name = pm_global_variable_write_name(parser, target),
4539 .name_loc = target->location,
4540 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4542 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
4551static pm_global_variable_or_write_node_t *
4552pm_global_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4553 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4554 pm_global_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_or_write_node_t);
4556 *node = (pm_global_variable_or_write_node_t) {
4558 .type = PM_GLOBAL_VARIABLE_OR_WRITE_NODE,
4559 .node_id = PM_NODE_IDENTIFY(parser),
4561 .start = target->location.start,
4562 .end = value->location.end
4565 .name = pm_global_variable_write_name(parser, target),
4566 .name_loc = target->location,
4567 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4577static pm_global_variable_read_node_t *
4578pm_global_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
4579 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4581 *node = (pm_global_variable_read_node_t) {
4583 .type = PM_GLOBAL_VARIABLE_READ_NODE,
4584 .node_id = PM_NODE_IDENTIFY(parser),
4585 .location = PM_LOCATION_TOKEN_VALUE(name),
4587 .name = pm_parser_constant_id_token(parser, name)
4596static pm_global_variable_read_node_t *
4597pm_global_variable_read_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name) {
4598 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4600 *node = (pm_global_variable_read_node_t) {
4602 .type = PM_GLOBAL_VARIABLE_READ_NODE,
4603 .node_id = PM_NODE_IDENTIFY(parser),
4604 .location = PM_LOCATION_NULL_VALUE(parser)
4615static pm_global_variable_write_node_t *
4616pm_global_variable_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4617 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4619 *node = (pm_global_variable_write_node_t) {
4621 .type = PM_GLOBAL_VARIABLE_WRITE_NODE,
4622 .node_id = PM_NODE_IDENTIFY(parser),
4623 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
4625 .start = target->location.start,
4626 .end = value->location.end
4629 .name = pm_global_variable_write_name(parser, target),
4630 .name_loc = PM_LOCATION_NODE_VALUE(target),
4631 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
4641static pm_global_variable_write_node_t *
4642pm_global_variable_write_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name, pm_node_t *value) {
4643 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4645 *node = (pm_global_variable_write_node_t) {
4647 .type = PM_GLOBAL_VARIABLE_WRITE_NODE,
4648 .node_id = PM_NODE_IDENTIFY(parser),
4649 .location = PM_LOCATION_NULL_VALUE(parser)
4652 .name_loc = PM_LOCATION_NULL_VALUE(parser),
4653 .operator_loc = PM_LOCATION_NULL_VALUE(parser),
4663static pm_hash_node_t *
4664pm_hash_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4665 assert(opening != NULL);
4666 pm_hash_node_t *node = PM_NODE_ALLOC(parser, pm_hash_node_t);
4668 *node = (pm_hash_node_t) {
4670 .type = PM_HASH_NODE,
4671 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4672 .node_id = PM_NODE_IDENTIFY(parser),
4673 .location = PM_LOCATION_TOKEN_VALUE(opening)
4675 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4676 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
4687pm_hash_node_elements_append(pm_hash_node_t *hash, pm_node_t *element) {
4688 pm_node_list_append(&hash->elements, element);
4690 bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE);
4691 if (static_literal) {
4692 pm_assoc_node_t *assoc = (pm_assoc_node_t *) element;
4693 static_literal = !PM_NODE_TYPE_P(assoc->key, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(assoc->key, PM_HASH_NODE) && !PM_NODE_TYPE_P(assoc->key, PM_RANGE_NODE);
4694 static_literal = static_literal && PM_NODE_FLAG_P(assoc->key, PM_NODE_FLAG_STATIC_LITERAL);
4695 static_literal = static_literal && PM_NODE_FLAG_P(assoc, PM_NODE_FLAG_STATIC_LITERAL);
4698 if (!static_literal) {
4699 pm_node_flag_unset((pm_node_t *)hash, PM_NODE_FLAG_STATIC_LITERAL);
4704pm_hash_node_closing_loc_set(pm_hash_node_t *hash, pm_token_t *token) {
4705 hash->base.location.end = token->end;
4706 hash->closing_loc = PM_LOCATION_TOKEN_VALUE(token);
4712static pm_if_node_t *
4713pm_if_node_create(pm_parser_t *parser,
4714 const pm_token_t *if_keyword,
4715 pm_node_t *predicate,
4716 const pm_token_t *then_keyword,
4717 pm_statements_node_t *statements,
4718 pm_node_t *subsequent,
4719 const pm_token_t *end_keyword
4721 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4722 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4725 if (end_keyword->type != PM_TOKEN_NOT_PROVIDED) {
4726 end = end_keyword->end;
4727 } else if (subsequent != NULL) {
4728 end = subsequent->location.end;
4729 } else if (pm_statements_node_body_length(statements) != 0) {
4730 end = statements->base.location.end;
4732 end = predicate->location.end;
4735 *node = (pm_if_node_t) {
4738 .flags = PM_NODE_FLAG_NEWLINE,
4739 .node_id = PM_NODE_IDENTIFY(parser),
4741 .start = if_keyword->start,
4745 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4746 .predicate = predicate,
4747 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
4748 .statements = statements,
4749 .subsequent = subsequent,
4750 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
4759static pm_if_node_t *
4760pm_if_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *if_keyword, pm_node_t *predicate) {
4761 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4762 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4764 pm_statements_node_t *statements = pm_statements_node_create(parser);
4765 pm_statements_node_body_append(parser, statements, statement, true);
4767 *node = (pm_if_node_t) {
4770 .flags = PM_NODE_FLAG_NEWLINE,
4771 .node_id = PM_NODE_IDENTIFY(parser),
4773 .start = statement->location.start,
4774 .end = predicate->location.end
4777 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4778 .predicate = predicate,
4779 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4780 .statements = statements,
4782 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4791static pm_if_node_t *
4792pm_if_node_ternary_create(pm_parser_t *parser, pm_node_t *predicate, const pm_token_t *qmark, pm_node_t *true_expression, const pm_token_t *colon, pm_node_t *false_expression) {
4793 pm_assert_value_expression(parser, predicate);
4794 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4796 pm_statements_node_t *if_statements = pm_statements_node_create(parser);
4797 pm_statements_node_body_append(parser, if_statements, true_expression, true);
4799 pm_statements_node_t *else_statements = pm_statements_node_create(parser);
4800 pm_statements_node_body_append(parser, else_statements, false_expression, true);
4802 pm_token_t end_keyword = not_provided(parser);
4803 pm_else_node_t *else_node = pm_else_node_create(parser, colon, else_statements, &end_keyword);
4805 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4807 *node = (pm_if_node_t) {
4810 .flags = PM_NODE_FLAG_NEWLINE,
4811 .node_id = PM_NODE_IDENTIFY(parser),
4813 .start = predicate->location.start,
4814 .end = false_expression->location.end,
4817 .if_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4818 .predicate = predicate,
4819 .then_keyword_loc = PM_LOCATION_TOKEN_VALUE(qmark),
4820 .statements = if_statements,
4821 .subsequent = (pm_node_t *) else_node,
4822 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4830pm_if_node_end_keyword_loc_set(pm_if_node_t *node, const pm_token_t *keyword) {
4831 node->base.location.end = keyword->end;
4832 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4836pm_else_node_end_keyword_loc_set(pm_else_node_t *node, const pm_token_t *keyword) {
4837 node->base.location.end = keyword->end;
4838 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4844static pm_implicit_node_t *
4845pm_implicit_node_create(pm_parser_t *parser, pm_node_t *value) {
4846 pm_implicit_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_node_t);
4848 *node = (pm_implicit_node_t) {
4850 .type = PM_IMPLICIT_NODE,
4851 .node_id = PM_NODE_IDENTIFY(parser),
4852 .location = value->location
4863static pm_implicit_rest_node_t *
4864pm_implicit_rest_node_create(pm_parser_t *parser, const pm_token_t *token) {
4865 assert(token->type == PM_TOKEN_COMMA);
4867 pm_implicit_rest_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_rest_node_t);
4869 *node = (pm_implicit_rest_node_t) {
4871 .type = PM_IMPLICIT_REST_NODE,
4872 .node_id = PM_NODE_IDENTIFY(parser),
4873 .location = PM_LOCATION_TOKEN_VALUE(token)
4883static pm_integer_node_t *
4884pm_integer_node_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4885 assert(token->type == PM_TOKEN_INTEGER);
4886 pm_integer_node_t *node = PM_NODE_ALLOC(parser, pm_integer_node_t);
4888 *node = (pm_integer_node_t) {
4890 .type = PM_INTEGER_NODE,
4891 .flags = base | PM_NODE_FLAG_STATIC_LITERAL,
4892 .node_id = PM_NODE_IDENTIFY(parser),
4893 .location = PM_LOCATION_TOKEN_VALUE(token)
4898 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4900 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4901 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4902 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4903 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4904 default: assert(false && "unreachable"); break;
4907 pm_integer_parse(&node->value, integer_base, token->start, token->end);
4915static pm_imaginary_node_t *
4916pm_integer_node_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4917 assert(token->type == PM_TOKEN_INTEGER_IMAGINARY);
4919 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4920 *node = (pm_imaginary_node_t) {
4922 .type = PM_IMAGINARY_NODE,
4923 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4924 .node_id = PM_NODE_IDENTIFY(parser),
4925 .location = PM_LOCATION_TOKEN_VALUE(token)
4927 .numeric = (pm_node_t *) pm_integer_node_create(parser, base, &((pm_token_t) {
4928 .type = PM_TOKEN_INTEGER,
4929 .start = token->start,
4930 .end = token->end - 1
4941static pm_rational_node_t *
4942pm_integer_node_rational_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4943 assert(token->type == PM_TOKEN_INTEGER_RATIONAL);
4945 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
4946 *node = (pm_rational_node_t) {
4948 .type = PM_RATIONAL_NODE,
4949 .flags = base | PM_NODE_FLAG_STATIC_LITERAL,
4950 .node_id = PM_NODE_IDENTIFY(parser),
4951 .location = PM_LOCATION_TOKEN_VALUE(token)
4954 .denominator = { .value = 1, 0 }
4957 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4959 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4960 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4961 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4962 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4963 default: assert(false && "unreachable"); break;
4966 pm_integer_parse(&node->numerator, integer_base, token->start, token->end - 1);
4975static pm_imaginary_node_t *
4976pm_integer_node_rational_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4977 assert(token->type == PM_TOKEN_INTEGER_RATIONAL_IMAGINARY);
4979 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4980 *node = (pm_imaginary_node_t) {
4982 .type = PM_IMAGINARY_NODE,
4983 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4984 .node_id = PM_NODE_IDENTIFY(parser),
4985 .location = PM_LOCATION_TOKEN_VALUE(token)
4987 .numeric = (pm_node_t *) pm_integer_node_rational_create(parser, base, &((pm_token_t) {
4988 .type = PM_TOKEN_INTEGER_RATIONAL,
4989 .start = token->start,
4990 .end = token->end - 1
5000static pm_in_node_t *
5001pm_in_node_create(pm_parser_t *parser, pm_node_t *pattern, pm_statements_node_t *statements, const pm_token_t *in_keyword, const pm_token_t *then_keyword) {
5002 pm_in_node_t *node = PM_NODE_ALLOC(parser, pm_in_node_t);
5005 if (statements != NULL) {
5006 end = statements->base.location.end;
5007 } else if (then_keyword->type != PM_TOKEN_NOT_PROVIDED) {
5008 end = then_keyword->end;
5010 end = pattern->location.end;
5013 *node = (pm_in_node_t) {
5016 .node_id = PM_NODE_IDENTIFY(parser),
5018 .start = in_keyword->start,
5023 .statements = statements,
5024 .in_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
5025 .then_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword)
5034static pm_instance_variable_and_write_node_t *
5035pm_instance_variable_and_write_node_create(pm_parser_t *parser, pm_instance_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
5036 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5037 pm_instance_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_and_write_node_t);
5039 *node = (pm_instance_variable_and_write_node_t) {
5041 .type = PM_INSTANCE_VARIABLE_AND_WRITE_NODE,
5042 .node_id = PM_NODE_IDENTIFY(parser),
5044 .start = target->base.location.start,
5045 .end = value->location.end
5048 .name = target->name,
5049 .name_loc = target->base.location,
5050 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5060static pm_instance_variable_operator_write_node_t *
5061pm_instance_variable_operator_write_node_create(pm_parser_t *parser, pm_instance_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
5062 pm_instance_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_operator_write_node_t);
5064 *node = (pm_instance_variable_operator_write_node_t) {
5066 .type = PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE,
5067 .node_id = PM_NODE_IDENTIFY(parser),
5069 .start = target->base.location.start,
5070 .end = value->location.end
5073 .name = target->name,
5074 .name_loc = target->base.location,
5075 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5077 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
5086static pm_instance_variable_or_write_node_t *
5087pm_instance_variable_or_write_node_create(pm_parser_t *parser, pm_instance_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
5088 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5089 pm_instance_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_or_write_node_t);
5091 *node = (pm_instance_variable_or_write_node_t) {
5093 .type = PM_INSTANCE_VARIABLE_OR_WRITE_NODE,
5094 .node_id = PM_NODE_IDENTIFY(parser),
5096 .start = target->base.location.start,
5097 .end = value->location.end
5100 .name = target->name,
5101 .name_loc = target->base.location,
5102 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5112static pm_instance_variable_read_node_t *
5113pm_instance_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
5114 assert(token->type == PM_TOKEN_INSTANCE_VARIABLE);
5115 pm_instance_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_read_node_t);
5117 *node = (pm_instance_variable_read_node_t) {
5119 .type = PM_INSTANCE_VARIABLE_READ_NODE,
5120 .node_id = PM_NODE_IDENTIFY(parser),
5121 .location = PM_LOCATION_TOKEN_VALUE(token)
5123 .name = pm_parser_constant_id_token(parser, token)
5133static pm_instance_variable_write_node_t *
5134pm_instance_variable_write_node_create(pm_parser_t *parser, pm_instance_variable_read_node_t *read_node, pm_token_t *operator, pm_node_t *value) {
5135 pm_instance_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_write_node_t);
5136 *node = (pm_instance_variable_write_node_t) {
5138 .type = PM_INSTANCE_VARIABLE_WRITE_NODE,
5139 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5140 .node_id = PM_NODE_IDENTIFY(parser),
5142 .start = read_node->base.location.start,
5143 .end = value->location.end
5146 .name = read_node->name,
5147 .name_loc = PM_LOCATION_NODE_BASE_VALUE(read_node),
5148 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
5161pm_interpolated_node_append(pm_node_t *node, pm_node_list_t *parts, pm_node_t *part) {
5162 switch (PM_NODE_TYPE(part)) {
5163 case PM_STRING_NODE:
5164 pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5166 case PM_EMBEDDED_STATEMENTS_NODE: {
5167 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5168 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5170 if (embedded == NULL) {
5171 // If there are no statements or more than one statement, then
5172 // we lose the static literal flag.
5173 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5174 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5175 // If the embedded statement is a string, then we can keep the
5176 // static literal flag and mark the string as frozen.
5177 pm_node_flag_set(embedded, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5178 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5179 // If the embedded statement is an interpolated string and it's
5180 // a static literal, then we can keep the static literal flag.
5182 // Otherwise we lose the static literal flag.
5183 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5188 case PM_EMBEDDED_VARIABLE_NODE:
5189 pm_node_flag_unset((pm_node_t *) node, PM_NODE_FLAG_STATIC_LITERAL);
5192 assert(false && "unexpected node type");
5196 pm_node_list_append(parts, part);
5202static pm_interpolated_regular_expression_node_t *
5203pm_interpolated_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening) {
5204 pm_interpolated_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_regular_expression_node_t);
5206 *node = (pm_interpolated_regular_expression_node_t) {
5208 .type = PM_INTERPOLATED_REGULAR_EXPRESSION_NODE,
5209 .flags = PM_NODE_FLAG_STATIC_LITERAL,
5210 .node_id = PM_NODE_IDENTIFY(parser),
5212 .start = opening->start,
5216 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5217 .closing_loc = PM_LOCATION_TOKEN_VALUE(opening),
5225pm_interpolated_regular_expression_node_append(pm_interpolated_regular_expression_node_t *node, pm_node_t *part) {
5226 if (node->base.location.start > part->location.start) {
5227 node->base.location.start = part->location.start;
5229 if (node->base.location.end < part->location.end) {
5230 node->base.location.end = part->location.end;
5233 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5237pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_interpolated_regular_expression_node_t *node, const pm_token_t *closing) {
5238 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
5239 node->base.location.end = closing->end;
5240 pm_node_flag_set((pm_node_t *) node, pm_regular_expression_flags_create(parser, closing));
5267pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_node_t *part) {
5268#define CLEAR_FLAGS(node) \
5269 node->base.flags = (pm_node_flags_t) (node->base.flags & ~(PM_NODE_FLAG_STATIC_LITERAL | PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE))
5271#define MUTABLE_FLAGS(node) \
5272 node->base.flags = (pm_node_flags_t) ((node->base.flags | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE) & ~PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN);
5274 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
5275 node->base.location.start = part->location.start;
5278 node->base.location.end = MAX(node->base.location.end, part->location.end);
5280 switch (PM_NODE_TYPE(part)) {
5281 case PM_STRING_NODE:
5282 // If inner string is not frozen, clear flags for this string
5283 if (!PM_NODE_FLAG_P(part, PM_STRING_FLAGS_FROZEN)) {
5286 part->flags = (pm_node_flags_t) ((part->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5288 case PM_INTERPOLATED_STRING_NODE:
5289 if (PM_NODE_FLAG_P(part, PM_NODE_FLAG_STATIC_LITERAL)) {
5290 // If the string that we're concatenating is a static literal,
5291 // then we can keep the static literal flag for this string.
5293 // Otherwise, we lose the static literal flag here and we should
5294 // also clear the mutability flags.
5298 case PM_EMBEDDED_STATEMENTS_NODE: {
5299 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5300 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5302 if (embedded == NULL) {
5303 // If we're embedding multiple statements or no statements, then
5304 // the string is not longer a static literal.
5306 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5307 // If the embedded statement is a string, then we can make that
5308 // string as frozen and static literal, and not touch the static
5309 // literal status of this string.
5310 embedded->flags = (pm_node_flags_t) ((embedded->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5312 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5313 MUTABLE_FLAGS(node);
5315 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5316 // If the embedded statement is an interpolated string, but that
5317 // string is marked as static literal, then we can keep our
5318 // static literal status for this string.
5319 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5320 MUTABLE_FLAGS(node);
5323 // In all other cases, we lose the static literal flag here and
5330 case PM_EMBEDDED_VARIABLE_NODE:
5331 // Embedded variables clear static literal, which means we also
5332 // should clear the mutability flags.
5335 case PM_X_STRING_NODE:
5336 case PM_INTERPOLATED_X_STRING_NODE:
5337 // If this is an x string, then this is a syntax error. But we want
5338 // to handle it here so that we don't fail the assertion.
5342 assert(false && "unexpected node type");
5346 pm_node_list_append(&node->parts, part);
5355static pm_interpolated_string_node_t *
5356pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5357 pm_interpolated_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_string_node_t);
5358 pm_node_flags_t flags = PM_NODE_FLAG_STATIC_LITERAL;
5360 switch (parser->frozen_string_literal) {
5361 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
5362 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE;
5364 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
5365 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN;
5369 *node = (pm_interpolated_string_node_t) {
5371 .type = PM_INTERPOLATED_STRING_NODE,
5373 .node_id = PM_NODE_IDENTIFY(parser),
5375 .start = opening->start,
5376 .end = closing->end,
5379 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5380 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5384 if (parts != NULL) {
5386 PM_NODE_LIST_FOREACH(parts, index, part) {
5387 pm_interpolated_string_node_append(node, part);
5398pm_interpolated_string_node_closing_set(pm_interpolated_string_node_t *node, const pm_token_t *closing) {
5399 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5400 node->base.location.end = closing->end;
5404pm_interpolated_symbol_node_append(pm_interpolated_symbol_node_t *node, pm_node_t *part) {
5405 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
5406 node->base.location.start = part->location.start;
5409 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5410 node->base.location.end = MAX(node->base.location.end, part->location.end);
5414pm_interpolated_symbol_node_closing_loc_set(pm_interpolated_symbol_node_t *node, const pm_token_t *closing) {
5415 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5416 node->base.location.end = closing->end;
5422static pm_interpolated_symbol_node_t *
5423pm_interpolated_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5424 pm_interpolated_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_symbol_node_t);
5426 *node = (pm_interpolated_symbol_node_t) {
5428 .type = PM_INTERPOLATED_SYMBOL_NODE,
5429 .flags = PM_NODE_FLAG_STATIC_LITERAL,
5430 .node_id = PM_NODE_IDENTIFY(parser),
5432 .start = opening->start,
5433 .end = closing->end,
5436 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5437 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5441 if (parts != NULL) {
5443 PM_NODE_LIST_FOREACH(parts, index, part) {
5444 pm_interpolated_symbol_node_append(node, part);
5454static pm_interpolated_x_string_node_t *
5455pm_interpolated_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5456 pm_interpolated_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_x_string_node_t);
5458 *node = (pm_interpolated_x_string_node_t) {
5460 .type = PM_INTERPOLATED_X_STRING_NODE,
5461 .node_id = PM_NODE_IDENTIFY(parser),
5463 .start = opening->start,
5467 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5468 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5476pm_interpolated_xstring_node_append(pm_interpolated_x_string_node_t *node, pm_node_t *part) {
5477 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5478 node->base.location.end = part->location.end;
5482pm_interpolated_xstring_node_closing_set(pm_interpolated_x_string_node_t *node, const pm_token_t *closing) {
5483 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5484 node->base.location.end = closing->end;
5490static pm_it_local_variable_read_node_t *
5491pm_it_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5492 pm_it_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_it_local_variable_read_node_t);
5494 *node = (pm_it_local_variable_read_node_t) {
5496 .type = PM_IT_LOCAL_VARIABLE_READ_NODE,
5497 .node_id = PM_NODE_IDENTIFY(parser),
5498 .location = PM_LOCATION_TOKEN_VALUE(name)
5508static pm_it_parameters_node_t *
5509pm_it_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5510 pm_it_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_it_parameters_node_t);
5512 *node = (pm_it_parameters_node_t) {
5514 .type = PM_IT_PARAMETERS_NODE,
5515 .node_id = PM_NODE_IDENTIFY(parser),
5517 .start = opening->start,
5529static pm_keyword_hash_node_t *
5530pm_keyword_hash_node_create(pm_parser_t *parser) {
5531 pm_keyword_hash_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_hash_node_t);
5533 *node = (pm_keyword_hash_node_t) {
5535 .type = PM_KEYWORD_HASH_NODE,
5536 .flags = PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS,
5537 .node_id = PM_NODE_IDENTIFY(parser),
5538 .location = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
5550pm_keyword_hash_node_elements_append(pm_keyword_hash_node_t *hash, pm_node_t *element) {
5551 // If the element being added is not an AssocNode or does not have a symbol
5552 // key, then we want to turn the SYMBOL_KEYS flag off.
5553 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE) || !PM_NODE_TYPE_P(((pm_assoc_node_t *) element)->key, PM_SYMBOL_NODE)) {
5554 pm_node_flag_unset((pm_node_t *)hash, PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS);
5557 pm_node_list_append(&hash->elements, element);
5558 if (hash->base.location.start == NULL) {
5559 hash->base.location.start = element->location.start;
5561 hash->base.location.end = element->location.end;
5567static pm_required_keyword_parameter_node_t *
5568pm_required_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name) {
5569 pm_required_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_keyword_parameter_node_t);
5571 *node = (pm_required_keyword_parameter_node_t) {
5573 .type = PM_REQUIRED_KEYWORD_PARAMETER_NODE,
5574 .node_id = PM_NODE_IDENTIFY(parser),
5576 .start = name->start,
5580 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5581 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5590static pm_optional_keyword_parameter_node_t *
5591pm_optional_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, pm_node_t *value) {
5592 pm_optional_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_keyword_parameter_node_t);
5594 *node = (pm_optional_keyword_parameter_node_t) {
5596 .type = PM_OPTIONAL_KEYWORD_PARAMETER_NODE,
5597 .node_id = PM_NODE_IDENTIFY(parser),
5599 .start = name->start,
5600 .end = value->location.end
5603 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5604 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5614static pm_keyword_rest_parameter_node_t *
5615pm_keyword_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
5616 pm_keyword_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_rest_parameter_node_t);
5618 *node = (pm_keyword_rest_parameter_node_t) {
5620 .type = PM_KEYWORD_REST_PARAMETER_NODE,
5621 .node_id = PM_NODE_IDENTIFY(parser),
5623 .start = operator->start,
5624 .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
5627 .name = pm_parser_optional_constant_id_token(parser, name),
5628 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
5629 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5638static pm_lambda_node_t *
5639pm_lambda_node_create(
5640 pm_parser_t *parser,
5641 pm_constant_id_list_t *locals,
5642 const pm_token_t *operator,
5643 const pm_token_t *opening,
5644 const pm_token_t *closing,
5645 pm_node_t *parameters,
5648 pm_lambda_node_t *node = PM_NODE_ALLOC(parser, pm_lambda_node_t);
5650 *node = (pm_lambda_node_t) {
5652 .type = PM_LAMBDA_NODE,
5653 .node_id = PM_NODE_IDENTIFY(parser),
5655 .start = operator->start,
5660 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5661 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5662 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
5663 .parameters = parameters,
5673static pm_local_variable_and_write_node_t *
5674pm_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) {
5675 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));
5676 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5677 pm_local_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_and_write_node_t);
5679 *node = (pm_local_variable_and_write_node_t) {
5681 .type = PM_LOCAL_VARIABLE_AND_WRITE_NODE,
5682 .node_id = PM_NODE_IDENTIFY(parser),
5684 .start = target->location.start,
5685 .end = value->location.end
5688 .name_loc = target->location,
5689 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5701static pm_local_variable_operator_write_node_t *
5702pm_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) {
5703 pm_local_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_operator_write_node_t);
5705 *node = (pm_local_variable_operator_write_node_t) {
5707 .type = PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE,
5708 .node_id = PM_NODE_IDENTIFY(parser),
5710 .start = target->location.start,
5711 .end = value->location.end
5714 .name_loc = target->location,
5715 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5718 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
5728static pm_local_variable_or_write_node_t *
5729pm_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) {
5730 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));
5731 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5732 pm_local_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_or_write_node_t);
5734 *node = (pm_local_variable_or_write_node_t) {
5736 .type = PM_LOCAL_VARIABLE_OR_WRITE_NODE,
5737 .node_id = PM_NODE_IDENTIFY(parser),
5739 .start = target->location.start,
5740 .end = value->location.end
5743 .name_loc = target->location,
5744 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5756static pm_local_variable_read_node_t *
5757pm_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) {
5758 if (!missing) pm_locals_read(&pm_parser_scope_find(parser, depth)->locals, name_id);
5760 pm_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_read_node_t);
5762 *node = (pm_local_variable_read_node_t) {
5764 .type = PM_LOCAL_VARIABLE_READ_NODE,
5765 .node_id = PM_NODE_IDENTIFY(parser),
5766 .location = PM_LOCATION_TOKEN_VALUE(name)
5778static pm_local_variable_read_node_t *
5779pm_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5780 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5781 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, false);
5788static pm_local_variable_read_node_t *
5789pm_local_variable_read_node_missing_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, true);
5797static pm_local_variable_write_node_t *
5798pm_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) {
5799 pm_local_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_write_node_t);
5801 *node = (pm_local_variable_write_node_t) {
5803 .type = PM_LOCAL_VARIABLE_WRITE_NODE,
5804 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5805 .node_id = PM_NODE_IDENTIFY(parser),
5807 .start = name_loc->start,
5808 .end = value->location.end
5814 .name_loc = *name_loc,
5815 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator)
5825pm_token_is_it(const uint8_t *start, const uint8_t *end) {
5826 return (end - start == 2) && (start[0] == 'i') && (start[1] == 't');
5834pm_token_is_numbered_parameter(const uint8_t *start, const uint8_t *end) {
5835 return (end - start == 2) && (start[0] == '_') && (start[1] != '0') && (pm_char_is_decimal_digit(start[1]));
5843pm_refute_numbered_parameter(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
5844 if (pm_token_is_numbered_parameter(start, end)) {
5845 PM_PARSER_ERR_FORMAT(parser, start, end, PM_ERR_PARAMETER_NUMBERED_RESERVED, start);
5853static pm_local_variable_target_node_t *
5854pm_local_variable_target_node_create(pm_parser_t *parser, const pm_location_t *location, pm_constant_id_t name, uint32_t depth) {
5855 pm_refute_numbered_parameter(parser, location->start, location->end);
5856 pm_local_variable_target_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_target_node_t);
5858 *node = (pm_local_variable_target_node_t) {
5860 .type = PM_LOCAL_VARIABLE_TARGET_NODE,
5861 .node_id = PM_NODE_IDENTIFY(parser),
5862 .location = *location
5874static pm_match_predicate_node_t *
5875pm_match_predicate_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5876 pm_assert_value_expression(parser, value);
5878 pm_match_predicate_node_t *node = PM_NODE_ALLOC(parser, pm_match_predicate_node_t);
5880 *node = (pm_match_predicate_node_t) {
5882 .type = PM_MATCH_PREDICATE_NODE,
5883 .node_id = PM_NODE_IDENTIFY(parser),
5885 .start = value->location.start,
5886 .end = pattern->location.end
5891 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5900static pm_match_required_node_t *
5901pm_match_required_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5902 pm_assert_value_expression(parser, value);
5904 pm_match_required_node_t *node = PM_NODE_ALLOC(parser, pm_match_required_node_t);
5906 *node = (pm_match_required_node_t) {
5908 .type = PM_MATCH_REQUIRED_NODE,
5909 .node_id = PM_NODE_IDENTIFY(parser),
5911 .start = value->location.start,
5912 .end = pattern->location.end
5917 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5926static pm_match_write_node_t *
5927pm_match_write_node_create(pm_parser_t *parser, pm_call_node_t *call) {
5928 pm_match_write_node_t *node = PM_NODE_ALLOC(parser, pm_match_write_node_t);
5930 *node = (pm_match_write_node_t) {
5932 .type = PM_MATCH_WRITE_NODE,
5933 .node_id = PM_NODE_IDENTIFY(parser),
5934 .location = call->base.location
5946static pm_module_node_t *
5947pm_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) {
5948 pm_module_node_t *node = PM_NODE_ALLOC(parser, pm_module_node_t);
5950 *node = (pm_module_node_t) {
5952 .type = PM_MODULE_NODE,
5953 .node_id = PM_NODE_IDENTIFY(parser),
5955 .start = module_keyword->start,
5956 .end = end_keyword->end
5959 .locals = (locals == NULL ? ((pm_constant_id_list_t) { .ids = NULL, .size = 0, .capacity = 0 }) : *locals),
5960 .module_keyword_loc = PM_LOCATION_TOKEN_VALUE(module_keyword),
5961 .constant_path = constant_path,
5963 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
5964 .name = pm_parser_constant_id_token(parser, name)
5973static pm_multi_target_node_t *
5974pm_multi_target_node_create(pm_parser_t *parser) {
5975 pm_multi_target_node_t *node = PM_NODE_ALLOC(parser, pm_multi_target_node_t);
5977 *node = (pm_multi_target_node_t) {
5979 .type = PM_MULTI_TARGET_NODE,
5980 .node_id = PM_NODE_IDENTIFY(parser),
5981 .location = { .start = NULL, .end = NULL }
5986 .lparen_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
5987 .rparen_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
5997pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t *node, pm_node_t *target) {
5998 if (PM_NODE_TYPE_P(target, PM_SPLAT_NODE)) {
5999 if (node->rest == NULL) {
6000 node->rest = target;
6002 pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
6003 pm_node_list_append(&node->rights, target);
6005 } else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
6006 if (node->rest == NULL) {
6007 node->rest = target;
6009 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
6010 pm_node_list_append(&node->rights, target);
6012 } else if (node->rest == NULL) {
6013 pm_node_list_append(&node->lefts, target);
6015 pm_node_list_append(&node->rights, target);
6018 if (node->base.location.start == NULL || (node->base.location.start > target->location.start)) {
6019 node->base.location.start = target->location.start;
6022 if (node->base.location.end == NULL || (node->base.location.end < target->location.end)) {
6023 node->base.location.end = target->location.end;
6031pm_multi_target_node_opening_set(pm_multi_target_node_t *node, const pm_token_t *lparen) {
6032 node->base.location.start = lparen->start;
6033 node->lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen);
6040pm_multi_target_node_closing_set(pm_multi_target_node_t *node, const pm_token_t *rparen) {
6041 node->base.location.end = rparen->end;
6042 node->rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen);
6048static pm_multi_write_node_t *
6049pm_multi_write_node_create(pm_parser_t *parser, pm_multi_target_node_t *target, const pm_token_t *operator, pm_node_t *value) {
6050 pm_multi_write_node_t *node = PM_NODE_ALLOC(parser, pm_multi_write_node_t);
6052 *node = (pm_multi_write_node_t) {
6054 .type = PM_MULTI_WRITE_NODE,
6055 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
6056 .node_id = PM_NODE_IDENTIFY(parser),
6058 .start = target->base.location.start,
6059 .end = value->location.end
6062 .lefts = target->lefts,
6063 .rest = target->rest,
6064 .rights = target->rights,
6065 .lparen_loc = target->lparen_loc,
6066 .rparen_loc = target->rparen_loc,
6067 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6071 // Explicitly do not call pm_node_destroy here because we want to keep
6072 // around all of the information within the MultiWriteNode node.
6081static pm_next_node_t *
6082pm_next_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6083 assert(keyword->type == PM_TOKEN_KEYWORD_NEXT);
6084 pm_next_node_t *node = PM_NODE_ALLOC(parser, pm_next_node_t);
6086 *node = (pm_next_node_t) {
6088 .type = PM_NEXT_NODE,
6089 .node_id = PM_NODE_IDENTIFY(parser),
6091 .start = keyword->start,
6092 .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
6095 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6096 .arguments = arguments
6105static pm_nil_node_t *
6106pm_nil_node_create(pm_parser_t *parser, const pm_token_t *token) {
6107 assert(token->type == PM_TOKEN_KEYWORD_NIL);
6108 pm_nil_node_t *node = PM_NODE_ALLOC(parser, pm_nil_node_t);
6110 *node = (pm_nil_node_t) {{
6111 .type = PM_NIL_NODE,
6112 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6113 .node_id = PM_NODE_IDENTIFY(parser),
6114 .location = PM_LOCATION_TOKEN_VALUE(token)
6123static pm_no_keywords_parameter_node_t *
6124pm_no_keywords_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
6125 assert(operator->type == PM_TOKEN_USTAR_STAR || operator->type == PM_TOKEN_STAR_STAR);
6126 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
6127 pm_no_keywords_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_no_keywords_parameter_node_t);
6129 *node = (pm_no_keywords_parameter_node_t) {
6131 .type = PM_NO_KEYWORDS_PARAMETER_NODE,
6132 .node_id = PM_NODE_IDENTIFY(parser),
6134 .start = operator->start,
6138 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6139 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
6148static pm_numbered_parameters_node_t *
6149pm_numbered_parameters_node_create(pm_parser_t *parser, const pm_location_t *location, uint8_t maximum) {
6150 pm_numbered_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_parameters_node_t);
6152 *node = (pm_numbered_parameters_node_t) {
6154 .type = PM_NUMBERED_PARAMETERS_NODE,
6155 .node_id = PM_NODE_IDENTIFY(parser),
6156 .location = *location
6168#define NTH_REF_MAX ((uint32_t) (INT_MAX >> 1))
6177pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *token) {
6178 const uint8_t *start = token->start + 1;
6179 const uint8_t *end = token->end;
6181 ptrdiff_t diff = end - start;
6183#if PTRDIFF_MAX > SIZE_MAX
6184 assert(diff < (ptrdiff_t) SIZE_MAX);
6186 size_t length = (size_t) diff;
6188 char *digits = xcalloc(length + 1, sizeof(char));
6189 memcpy(digits, start, length);
6190 digits[length] = '\0';
6194 unsigned long value = strtoul(digits, &endptr, 10);
6196 if ((digits == endptr) || (*endptr != '\0')) {
6197 pm_parser_err(parser, start, end, PM_ERR_INVALID_NUMBER_DECIMAL);
6203 if ((errno == ERANGE) || (value > NTH_REF_MAX)) {
6204 PM_PARSER_WARN_FORMAT(parser, start, end, PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start);
6208 return (uint32_t) value;
6216static pm_numbered_reference_read_node_t *
6217pm_numbered_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
6218 assert(name->type == PM_TOKEN_NUMBERED_REFERENCE);
6219 pm_numbered_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_reference_read_node_t);
6221 *node = (pm_numbered_reference_read_node_t) {
6223 .type = PM_NUMBERED_REFERENCE_READ_NODE,
6224 .node_id = PM_NODE_IDENTIFY(parser),
6225 .location = PM_LOCATION_TOKEN_VALUE(name),
6227 .number = pm_numbered_reference_read_node_number(parser, name)
6236static pm_optional_parameter_node_t *
6237pm_optional_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator, pm_node_t *value) {
6238 pm_optional_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_parameter_node_t);
6240 *node = (pm_optional_parameter_node_t) {
6242 .type = PM_OPTIONAL_PARAMETER_NODE,
6243 .node_id = PM_NODE_IDENTIFY(parser),
6245 .start = name->start,
6246 .end = value->location.end
6249 .name = pm_parser_constant_id_token(parser, name),
6250 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
6251 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6261static pm_or_node_t *
6262pm_or_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
6263 pm_assert_value_expression(parser, left);
6265 pm_or_node_t *node = PM_NODE_ALLOC(parser, pm_or_node_t);
6267 *node = (pm_or_node_t) {
6270 .node_id = PM_NODE_IDENTIFY(parser),
6272 .start = left->location.start,
6273 .end = right->location.end
6278 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6287static pm_parameters_node_t *
6288pm_parameters_node_create(pm_parser_t *parser) {
6289 pm_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_parameters_node_t);
6291 *node = (pm_parameters_node_t) {
6293 .type = PM_PARAMETERS_NODE,
6294 .node_id = PM_NODE_IDENTIFY(parser),
6295 .location = PM_LOCATION_TOKEN_VALUE(&parser->current)
6298 .keyword_rest = NULL,
6313pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param) {
6314 if (params->base.location.start == NULL) {
6315 params->base.location.start = param->location.start;
6317 params->base.location.start = params->base.location.start < param->location.start ? params->base.location.start : param->location.start;
6320 if (params->base.location.end == NULL) {
6321 params->base.location.end = param->location.end;
6323 params->base.location.end = params->base.location.end > param->location.end ? params->base.location.end : param->location.end;
6331pm_parameters_node_requireds_append(pm_parameters_node_t *params, pm_node_t *param) {
6332 pm_parameters_node_location_set(params, param);
6333 pm_node_list_append(¶ms->requireds, param);
6340pm_parameters_node_optionals_append(pm_parameters_node_t *params, pm_optional_parameter_node_t *param) {
6341 pm_parameters_node_location_set(params, (pm_node_t *) param);
6342 pm_node_list_append(¶ms->optionals, (pm_node_t *) param);
6349pm_parameters_node_posts_append(pm_parameters_node_t *params, pm_node_t *param) {
6350 pm_parameters_node_location_set(params, param);
6351 pm_node_list_append(¶ms->posts, param);
6358pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6359 pm_parameters_node_location_set(params, param);
6360 params->rest = param;
6367pm_parameters_node_keywords_append(pm_parameters_node_t *params, pm_node_t *param) {
6368 pm_parameters_node_location_set(params, param);
6369 pm_node_list_append(¶ms->keywords, param);
6376pm_parameters_node_keyword_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6377 assert(params->keyword_rest == NULL);
6378 pm_parameters_node_location_set(params, param);
6379 params->keyword_rest = param;
6386pm_parameters_node_block_set(pm_parameters_node_t *params, pm_block_parameter_node_t *param) {
6387 assert(params->block == NULL);
6388 pm_parameters_node_location_set(params, (pm_node_t *) param);
6389 params->block = param;
6395static pm_program_node_t *
6396pm_program_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, pm_statements_node_t *statements) {
6397 pm_program_node_t *node = PM_NODE_ALLOC(parser, pm_program_node_t);
6399 *node = (pm_program_node_t) {
6401 .type = PM_PROGRAM_NODE,
6402 .node_id = PM_NODE_IDENTIFY(parser),
6404 .start = statements == NULL ? parser->start : statements->base.location.start,
6405 .end = statements == NULL ? parser->end : statements->base.location.end
6409 .statements = statements
6418static pm_parentheses_node_t *
6419pm_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) {
6420 pm_parentheses_node_t *node = PM_NODE_ALLOC(parser, pm_parentheses_node_t);
6422 *node = (pm_parentheses_node_t) {
6424 .type = PM_PARENTHESES_NODE,
6426 .node_id = PM_NODE_IDENTIFY(parser),
6428 .start = opening->start,
6433 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6434 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6443static pm_pinned_expression_node_t *
6444pm_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) {
6445 pm_pinned_expression_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_expression_node_t);
6447 *node = (pm_pinned_expression_node_t) {
6449 .type = PM_PINNED_EXPRESSION_NODE,
6450 .node_id = PM_NODE_IDENTIFY(parser),
6452 .start = operator->start,
6456 .expression = expression,
6457 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6458 .lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen),
6459 .rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen)
6468static pm_pinned_variable_node_t *
6469pm_pinned_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
6470 pm_pinned_variable_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_variable_node_t);
6472 *node = (pm_pinned_variable_node_t) {
6474 .type = PM_PINNED_VARIABLE_NODE,
6475 .node_id = PM_NODE_IDENTIFY(parser),
6477 .start = operator->start,
6478 .end = variable->location.end
6481 .variable = variable,
6482 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6491static pm_post_execution_node_t *
6492pm_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) {
6493 pm_post_execution_node_t *node = PM_NODE_ALLOC(parser, pm_post_execution_node_t);
6495 *node = (pm_post_execution_node_t) {
6497 .type = PM_POST_EXECUTION_NODE,
6498 .node_id = PM_NODE_IDENTIFY(parser),
6500 .start = keyword->start,
6504 .statements = statements,
6505 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6506 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6507 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6516static pm_pre_execution_node_t *
6517pm_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) {
6518 pm_pre_execution_node_t *node = PM_NODE_ALLOC(parser, pm_pre_execution_node_t);
6520 *node = (pm_pre_execution_node_t) {
6522 .type = PM_PRE_EXECUTION_NODE,
6523 .node_id = PM_NODE_IDENTIFY(parser),
6525 .start = keyword->start,
6529 .statements = statements,
6530 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6531 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6532 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6541static pm_range_node_t *
6542pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
6543 pm_assert_value_expression(parser, left);
6544 pm_assert_value_expression(parser, right);
6546 pm_range_node_t *node = PM_NODE_ALLOC(parser, pm_range_node_t);
6547 pm_node_flags_t flags = 0;
6549 // Indicate that this node is an exclusive range if the operator is `...`.
6550 if (operator->type == PM_TOKEN_DOT_DOT_DOT || operator->type == PM_TOKEN_UDOT_DOT_DOT) {
6551 flags |= PM_RANGE_FLAGS_EXCLUDE_END;
6554 // Indicate that this node is a static literal (i.e., can be compiled with
6555 // a putobject in CRuby) if the left and right are implicit nil, explicit
6556 // nil, or integers.
6558 (left == NULL || PM_NODE_TYPE_P(left, PM_NIL_NODE) || PM_NODE_TYPE_P(left, PM_INTEGER_NODE)) &&
6559 (right == NULL || PM_NODE_TYPE_P(right, PM_NIL_NODE) || PM_NODE_TYPE_P(right, PM_INTEGER_NODE))
6561 flags |= PM_NODE_FLAG_STATIC_LITERAL;
6564 *node = (pm_range_node_t) {
6566 .type = PM_RANGE_NODE,
6568 .node_id = PM_NODE_IDENTIFY(parser),
6570 .start = (left == NULL ? operator->start : left->location.start),
6571 .end = (right == NULL ? operator->end : right->location.end)
6576 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6585static pm_redo_node_t *
6586pm_redo_node_create(pm_parser_t *parser, const pm_token_t *token) {
6587 assert(token->type == PM_TOKEN_KEYWORD_REDO);
6588 pm_redo_node_t *node = PM_NODE_ALLOC(parser, pm_redo_node_t);
6590 *node = (pm_redo_node_t) {{
6591 .type = PM_REDO_NODE,
6592 .node_id = PM_NODE_IDENTIFY(parser),
6593 .location = PM_LOCATION_TOKEN_VALUE(token)
6603static pm_regular_expression_node_t *
6604pm_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) {
6605 pm_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_regular_expression_node_t);
6607 *node = (pm_regular_expression_node_t) {
6609 .type = PM_REGULAR_EXPRESSION_NODE,
6610 .flags = pm_regular_expression_flags_create(parser, closing) | PM_NODE_FLAG_STATIC_LITERAL,
6611 .node_id = PM_NODE_IDENTIFY(parser),
6613 .start = MIN(opening->start, closing->start),
6614 .end = MAX(opening->end, closing->end)
6617 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6618 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
6619 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
6620 .unescaped = *unescaped
6629static inline pm_regular_expression_node_t *
6630pm_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6631 return pm_regular_expression_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6637static pm_required_parameter_node_t *
6638pm_required_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
6639 pm_required_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_parameter_node_t);
6641 *node = (pm_required_parameter_node_t) {
6643 .type = PM_REQUIRED_PARAMETER_NODE,
6644 .node_id = PM_NODE_IDENTIFY(parser),
6645 .location = PM_LOCATION_TOKEN_VALUE(token)
6647 .name = pm_parser_constant_id_token(parser, token)
6656static pm_rescue_modifier_node_t *
6657pm_rescue_modifier_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *keyword, pm_node_t *rescue_expression) {
6658 pm_rescue_modifier_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_modifier_node_t);
6660 *node = (pm_rescue_modifier_node_t) {
6662 .type = PM_RESCUE_MODIFIER_NODE,
6663 .node_id = PM_NODE_IDENTIFY(parser),
6665 .start = expression->location.start,
6666 .end = rescue_expression->location.end
6669 .expression = expression,
6670 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6671 .rescue_expression = rescue_expression
6680static pm_rescue_node_t *
6681pm_rescue_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
6682 pm_rescue_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_node_t);
6684 *node = (pm_rescue_node_t) {
6686 .type = PM_RESCUE_NODE,
6687 .node_id = PM_NODE_IDENTIFY(parser),
6688 .location = PM_LOCATION_TOKEN_VALUE(keyword)
6690 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6691 .operator_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
6692 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
6703pm_rescue_node_operator_set(pm_rescue_node_t *node, const pm_token_t *operator) {
6704 node->operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
6711pm_rescue_node_reference_set(pm_rescue_node_t *node, pm_node_t *reference) {
6712 node->reference = reference;
6713 node->base.location.end = reference->location.end;
6720pm_rescue_node_statements_set(pm_rescue_node_t *node, pm_statements_node_t *statements) {
6721 node->statements = statements;
6722 if (pm_statements_node_body_length(statements) > 0) {
6723 node->base.location.end = statements->base.location.end;
6731pm_rescue_node_subsequent_set(pm_rescue_node_t *node, pm_rescue_node_t *subsequent) {
6732 node->subsequent = subsequent;
6733 node->base.location.end = subsequent->base.location.end;
6740pm_rescue_node_exceptions_append(pm_rescue_node_t *node, pm_node_t *exception) {
6741 pm_node_list_append(&node->exceptions, exception);
6742 node->base.location.end = exception->location.end;
6748static pm_rest_parameter_node_t *
6749pm_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
6750 pm_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_rest_parameter_node_t);
6752 *node = (pm_rest_parameter_node_t) {
6754 .type = PM_REST_PARAMETER_NODE,
6755 .node_id = PM_NODE_IDENTIFY(parser),
6757 .start = operator->start,
6758 .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
6761 .name = pm_parser_optional_constant_id_token(parser, name),
6762 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
6763 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6772static pm_retry_node_t *
6773pm_retry_node_create(pm_parser_t *parser, const pm_token_t *token) {
6774 assert(token->type == PM_TOKEN_KEYWORD_RETRY);
6775 pm_retry_node_t *node = PM_NODE_ALLOC(parser, pm_retry_node_t);
6777 *node = (pm_retry_node_t) {{
6778 .type = PM_RETRY_NODE,
6779 .node_id = PM_NODE_IDENTIFY(parser),
6780 .location = PM_LOCATION_TOKEN_VALUE(token)
6789static pm_return_node_t *
6790pm_return_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6791 pm_return_node_t *node = PM_NODE_ALLOC(parser, pm_return_node_t);
6793 *node = (pm_return_node_t) {
6795 .type = PM_RETURN_NODE,
6796 .node_id = PM_NODE_IDENTIFY(parser),
6798 .start = keyword->start,
6799 .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
6802 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6803 .arguments = arguments
6812static pm_self_node_t *
6813pm_self_node_create(pm_parser_t *parser, const pm_token_t *token) {
6814 assert(token->type == PM_TOKEN_KEYWORD_SELF);
6815 pm_self_node_t *node = PM_NODE_ALLOC(parser, pm_self_node_t);
6817 *node = (pm_self_node_t) {{
6818 .type = PM_SELF_NODE,
6819 .node_id = PM_NODE_IDENTIFY(parser),
6820 .location = PM_LOCATION_TOKEN_VALUE(token)
6829static pm_shareable_constant_node_t *
6830pm_shareable_constant_node_create(pm_parser_t *parser, pm_node_t *write, pm_shareable_constant_value_t value) {
6831 pm_shareable_constant_node_t *node = PM_NODE_ALLOC(parser, pm_shareable_constant_node_t);
6833 *node = (pm_shareable_constant_node_t) {
6835 .type = PM_SHAREABLE_CONSTANT_NODE,
6836 .flags = (pm_node_flags_t) value,
6837 .node_id = PM_NODE_IDENTIFY(parser),
6838 .location = PM_LOCATION_NODE_VALUE(write)
6849static pm_singleton_class_node_t *
6850pm_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) {
6851 pm_singleton_class_node_t *node = PM_NODE_ALLOC(parser, pm_singleton_class_node_t);
6853 *node = (pm_singleton_class_node_t) {
6855 .type = PM_SINGLETON_CLASS_NODE,
6856 .node_id = PM_NODE_IDENTIFY(parser),
6858 .start = class_keyword->start,
6859 .end = end_keyword->end
6863 .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
6864 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6865 .expression = expression,
6867 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
6876static pm_source_encoding_node_t *
6877pm_source_encoding_node_create(pm_parser_t *parser, const pm_token_t *token) {
6878 assert(token->type == PM_TOKEN_KEYWORD___ENCODING__);
6879 pm_source_encoding_node_t *node = PM_NODE_ALLOC(parser, pm_source_encoding_node_t);
6881 *node = (pm_source_encoding_node_t) {{
6882 .type = PM_SOURCE_ENCODING_NODE,
6883 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6884 .node_id = PM_NODE_IDENTIFY(parser),
6885 .location = PM_LOCATION_TOKEN_VALUE(token)
6894static pm_source_file_node_t*
6895pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword) {
6896 pm_source_file_node_t *node = PM_NODE_ALLOC(parser, pm_source_file_node_t);
6897 assert(file_keyword->type == PM_TOKEN_KEYWORD___FILE__);
6899 pm_node_flags_t flags = 0;
6901 switch (parser->frozen_string_literal) {
6902 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6903 flags |= PM_STRING_FLAGS_MUTABLE;
6905 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6906 flags |= PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6910 *node = (pm_source_file_node_t) {
6912 .type = PM_SOURCE_FILE_NODE,
6914 .node_id = PM_NODE_IDENTIFY(parser),
6915 .location = PM_LOCATION_TOKEN_VALUE(file_keyword),
6917 .filepath = parser->filepath
6926static pm_source_line_node_t *
6927pm_source_line_node_create(pm_parser_t *parser, const pm_token_t *token) {
6928 assert(token->type == PM_TOKEN_KEYWORD___LINE__);
6929 pm_source_line_node_t *node = PM_NODE_ALLOC(parser, pm_source_line_node_t);
6931 *node = (pm_source_line_node_t) {{
6932 .type = PM_SOURCE_LINE_NODE,
6933 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6934 .node_id = PM_NODE_IDENTIFY(parser),
6935 .location = PM_LOCATION_TOKEN_VALUE(token)
6944static pm_splat_node_t *
6945pm_splat_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
6946 pm_splat_node_t *node = PM_NODE_ALLOC(parser, pm_splat_node_t);
6948 *node = (pm_splat_node_t) {
6950 .type = PM_SPLAT_NODE,
6951 .node_id = PM_NODE_IDENTIFY(parser),
6953 .start = operator->start,
6954 .end = (expression == NULL ? operator->end : expression->location.end)
6957 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6958 .expression = expression
6967static pm_statements_node_t *
6968pm_statements_node_create(pm_parser_t *parser) {
6969 pm_statements_node_t *node = PM_NODE_ALLOC(parser, pm_statements_node_t);
6971 *node = (pm_statements_node_t) {
6973 .type = PM_STATEMENTS_NODE,
6974 .node_id = PM_NODE_IDENTIFY(parser),
6975 .location = PM_LOCATION_NULL_VALUE(parser)
6987pm_statements_node_body_length(pm_statements_node_t *node) {
6988 return node && node->body.size;
6995pm_statements_node_location_set(pm_statements_node_t *node, const uint8_t *start, const uint8_t *end) {
6996 node->base.location = (pm_location_t) { .start = start, .end = end };
7004pm_statements_node_body_update(pm_statements_node_t *node, pm_node_t *statement) {
7005 if (pm_statements_node_body_length(node) == 0 || statement->location.start < node->base.location.start) {
7006 node->base.location.start = statement->location.start;
7009 if (statement->location.end > node->base.location.end) {
7010 node->base.location.end = statement->location.end;
7018pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline) {
7019 pm_statements_node_body_update(node, statement);
7021 if (node->body.size > 0) {
7022 const pm_node_t *previous = node->body.nodes[node->body.size - 1];
7024 switch (PM_NODE_TYPE(previous)) {
7029 case PM_RETURN_NODE:
7030 pm_parser_warn_node(parser, statement, PM_WARN_UNREACHABLE_STATEMENT);
7037 pm_node_list_append(&node->body, statement);
7038 if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
7045pm_statements_node_body_prepend(pm_statements_node_t *node, pm_node_t *statement) {
7046 pm_statements_node_body_update(node, statement);
7047 pm_node_list_prepend(&node->body, statement);
7048 pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
7054static inline pm_string_node_t *
7055pm_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) {
7056 pm_string_node_t *node = PM_NODE_ALLOC(parser, pm_string_node_t);
7057 pm_node_flags_t flags = 0;
7059 switch (parser->frozen_string_literal) {
7060 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
7061 flags = PM_STRING_FLAGS_MUTABLE;
7063 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
7064 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
7068 *node = (pm_string_node_t) {
7070 .type = PM_STRING_NODE,
7072 .node_id = PM_NODE_IDENTIFY(parser),
7074 .start = (opening->type == PM_TOKEN_NOT_PROVIDED ? content->start : opening->start),
7075 .end = (closing->type == PM_TOKEN_NOT_PROVIDED ? content->end : closing->end)
7078 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7079 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
7080 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7081 .unescaped = *string
7090static pm_string_node_t *
7091pm_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7092 return pm_string_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7099static pm_string_node_t *
7100pm_string_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7101 pm_string_node_t *node = pm_string_node_create_unescaped(parser, opening, content, closing, &parser->current_string);
7102 parser->current_string = PM_STRING_EMPTY;
7109static pm_super_node_t *
7110pm_super_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_t *arguments) {
7111 assert(keyword->type == PM_TOKEN_KEYWORD_SUPER);
7112 pm_super_node_t *node = PM_NODE_ALLOC(parser, pm_super_node_t);
7114 const uint8_t *end = pm_arguments_end(arguments);
7116 assert(false && "unreachable");
7119 *node = (pm_super_node_t) {
7121 .type = PM_SUPER_NODE,
7122 .node_id = PM_NODE_IDENTIFY(parser),
7124 .start = keyword->start,
7128 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7129 .lparen_loc = arguments->opening_loc,
7130 .arguments = arguments->arguments,
7131 .rparen_loc = arguments->closing_loc,
7132 .block = arguments->block
7143pm_ascii_only_p(const pm_string_t *contents) {
7144 const size_t length = pm_string_length(contents);
7145 const uint8_t *source = pm_string_source(contents);
7147 for (size_t index = 0; index < length; index++) {
7148 if (source[index] & 0x80) return false;
7158parse_symbol_encoding_validate_utf8(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
7159 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
7160 size_t width = pm_encoding_utf_8_char_width(cursor, end - cursor);
7163 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
7176parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
7177 const pm_encoding_t *encoding = parser->encoding;
7179 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
7180 size_t width = encoding->char_width(cursor, end - cursor);
7183 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
7200static inline pm_node_flags_t
7201parse_symbol_encoding(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents, bool validate) {
7202 if (parser->explicit_encoding != NULL) {
7203 // A Symbol may optionally have its encoding explicitly set. This will
7204 // happen if an escape sequence results in a non-ASCII code point.
7205 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7206 if (validate) parse_symbol_encoding_validate_utf8(parser, location, contents);
7207 return PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING;
7208 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7209 return PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING;
7210 } else if (validate) {
7211 parse_symbol_encoding_validate_other(parser, location, contents);
7213 } else if (pm_ascii_only_p(contents)) {
7214 // Ruby stipulates that all source files must use an ASCII-compatible
7215 // encoding. Thus, all symbols appearing in source are eligible for
7216 // "downgrading" to US-ASCII.
7217 return PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING;
7218 } else if (validate) {
7219 parse_symbol_encoding_validate_other(parser, location, contents);
7225static pm_node_flags_t
7226parse_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) {
7227 assert ((modifier == 'n' && modifier_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) ||
7228 (modifier == 'u' && modifier_encoding == PM_ENCODING_UTF_8_ENTRY) ||
7229 (modifier == 'e' && modifier_encoding == PM_ENCODING_EUC_JP_ENTRY) ||
7230 (modifier == 's' && modifier_encoding == PM_ENCODING_WINDOWS_31J_ENTRY));
7232 // There's special validation logic used if a string does not contain any character escape sequences.
7233 if (parser->explicit_encoding == NULL) {
7234 // If an ASCII-only string without character escapes is used with an encoding modifier, then resulting Regexp
7235 // has the modifier encoding, unless the ASCII-8BIT modifier is used, in which case the Regexp "downgrades" to
7236 // the US-ASCII encoding.
7238 return modifier == 'n' ? PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING : flags;
7241 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7243 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
7245 } else if (parser->encoding != modifier_encoding) {
7246 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_ENCODING_OPTION_MISMATCH, modifier, parser->encoding->name);
7248 if (modifier == 'n' && !ascii_only) {
7249 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));
7256 // 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.
7257 bool mixed_encoding = false;
7259 if (mixed_encoding) {
7260 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
7261 } else if (modifier != 'n' && parser->explicit_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) {
7262 // 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.
7263 bool valid_string_in_modifier_encoding = true;
7265 if (!valid_string_in_modifier_encoding) {
7266 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
7268 } else if (modifier != 'u' && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7269 // 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.
7270 if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
7271 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));
7275 // We've determined the encoding would naturally be EUC-JP and there is no need to force the encoding to anything else.
7285static pm_node_flags_t
7286parse_and_validate_regular_expression_encoding(pm_parser_t *parser, const pm_string_t *source, bool ascii_only, pm_node_flags_t flags) {
7287 // 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.
7288 bool valid_unicode_range = true;
7289 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY && !valid_unicode_range) {
7290 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));
7294 // US-ASCII strings do not admit multi-byte character literals. However, character escape sequences corresponding
7295 // to multi-byte characters are allowed.
7296 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY && parser->explicit_encoding == NULL && !ascii_only) {
7297 // CRuby will continue processing even though a SyntaxError has already been detected. It may result in the
7298 // following error message appearing twice. We do the same for compatibility.
7299 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
7310 if (flags & PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT) {
7311 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'n', PM_ENCODING_ASCII_8BIT_ENTRY);
7314 if (flags & PM_REGULAR_EXPRESSION_FLAGS_UTF_8) {
7315 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'u', PM_ENCODING_UTF_8_ENTRY);
7318 if (flags & PM_REGULAR_EXPRESSION_FLAGS_EUC_JP) {
7319 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'e', PM_ENCODING_EUC_JP_ENTRY);
7322 if (flags & PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J) {
7323 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 's', PM_ENCODING_WINDOWS_31J_ENTRY);
7326 // At this point no encoding modifiers will be present on the regular expression as they would have already
7327 // been processed. Ruby stipulates that all source files must use an ASCII-compatible encoding. Thus, all
7328 // regular expressions without an encoding modifier appearing in source are eligible for "downgrading" to US-ASCII.
7330 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING;
7333 // A Regexp may optionally have its encoding explicitly set via a character escape sequence in the source string
7334 // or by specifying a modifier.
7336 // NB: an explicitly set encoding is ignored by Ruby if the Regexp consists of only US ASCII code points.
7337 if (parser->explicit_encoding != NULL) {
7338 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7339 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING;
7340 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7341 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING;
7352static pm_symbol_node_t *
7353pm_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) {
7354 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7356 *node = (pm_symbol_node_t) {
7358 .type = PM_SYMBOL_NODE,
7359 .flags = PM_NODE_FLAG_STATIC_LITERAL | flags,
7360 .node_id = PM_NODE_IDENTIFY(parser),
7362 .start = (opening->type == PM_TOKEN_NOT_PROVIDED ? value->start : opening->start),
7363 .end = (closing->type == PM_TOKEN_NOT_PROVIDED ? value->end : closing->end)
7366 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7367 .value_loc = PM_LOCATION_TOKEN_VALUE(value),
7368 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7369 .unescaped = *unescaped
7378static inline pm_symbol_node_t *
7379pm_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
7380 return pm_symbol_node_create_unescaped(parser, opening, value, closing, &PM_STRING_EMPTY, 0);
7386static pm_symbol_node_t *
7387pm_symbol_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
7388 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));
7389 parser->current_string = PM_STRING_EMPTY;
7396static pm_symbol_node_t *
7397pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
7398 pm_symbol_node_t *node;
7400 switch (token->type) {
7401 case PM_TOKEN_LABEL: {
7402 pm_token_t opening = not_provided(parser);
7403 pm_token_t closing = { .type = PM_TOKEN_LABEL_END, .start = token->end - 1, .end = token->end };
7405 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end - 1 };
7406 node = pm_symbol_node_create(parser, &opening, &label, &closing);
7408 assert((label.end - label.start) >= 0);
7409 pm_string_shared_init(&node->unescaped, label.start, label.end);
7410 pm_node_flag_set((pm_node_t *) node, parse_symbol_encoding(parser, &label, &node->unescaped, false));
7414 case PM_TOKEN_MISSING: {
7415 pm_token_t opening = not_provided(parser);
7416 pm_token_t closing = not_provided(parser);
7418 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end };
7419 node = pm_symbol_node_create(parser, &opening, &label, &closing);
7423 assert(false && "unreachable");
7434static pm_symbol_node_t *
7435pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
7436 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7438 *node = (pm_symbol_node_t) {
7440 .type = PM_SYMBOL_NODE,
7441 .flags = PM_NODE_FLAG_STATIC_LITERAL | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING,
7442 .node_id = PM_NODE_IDENTIFY(parser),
7443 .location = PM_LOCATION_NULL_VALUE(parser)
7445 .value_loc = PM_LOCATION_NULL_VALUE(parser),
7449 pm_string_constant_init(&node->unescaped, content, strlen(content));
7457pm_symbol_node_label_p(pm_node_t *node) {
7458 const uint8_t *end = NULL;
7460 switch (PM_NODE_TYPE(node)) {
7461 case PM_SYMBOL_NODE:
7462 end = ((pm_symbol_node_t *) node)->closing_loc.end;
7464 case PM_INTERPOLATED_SYMBOL_NODE:
7465 end = ((pm_interpolated_symbol_node_t *) node)->closing_loc.end;
7471 return (end != NULL) && (end[-1] == ':');
7477static pm_symbol_node_t *
7478pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const pm_token_t *opening, const pm_token_t *closing) {
7479 pm_symbol_node_t *new_node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7481 *new_node = (pm_symbol_node_t) {
7483 .type = PM_SYMBOL_NODE,
7484 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7485 .node_id = PM_NODE_IDENTIFY(parser),
7487 .start = opening->start,
7491 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7492 .value_loc = node->content_loc,
7493 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7494 .unescaped = node->unescaped
7497 pm_token_t content = { .type = PM_TOKEN_IDENTIFIER, .start = node->content_loc.start, .end = node->content_loc.end };
7498 pm_node_flag_set((pm_node_t *) new_node, parse_symbol_encoding(parser, &content, &node->unescaped, true));
7500 // We are explicitly _not_ using pm_node_destroy here because we don't want
7501 // to trash the unescaped string. We could instead copy the string if we
7502 // know that it is owned, but we're taking the fast path for now.
7511static pm_string_node_t *
7512pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
7513 pm_string_node_t *new_node = PM_NODE_ALLOC(parser, pm_string_node_t);
7514 pm_node_flags_t flags = 0;
7516 switch (parser->frozen_string_literal) {
7517 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
7518 flags = PM_STRING_FLAGS_MUTABLE;
7520 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
7521 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
7525 *new_node = (pm_string_node_t) {
7527 .type = PM_STRING_NODE,
7529 .node_id = PM_NODE_IDENTIFY(parser),
7530 .location = node->base.location
7532 .opening_loc = node->opening_loc,
7533 .content_loc = node->value_loc,
7534 .closing_loc = node->closing_loc,
7535 .unescaped = node->unescaped
7538 // We are explicitly _not_ using pm_node_destroy here because we don't want
7539 // to trash the unescaped string. We could instead copy the string if we
7540 // know that it is owned, but we're taking the fast path for now.
7549static pm_true_node_t *
7550pm_true_node_create(pm_parser_t *parser, const pm_token_t *token) {
7551 assert(token->type == PM_TOKEN_KEYWORD_TRUE);
7552 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
7554 *node = (pm_true_node_t) {{
7555 .type = PM_TRUE_NODE,
7556 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7557 .node_id = PM_NODE_IDENTIFY(parser),
7558 .location = PM_LOCATION_TOKEN_VALUE(token)
7567static pm_true_node_t *
7568pm_true_node_synthesized_create(pm_parser_t *parser) {
7569 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
7571 *node = (pm_true_node_t) {{
7572 .type = PM_TRUE_NODE,
7573 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7574 .node_id = PM_NODE_IDENTIFY(parser),
7575 .location = { .start = parser->start, .end = parser->end }
7584static pm_undef_node_t *
7585pm_undef_node_create(pm_parser_t *parser, const pm_token_t *token) {
7586 assert(token->type == PM_TOKEN_KEYWORD_UNDEF);
7587 pm_undef_node_t *node = PM_NODE_ALLOC(parser, pm_undef_node_t);
7589 *node = (pm_undef_node_t) {
7591 .type = PM_UNDEF_NODE,
7592 .node_id = PM_NODE_IDENTIFY(parser),
7593 .location = PM_LOCATION_TOKEN_VALUE(token),
7595 .keyword_loc = PM_LOCATION_TOKEN_VALUE(token),
7606pm_undef_node_append(pm_undef_node_t *node, pm_node_t *name) {
7607 node->base.location.end = name->location.end;
7608 pm_node_list_append(&node->names, name);
7614static pm_unless_node_t *
7615pm_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) {
7616 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7617 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
7620 if (statements != NULL) {
7621 end = statements->base.location.end;
7623 end = predicate->location.end;
7626 *node = (pm_unless_node_t) {
7628 .type = PM_UNLESS_NODE,
7629 .flags = PM_NODE_FLAG_NEWLINE,
7630 .node_id = PM_NODE_IDENTIFY(parser),
7632 .start = keyword->start,
7636 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7637 .predicate = predicate,
7638 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
7639 .statements = statements,
7640 .else_clause = NULL,
7641 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
7650static pm_unless_node_t *
7651pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *unless_keyword, pm_node_t *predicate) {
7652 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7653 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
7655 pm_statements_node_t *statements = pm_statements_node_create(parser);
7656 pm_statements_node_body_append(parser, statements, statement, true);
7658 *node = (pm_unless_node_t) {
7660 .type = PM_UNLESS_NODE,
7661 .flags = PM_NODE_FLAG_NEWLINE,
7662 .node_id = PM_NODE_IDENTIFY(parser),
7664 .start = statement->location.start,
7665 .end = predicate->location.end
7668 .keyword_loc = PM_LOCATION_TOKEN_VALUE(unless_keyword),
7669 .predicate = predicate,
7670 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7671 .statements = statements,
7672 .else_clause = NULL,
7673 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
7680pm_unless_node_end_keyword_loc_set(pm_unless_node_t *node, const pm_token_t *end_keyword) {
7681 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
7682 node->base.location.end = end_keyword->end;
7691pm_loop_modifier_block_exits(pm_parser_t *parser, pm_statements_node_t *statements) {
7692 assert(parser->current_block_exits != NULL);
7694 // All of the block exits that we want to remove should be within the
7695 // statements, and since we are modifying the statements, we shouldn't have
7696 // to check the end location.
7697 const uint8_t *start = statements->base.location.start;
7699 for (size_t index = parser->current_block_exits->size; index > 0; index--) {
7700 pm_node_t *block_exit = parser->current_block_exits->nodes[index - 1];
7701 if (block_exit->location.start < start) break;
7703 // Implicitly remove from the list by lowering the size.
7704 parser->current_block_exits->size--;
7711static pm_until_node_t *
7712pm_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) {
7713 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
7714 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7716 *node = (pm_until_node_t) {
7718 .type = PM_UNTIL_NODE,
7720 .node_id = PM_NODE_IDENTIFY(parser),
7722 .start = keyword->start,
7723 .end = closing->end,
7726 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7727 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
7728 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7729 .predicate = predicate,
7730 .statements = statements
7739static pm_until_node_t *
7740pm_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) {
7741 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
7742 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7743 pm_loop_modifier_block_exits(parser, statements);
7745 *node = (pm_until_node_t) {
7747 .type = PM_UNTIL_NODE,
7749 .node_id = PM_NODE_IDENTIFY(parser),
7751 .start = statements->base.location.start,
7752 .end = predicate->location.end,
7755 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7756 .do_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7757 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7758 .predicate = predicate,
7759 .statements = statements
7768static pm_when_node_t *
7769pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
7770 pm_when_node_t *node = PM_NODE_ALLOC(parser, pm_when_node_t);
7772 *node = (pm_when_node_t) {
7774 .type = PM_WHEN_NODE,
7775 .node_id = PM_NODE_IDENTIFY(parser),
7777 .start = keyword->start,
7781 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7783 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7794pm_when_node_conditions_append(pm_when_node_t *node, pm_node_t *condition) {
7795 node->base.location.end = condition->location.end;
7796 pm_node_list_append(&node->conditions, condition);
7803pm_when_node_then_keyword_loc_set(pm_when_node_t *node, const pm_token_t *then_keyword) {
7804 node->base.location.end = then_keyword->end;
7805 node->then_keyword_loc = PM_LOCATION_TOKEN_VALUE(then_keyword);
7812pm_when_node_statements_set(pm_when_node_t *node, pm_statements_node_t *statements) {
7813 if (statements->base.location.end > node->base.location.end) {
7814 node->base.location.end = statements->base.location.end;
7817 node->statements = statements;
7823static pm_while_node_t *
7824pm_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) {
7825 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7826 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7828 *node = (pm_while_node_t) {
7830 .type = PM_WHILE_NODE,
7832 .node_id = PM_NODE_IDENTIFY(parser),
7834 .start = keyword->start,
7838 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7839 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
7840 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7841 .predicate = predicate,
7842 .statements = statements
7851static pm_while_node_t *
7852pm_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) {
7853 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7854 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7855 pm_loop_modifier_block_exits(parser, statements);
7857 *node = (pm_while_node_t) {
7859 .type = PM_WHILE_NODE,
7861 .node_id = PM_NODE_IDENTIFY(parser),
7863 .start = statements->base.location.start,
7864 .end = predicate->location.end
7867 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7868 .do_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7869 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7870 .predicate = predicate,
7871 .statements = statements
7880static pm_while_node_t *
7881pm_while_node_synthesized_create(pm_parser_t *parser, pm_node_t *predicate, pm_statements_node_t *statements) {
7882 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7884 *node = (pm_while_node_t) {
7886 .type = PM_WHILE_NODE,
7887 .node_id = PM_NODE_IDENTIFY(parser),
7888 .location = PM_LOCATION_NULL_VALUE(parser)
7890 .keyword_loc = PM_LOCATION_NULL_VALUE(parser),
7891 .do_keyword_loc = PM_LOCATION_NULL_VALUE(parser),
7892 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
7893 .predicate = predicate,
7894 .statements = statements
7904static pm_x_string_node_t *
7905pm_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) {
7906 pm_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_x_string_node_t);
7908 *node = (pm_x_string_node_t) {
7910 .type = PM_X_STRING_NODE,
7911 .flags = PM_STRING_FLAGS_FROZEN,
7912 .node_id = PM_NODE_IDENTIFY(parser),
7914 .start = opening->start,
7918 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
7919 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
7920 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
7921 .unescaped = *unescaped
7930static inline pm_x_string_node_t *
7931pm_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7932 return pm_xstring_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7938static pm_yield_node_t *
7939pm_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) {
7940 pm_yield_node_t *node = PM_NODE_ALLOC(parser, pm_yield_node_t);
7943 if (rparen_loc->start != NULL) {
7944 end = rparen_loc->end;
7945 } else if (arguments != NULL) {
7946 end = arguments->base.location.end;
7947 } else if (lparen_loc->start != NULL) {
7948 end = lparen_loc->end;
7953 *node = (pm_yield_node_t) {
7955 .type = PM_YIELD_NODE,
7956 .node_id = PM_NODE_IDENTIFY(parser),
7958 .start = keyword->start,
7962 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7963 .lparen_loc = *lparen_loc,
7964 .arguments = arguments,
7965 .rparen_loc = *rparen_loc
7972#undef PM_NODE_IDENTIFY
7979pm_parser_local_depth_constant_id(pm_parser_t *parser, pm_constant_id_t constant_id) {
7980 pm_scope_t *scope = parser->current_scope;
7983 while (scope != NULL) {
7984 if (pm_locals_find(&scope->locals, constant_id) != UINT32_MAX) return depth;
7985 if (scope->closed) break;
7987 scope = scope->previous;
8000pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
8001 return pm_parser_local_depth_constant_id(parser, pm_parser_constant_id_token(parser, token));
8008pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id, const uint8_t *start, const uint8_t *end, uint32_t reads) {
8009 pm_locals_write(&parser->current_scope->locals, constant_id, start, end, reads);
8015static pm_constant_id_t
8016pm_parser_local_add_location(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, uint32_t reads) {
8017 pm_constant_id_t constant_id = pm_parser_constant_id_location(parser, start, end);
8018 if (constant_id != 0) pm_parser_local_add(parser, constant_id, start, end, reads);
8025static inline pm_constant_id_t
8026pm_parser_local_add_token(pm_parser_t *parser, pm_token_t *token, uint32_t reads) {
8027 return pm_parser_local_add_location(parser, token->start, token->end, reads);
8033static pm_constant_id_t
8034pm_parser_local_add_owned(pm_parser_t *parser, uint8_t *start, size_t length) {
8035 pm_constant_id_t constant_id = pm_parser_constant_id_owned(parser, start, length);
8036 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
8043static pm_constant_id_t
8044pm_parser_local_add_constant(pm_parser_t *parser, const char *start, size_t length) {
8045 pm_constant_id_t constant_id = pm_parser_constant_id_constant(parser, start, length);
8046 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
8058pm_parser_parameter_name_check(pm_parser_t *parser, const pm_token_t *name) {
8059 // We want to check whether the parameter name is a numbered parameter or
8061 pm_refute_numbered_parameter(parser, name->start, name->end);
8063 // Otherwise we'll fetch the constant id for the parameter name and check
8064 // whether it's already in the current scope.
8065 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, name);
8067 if (pm_locals_find(&parser->current_scope->locals, constant_id) != UINT32_MAX) {
8068 // Add an error if the parameter doesn't start with _ and has been seen before
8069 if ((name->start < name->end) && (*name->start != '_')) {
8070 pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NAME_DUPLICATED);
8081pm_parser_scope_pop(pm_parser_t *parser) {
8082 pm_scope_t *scope = parser->current_scope;
8083 parser->current_scope = scope->previous;
8084 pm_locals_free(&scope->locals);
8085 pm_node_list_free(&scope->implicit_parameters);
8089/******************************************************************************/
8091/******************************************************************************/
8097pm_state_stack_push(pm_state_stack_t *stack, bool value) {
8098 *stack = (*stack << 1) | (value & 1);
8105pm_state_stack_pop(pm_state_stack_t *stack) {
8113pm_state_stack_p(const pm_state_stack_t *stack) {
8118pm_accepts_block_stack_push(pm_parser_t *parser, bool value) {
8119 // Use the negation of the value to prevent stack overflow.
8120 pm_state_stack_push(&parser->accepts_block_stack, !value);
8124pm_accepts_block_stack_pop(pm_parser_t *parser) {
8125 pm_state_stack_pop(&parser->accepts_block_stack);
8129pm_accepts_block_stack_p(pm_parser_t *parser) {
8130 return !pm_state_stack_p(&parser->accepts_block_stack);
8134pm_do_loop_stack_push(pm_parser_t *parser, bool value) {
8135 pm_state_stack_push(&parser->do_loop_stack, value);
8139pm_do_loop_stack_pop(pm_parser_t *parser) {
8140 pm_state_stack_pop(&parser->do_loop_stack);
8144pm_do_loop_stack_p(pm_parser_t *parser) {
8145 return pm_state_stack_p(&parser->do_loop_stack);
8148/******************************************************************************/
8149/* Lexer check helpers */
8150/******************************************************************************/
8156static inline uint8_t
8157peek_at(const pm_parser_t *parser, const uint8_t *cursor) {
8158 if (cursor < parser->end) {
8170static inline uint8_t
8171peek_offset(pm_parser_t *parser, ptrdiff_t offset) {
8172 return peek_at(parser, parser->current.end + offset);
8179static inline uint8_t
8180peek(const pm_parser_t *parser) {
8181 return peek_at(parser, parser->current.end);
8189match(pm_parser_t *parser, uint8_t value) {
8190 if (peek(parser) == value) {
8191 parser->current.end++;
8202match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
8203 if (peek_at(parser, cursor) == '\n') {
8206 if (peek_at(parser, cursor) == '\r' && peek_at(parser, cursor + 1) == '\n') {
8218match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
8219 return match_eol_at(parser, parser->current.end + offset);
8228match_eol(pm_parser_t *parser) {
8229 return match_eol_at(parser, parser->current.end);
8235static inline const uint8_t *
8236next_newline(const uint8_t *cursor, ptrdiff_t length) {
8237 assert(length >= 0);
8239 // Note that it's okay for us to use memchr here to look for \n because none
8240 // of the encodings that we support have \n as a component of a multi-byte
8242 return memchr(cursor, '\n', (size_t) length);
8249ambiguous_operator_p(const pm_parser_t *parser, bool space_seen) {
8250 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));
8258parser_lex_magic_comment_encoding_value(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
8259 const pm_encoding_t *encoding = pm_encoding_find(start, end);
8261 if (encoding != NULL) {
8262 if (parser->encoding != encoding) {
8263 parser->encoding = encoding;
8264 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
8267 parser->encoding_changed = (encoding != PM_ENCODING_UTF_8_ENTRY);
8279parser_lex_magic_comment_encoding(pm_parser_t *parser) {
8280 const uint8_t *cursor = parser->current.start + 1;
8281 const uint8_t *end = parser->current.end;
8283 bool separator = false;
8285 if (end - cursor <= 6) return;
8286 switch (cursor[6]) {
8287 case 'C': case 'c': cursor += 6; continue;
8288 case 'O': case 'o': cursor += 5; continue;
8289 case 'D': case 'd': cursor += 4; continue;
8290 case 'I': case 'i': cursor += 3; continue;
8291 case 'N': case 'n': cursor += 2; continue;
8292 case 'G': case 'g': cursor += 1; continue;
8299 if (pm_char_is_whitespace(*cursor)) break;
8302 if (pm_strncasecmp(cursor - 6, (const uint8_t *) "coding", 6) == 0) break;
8308 if (++cursor >= end) return;
8309 } while (pm_char_is_whitespace(*cursor));
8311 if (separator) break;
8312 if (*cursor != '=' && *cursor != ':') return;
8318 const uint8_t *value_start = cursor;
8319 while ((*cursor == '-' || *cursor == '_' || parser->encoding->alnum_char(cursor, 1)) && ++cursor < end);
8321 if (!parser_lex_magic_comment_encoding_value(parser, value_start, cursor)) {
8322 // If we were unable to parse the encoding value, then we've got an
8323 // issue because we didn't understand the encoding that the user was
8324 // trying to use. In this case we'll keep using the default encoding but
8325 // add an error to the parser to indicate an unsuccessful parse.
8326 pm_parser_err(parser, value_start, cursor, PM_ERR_INVALID_ENCODING_MAGIC_COMMENT);
8331 PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE,
8332 PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE,
8333 PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID
8334} pm_magic_comment_boolean_value_t;
8340static pm_magic_comment_boolean_value_t
8341parser_lex_magic_comment_boolean_value(const uint8_t *value_start, uint32_t value_length) {
8342 if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "true", 4) == 0) {
8343 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE;
8344 } else if (value_length == 5 && pm_strncasecmp(value_start, (const uint8_t *) "false", 5) == 0) {
8345 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE;
8347 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID;
8352pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
8353 return b == '\'' || b == '"' || b == ':' || b == ';';
8361static inline const uint8_t *
8362parser_lex_magic_comment_emacs_marker(
pm_parser_t *parser,
const uint8_t *cursor,
const uint8_t *end) {
8363 while ((cursor + 3 <= end) && (cursor = pm_memchr(cursor,
'-', (
size_t) (end - cursor), parser->
encoding_changed, parser->
encoding)) != NULL) {
8364 if (cursor + 3 <= end && cursor[1] ==
'*' && cursor[2] ==
'-') {
8383parser_lex_magic_comment(
pm_parser_t *parser,
bool semantic_token_seen) {
8386 const uint8_t *start = parser->
current.start + 1;
8387 const uint8_t *end = parser->
current.end;
8388 if (end - start <= 7)
return false;
8390 const uint8_t *cursor;
8391 bool indicator =
false;
8393 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
8396 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
8407 while (cursor < end) {
8408 while (cursor < end && (pm_char_is_magic_comment_key_delimiter(*cursor) || pm_char_is_whitespace(*cursor))) cursor++;
8410 const uint8_t *key_start = cursor;
8411 while (cursor < end && (!pm_char_is_magic_comment_key_delimiter(*cursor) && !pm_char_is_whitespace(*cursor))) cursor++;
8413 const uint8_t *key_end = cursor;
8414 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
8415 if (cursor == end)
break;
8417 if (*cursor ==
':') {
8420 if (!indicator)
return false;
8424 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
8425 if (cursor == end)
break;
8427 const uint8_t *value_start;
8428 const uint8_t *value_end;
8430 if (*cursor ==
'"') {
8431 value_start = ++cursor;
8432 for (; cursor < end && *cursor !=
'"'; cursor++) {
8433 if (*cursor ==
'\\' && (cursor + 1 < end)) cursor++;
8436 if (*cursor ==
'"') cursor++;
8438 value_start = cursor;
8439 while (cursor < end && *cursor !=
'"' && *cursor !=
';' && !pm_char_is_whitespace(*cursor)) cursor++;
8444 while (cursor < end && (*cursor ==
';' || pm_char_is_whitespace(*cursor))) cursor++;
8446 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
8447 if (cursor != end)
return false;
8453 const size_t key_length = (size_t) (key_end - key_start);
8457 pm_string_shared_init(&key, key_start, key_end);
8459 uint8_t *buffer =
xmalloc(key_length);
8460 if (buffer == NULL)
break;
8462 memcpy(buffer, key_start, key_length);
8463 buffer[dash - key_start] =
'_';
8465 while ((dash = pm_memchr(dash + 1,
'-', (
size_t) (key_end - dash - 1), parser->
encoding_changed, parser->
encoding)) != NULL) {
8466 buffer[dash - key_start] =
'_';
8469 pm_string_owned_init(&key, buffer, key_length);
8474 const uint8_t *key_source = pm_string_source(&key);
8475 uint32_t value_length = (uint32_t) (value_end - value_start);
8481 (key_length == 8 && pm_strncasecmp(key_source, (
const uint8_t *)
"encoding", 8) == 0) ||
8482 (key_length == 6 && pm_strncasecmp(key_source, (
const uint8_t *)
"coding", 6) == 0)
8484 result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
8488 if (key_length == 11) {
8489 if (pm_strncasecmp(key_source, (
const uint8_t *)
"warn_indent", 11) == 0) {
8490 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
8491 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
8492 PM_PARSER_WARN_TOKEN_FORMAT(
8495 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8497 (
const char *) key_source,
8499 (
const char *) value_start
8502 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
8505 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
8510 }
else if (key_length == 21) {
8511 if (pm_strncasecmp(key_source, (
const uint8_t *)
"frozen_string_literal", 21) == 0) {
8514 if (semantic_token_seen) {
8515 pm_parser_warn_token(parser, &parser->
current, PM_WARN_IGNORED_FROZEN_STRING_LITERAL);
8517 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
8518 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
8519 PM_PARSER_WARN_TOKEN_FORMAT(
8522 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8524 (
const char *) key_source,
8526 (
const char *) value_start
8529 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
8532 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
8538 }
else if (key_length == 24) {
8539 if (pm_strncasecmp(key_source, (
const uint8_t *)
"shareable_constant_value", 24) == 0) {
8540 const uint8_t *cursor = parser->
current.start;
8541 while ((cursor > parser->
start) && ((cursor[-1] ==
' ') || (cursor[-1] ==
'\t'))) cursor--;
8543 if (!((cursor == parser->
start) || (cursor[-1] ==
'\n'))) {
8544 pm_parser_warn_token(parser, &parser->
current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
8545 }
else if (value_length == 4 && pm_strncasecmp(value_start, (
const uint8_t *)
"none", 4) == 0) {
8546 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
8547 }
else if (value_length == 7 && pm_strncasecmp(value_start, (
const uint8_t *)
"literal", 7) == 0) {
8548 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
8549 }
else if (value_length == 23 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_everything", 23) == 0) {
8550 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING);
8551 }
else if (value_length == 17 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_copy", 17) == 0) {
8552 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY);
8554 PM_PARSER_WARN_TOKEN_FORMAT(
8557 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8559 (
const char *) key_source,
8561 (
const char *) value_start
8569 pm_string_free(&key);
8589static const uint32_t context_terminators[] = {
8591 [
PM_CONTEXT_BEGIN] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8594 [
PM_CONTEXT_BEGIN_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8596 [
PM_CONTEXT_BLOCK_KEYWORDS] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
8599 [
PM_CONTEXT_BLOCK_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8600 [
PM_CONTEXT_CASE_WHEN] = (1 << PM_TOKEN_KEYWORD_WHEN) | (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_ELSE),
8601 [
PM_CONTEXT_CASE_IN] = (1 << PM_TOKEN_KEYWORD_IN) | (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_ELSE),
8602 [
PM_CONTEXT_CLASS] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
8605 [
PM_CONTEXT_CLASS_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8606 [
PM_CONTEXT_DEF] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
8609 [
PM_CONTEXT_DEF_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8614 [
PM_CONTEXT_ELSIF] = (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_ELSIF) | (1 << PM_TOKEN_KEYWORD_END),
8618 [
PM_CONTEXT_IF] = (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_ELSIF) | (1 << PM_TOKEN_KEYWORD_END),
8620 [
PM_CONTEXT_LAMBDA_DO_END] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
8623 [
PM_CONTEXT_LAMBDA_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8626 [
PM_CONTEXT_MODULE] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
8629 [
PM_CONTEXT_MODULE_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8633 [
PM_CONTEXT_PREDICATE] = (1 << PM_TOKEN_KEYWORD_THEN) | (1 << PM_TOKEN_NEWLINE) | (1 << PM_TOKEN_SEMICOLON),
8636 [
PM_CONTEXT_SCLASS] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
8639 [
PM_CONTEXT_SCLASS_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8641 [
PM_CONTEXT_UNLESS] = (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8648 return token->type < 32 && (context_terminators[context] & (1 << token->type));
8659 while (context_node != NULL) {
8660 if (context_terminator(context_node->
context, token))
return context_node->
context;
8661 context_node = context_node->
prev;
8670 if (context_node == NULL)
return false;
8695 while (context_node != NULL) {
8696 if (context_node->
context == context)
return true;
8697 context_node = context_node->
prev;
8707 while (context_node != NULL) {
8708 switch (context_node->
context) {
8729 context_node = context_node->
prev;
8744 assert(
false &&
"unreachable");
8801 assert(
false &&
"unreachable");
8810pm_strspn_number_validate(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const uint8_t *invalid) {
8811 if (invalid != NULL) {
8812 pm_diagnostic_id_t diag_id = (invalid == (
string + length - 1)) ? PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING : PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER;
8813 pm_parser_err(parser, invalid, invalid + 1, diag_id);
8818pm_strspn_binary_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8819 const uint8_t *invalid = NULL;
8820 size_t length = pm_strspn_binary_number(
string, parser->
end -
string, &invalid);
8821 pm_strspn_number_validate(parser,
string, length, invalid);
8826pm_strspn_octal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8827 const uint8_t *invalid = NULL;
8828 size_t length = pm_strspn_octal_number(
string, parser->
end -
string, &invalid);
8829 pm_strspn_number_validate(parser,
string, length, invalid);
8834pm_strspn_decimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8835 const uint8_t *invalid = NULL;
8836 size_t length = pm_strspn_decimal_number(
string, parser->
end -
string, &invalid);
8837 pm_strspn_number_validate(parser,
string, length, invalid);
8842pm_strspn_hexadecimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8843 const uint8_t *invalid = NULL;
8844 size_t length = pm_strspn_hexadecimal_number(
string, parser->
end -
string, &invalid);
8845 pm_strspn_number_validate(parser,
string, length, invalid);
8849static pm_token_type_t
8850lex_optional_float_suffix(
pm_parser_t *parser,
bool* seen_e) {
8851 pm_token_type_t
type = PM_TOKEN_INTEGER;
8855 if (peek(parser) ==
'.') {
8856 if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8858 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8859 type = PM_TOKEN_FLOAT;
8869 if ((peek(parser) ==
'e') || (peek(parser) ==
'E')) {
8870 if ((peek_offset(parser, 1) ==
'+') || (peek_offset(parser, 1) ==
'-')) {
8873 if (pm_char_is_decimal_digit(peek(parser))) {
8875 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8877 pm_parser_err_current(parser, PM_ERR_INVALID_FLOAT_EXPONENT);
8879 }
else if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8881 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8887 type = PM_TOKEN_FLOAT;
8893static pm_token_type_t
8894lex_numeric_prefix(
pm_parser_t *parser,
bool* seen_e) {
8895 pm_token_type_t
type = PM_TOKEN_INTEGER;
8898 if (peek_offset(parser, -1) ==
'0') {
8899 switch (*parser->
current.end) {
8904 if (pm_char_is_decimal_digit(peek(parser))) {
8905 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8908 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_DECIMAL);
8917 if (pm_char_is_binary_digit(peek(parser))) {
8918 parser->
current.end += pm_strspn_binary_number_validate(parser, parser->
current.end);
8921 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
8931 if (pm_char_is_octal_digit(peek(parser))) {
8932 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8935 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
8951 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8959 if (pm_char_is_hexadecimal_digit(peek(parser))) {
8960 parser->
current.end += pm_strspn_hexadecimal_number_validate(parser, parser->
current.end);
8963 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
8966 parser->
integer_base = PM_INTEGER_BASE_FLAGS_HEXADECIMAL;
8971 type = lex_optional_float_suffix(parser, seen_e);
8978 type = lex_optional_float_suffix(parser, seen_e);
8985 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8988 type = lex_optional_float_suffix(parser, seen_e);
8994 if (peek_offset(parser, 0) ==
'.' && pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8995 const uint8_t *fraction_start = parser->
current.end;
8996 const uint8_t *fraction_end = parser->
current.end + 2;
8997 fraction_end += pm_strspn_decimal_digit(fraction_end, parser->
end - fraction_end);
8998 pm_parser_err(parser, fraction_start, fraction_end, PM_ERR_INVALID_NUMBER_FRACTION);
9004static pm_token_type_t
9006 pm_token_type_t
type = PM_TOKEN_INTEGER;
9010 bool seen_e =
false;
9011 type = lex_numeric_prefix(parser, &seen_e);
9013 const uint8_t *end = parser->
current.end;
9014 pm_token_type_t suffix_type =
type;
9016 if (
type == PM_TOKEN_INTEGER) {
9017 if (match(parser,
'r')) {
9018 suffix_type = PM_TOKEN_INTEGER_RATIONAL;
9020 if (match(parser,
'i')) {
9021 suffix_type = PM_TOKEN_INTEGER_RATIONAL_IMAGINARY;
9023 }
else if (match(parser,
'i')) {
9024 suffix_type = PM_TOKEN_INTEGER_IMAGINARY;
9027 if (!seen_e && match(parser,
'r')) {
9028 suffix_type = PM_TOKEN_FLOAT_RATIONAL;
9030 if (match(parser,
'i')) {
9031 suffix_type = PM_TOKEN_FLOAT_RATIONAL_IMAGINARY;
9033 }
else if (match(parser,
'i')) {
9034 suffix_type = PM_TOKEN_FLOAT_IMAGINARY;
9038 const uint8_t b = peek(parser);
9039 if (b !=
'\0' && (b >= 0x80 || ((b >=
'a' && b <=
'z') || (b >=
'A' && b <=
'Z')) || b ==
'_')) {
9049static pm_token_type_t
9052 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
9053 return PM_TOKEN_GLOBAL_VARIABLE;
9058 bool allow_multiple =
true;
9060 switch (*parser->
current.end) {
9078 return PM_TOKEN_GLOBAL_VARIABLE;
9085 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_BACK_REFERENCE;
9091 if ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0) {
9094 }
while ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0);
9098 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
current, diag_id);
9101 return PM_TOKEN_GLOBAL_VARIABLE;
9114 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_NUMBERED_REFERENCE;
9118 allow_multiple =
false;
9123 if ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0) {
9126 }
while (allow_multiple && (width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0);
9127 }
else if (pm_char_is_whitespace(peek(parser))) {
9130 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
9136 PM_PARSER_ERR_FORMAT(parser, parser->
current.start, end, diag_id, (
int) (end - parser->
current.start), (
const char *) parser->
current.start);
9139 return PM_TOKEN_GLOBAL_VARIABLE;
9156static inline pm_token_type_t
9157lex_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) {
9158 if (memcmp(current_start, value, vlen) == 0) {
9161 if (parser->
lex_state & PM_LEX_STATE_FNAME) {
9162 lex_state_set(parser, PM_LEX_STATE_ENDFN);
9164 lex_state_set(parser, state);
9165 if (state == PM_LEX_STATE_BEG) {
9169 if ((modifier_type != PM_TOKEN_EOF) && !(last_state & (PM_LEX_STATE_BEG | PM_LEX_STATE_LABELED | PM_LEX_STATE_CLASS))) {
9170 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
9171 return modifier_type;
9178 return PM_TOKEN_EOF;
9181static pm_token_type_t
9182lex_identifier(
pm_parser_t *parser,
bool previous_command_start) {
9185 const uint8_t *end = parser->
end;
9186 const uint8_t *current_start = parser->
current.start;
9187 const uint8_t *current_end = parser->
current.end;
9190 if (encoding_changed) {
9191 while ((width = char_is_identifier(parser, current_end, end - current_end)) > 0) {
9192 current_end += width;
9195 while ((width = char_is_identifier_utf8(current_end, end - current_end)) > 0) {
9196 current_end += width;
9199 parser->
current.end = current_end;
9203 width = (size_t) (current_end - current_start);
9205 if (current_end < end) {
9206 if (((current_end + 1 >= end) || (current_end[1] !=
'=')) && (match(parser,
'!') || match(parser,
'?'))) {
9212 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
9213 (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')
9217 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
9218 (void) match(parser,
':');
9219 return PM_TOKEN_LABEL;
9222 if (parser->
lex_state != PM_LEX_STATE_DOT) {
9223 if (width == 8 && (lex_keyword(parser, current_start,
"defined?", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_DEFINED, PM_TOKEN_EOF) != PM_TOKEN_EOF)) {
9224 return PM_TOKEN_KEYWORD_DEFINED;
9228 return PM_TOKEN_METHOD_NAME;
9231 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,
'=')) {
9234 return PM_TOKEN_IDENTIFIER;
9238 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
9239 peek(parser) ==
':' && peek_offset(parser, 1) !=
':'
9243 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
9244 (void) match(parser,
':');
9245 return PM_TOKEN_LABEL;
9249 if (parser->
lex_state != PM_LEX_STATE_DOT) {
9250 pm_token_type_t
type;
9253 if (lex_keyword(parser, current_start,
"do", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_DO, PM_TOKEN_EOF) != PM_TOKEN_EOF) {
9254 if (pm_do_loop_stack_p(parser)) {
9255 return PM_TOKEN_KEYWORD_DO_LOOP;
9257 return PM_TOKEN_KEYWORD_DO;
9260 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;
9261 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;
9262 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;
9265 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;
9266 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;
9267 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;
9268 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;
9269 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;
9270 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;
9271 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;
9274 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;
9275 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;
9276 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;
9277 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;
9278 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;
9279 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;
9280 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;
9281 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;
9284 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;
9285 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;
9286 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;
9287 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;
9288 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;
9289 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;
9290 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;
9291 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;
9292 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;
9293 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;
9294 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;
9295 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;
9296 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;
9299 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;
9300 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;
9301 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;
9302 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;
9303 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;
9306 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;
9307 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;
9310 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;
9315 if (encoding_changed) {
9316 return parser->
encoding->
isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
9318 return pm_encoding_utf_8_isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
9344static pm_token_type_t
9345lex_interpolation(
pm_parser_t *parser,
const uint8_t *pound) {
9348 if (pound + 1 >= parser->
end) {
9349 parser->
current.end = pound + 1;
9350 return PM_TOKEN_STRING_CONTENT;
9359 if (pound + 2 >= parser->
end) {
9360 parser->
current.end = pound + 1;
9361 return PM_TOKEN_STRING_CONTENT;
9366 const uint8_t *variable = pound + 2;
9367 if (*variable ==
'@' && pound + 3 < parser->
end) variable++;
9369 if (char_is_identifier_start(parser, variable, parser->
end - variable)) {
9373 if (pound > parser->
current.start) {
9375 return PM_TOKEN_STRING_CONTENT;
9380 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
9381 parser->
current.end = pound + 1;
9382 return PM_TOKEN_EMBVAR;
9388 parser->
current.end = pound + 1;
9389 return PM_TOKEN_NOT_PROVIDED;
9394 if (pound + 2 >= parser->
end) {
9395 parser->
current.end = pound + 1;
9396 return PM_TOKEN_STRING_CONTENT;
9402 const uint8_t *check = pound + 2;
9404 if (pound[2] ==
'-') {
9405 if (pound + 3 >= parser->
end) {
9406 parser->
current.end = pound + 2;
9407 return PM_TOKEN_STRING_CONTENT;
9418 char_is_identifier_start(parser, check, parser->
end - check) ||
9419 (pound[2] !=
'-' && (pm_char_is_decimal_digit(pound[2]) || char_is_global_name_punctuation(pound[2])))
9424 if (pound > parser->
current.start) {
9426 return PM_TOKEN_STRING_CONTENT;
9431 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
9432 parser->
current.end = pound + 1;
9433 return PM_TOKEN_EMBVAR;
9438 parser->
current.end = pound + 1;
9439 return PM_TOKEN_NOT_PROVIDED;
9444 if (pound > parser->
current.start) {
9446 return PM_TOKEN_STRING_CONTENT;
9453 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBEXPR });
9454 parser->
current.end = pound + 2;
9456 pm_do_loop_stack_push(parser,
false);
9457 return PM_TOKEN_EMBEXPR_BEGIN;
9462 parser->
current.end = pound + 1;
9463 return PM_TOKEN_NOT_PROVIDED;
9467static const uint8_t PM_ESCAPE_FLAG_NONE = 0x0;
9468static const uint8_t PM_ESCAPE_FLAG_CONTROL = 0x1;
9469static const uint8_t PM_ESCAPE_FLAG_META = 0x2;
9470static const uint8_t PM_ESCAPE_FLAG_SINGLE = 0x4;
9471static const uint8_t PM_ESCAPE_FLAG_REGEXP = 0x8;
9476static const bool ascii_printable_chars[] = {
9477 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
9478 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9479 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9480 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9481 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9482 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
9483 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9484 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
9488char_is_ascii_printable(
const uint8_t b) {
9489 return (b < 0x80) && ascii_printable_chars[b];
9496static inline uint8_t
9497escape_hexadecimal_digit(
const uint8_t value) {
9498 return (uint8_t) ((value <=
'9') ? (value -
'0') : (value & 0x7) + 9);
9506static inline uint32_t
9507escape_unicode(
pm_parser_t *parser,
const uint8_t *
string,
size_t length) {
9509 for (
size_t index = 0; index < length; index++) {
9510 if (index != 0) value <<= 4;
9511 value |= escape_hexadecimal_digit(
string[index]);
9516 if (value >= 0xD800 && value <= 0xDFFF) {
9517 pm_parser_err(parser,
string,
string + length, PM_ERR_ESCAPE_INVALID_UNICODE);
9527static inline uint8_t
9528escape_byte(uint8_t value,
const uint8_t flags) {
9529 if (flags & PM_ESCAPE_FLAG_CONTROL) value &= 0x9f;
9530 if (flags & PM_ESCAPE_FLAG_META) value |= 0x80;
9538escape_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) {
9542 if (value >= 0x80 || flags & PM_ESCAPE_FLAG_SINGLE) {
9550 if (!pm_buffer_append_unicode_codepoint(buffer, value)) {
9551 pm_parser_err(parser, start, end, PM_ERR_ESCAPE_INVALID_UNICODE);
9552 pm_buffer_append_byte(buffer, 0xEF);
9553 pm_buffer_append_byte(buffer, 0xBF);
9554 pm_buffer_append_byte(buffer, 0xBD);
9566 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_MIXED_ENCODING, parser->
encoding->
name);
9572 pm_buffer_append_byte(buffer,
byte);
9592 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9593 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X",
byte);
9596 escape_write_byte_encoded(parser, buffer,
byte);
9608 width = pm_encoding_utf_8_char_width(parser->
current.end, parser->
end - parser->
current.end);
9612 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(*parser->
current.end++, flags));
9613 }
else if (width > 1) {
9615 pm_buffer_t *b = (flags & PM_ESCAPE_FLAG_REGEXP) ? regular_expression_buffer : buffer;
9616 pm_buffer_append_bytes(b, parser->
current.end, width);
9622 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9632escape_read_warn(
pm_parser_t *parser, uint8_t flags, uint8_t flag,
const char *
type) {
9633#define FLAG(value) ((value & PM_ESCAPE_FLAG_CONTROL) ? "\\C-" : (value & PM_ESCAPE_FLAG_META) ? "\\M-" : "")
9635 PM_PARSER_WARN_TOKEN_FORMAT(
9638 PM_WARN_INVALID_CHARACTER,
9652 uint8_t peeked = peek(parser);
9656 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\\', flags));
9661 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\'', flags));
9666 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\a', flags));
9671 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\b', flags));
9676 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\033', flags));
9681 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\f', flags));
9686 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\n', flags));
9691 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\r', flags));
9696 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
' ', flags));
9701 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\t', flags));
9706 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\v', flags));
9709 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': {
9710 uint8_t value = (uint8_t) (*parser->
current.end -
'0');
9713 if (pm_char_is_octal_digit(peek(parser))) {
9714 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
9717 if (pm_char_is_octal_digit(peek(parser))) {
9718 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
9723 value = escape_byte(value, flags);
9724 escape_write_byte(parser, buffer, regular_expression_buffer, flags, value);
9728 const uint8_t *start = parser->
current.end - 1;
9731 uint8_t
byte = peek(parser);
9733 if (pm_char_is_hexadecimal_digit(
byte)) {
9734 uint8_t value = escape_hexadecimal_digit(
byte);
9737 byte = peek(parser);
9738 if (pm_char_is_hexadecimal_digit(
byte)) {
9739 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(
byte));
9743 value = escape_byte(value, flags);
9744 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9745 if (flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) {
9746 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X", value);
9748 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9752 escape_write_byte_encoded(parser, buffer, value);
9754 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
9760 const uint8_t *start = parser->
current.end - 1;
9764 const uint8_t *start = parser->
current.end - 2;
9765 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9766 }
else if (peek(parser) ==
'{') {
9767 const uint8_t *unicode_codepoints_start = parser->
current.end - 2;
9772 if ((whitespace = pm_strspn_inline_whitespace(parser->
current.end, parser->
end - parser->
current.end)) > 0) {
9773 parser->
current.end += whitespace;
9774 }
else if (peek(parser) ==
'\\' && peek_offset(parser, 1) ==
'n') {
9785 const uint8_t *extra_codepoints_start = NULL;
9786 int codepoints_count = 0;
9789 const uint8_t *unicode_start = parser->
current.end;
9790 size_t hexadecimal_length = pm_strspn_hexadecimal_digit(parser->
current.end, parser->
end - parser->
current.end);
9792 if (hexadecimal_length > 6) {
9794 pm_parser_err(parser, unicode_start, unicode_start + hexadecimal_length, PM_ERR_ESCAPE_INVALID_UNICODE_LONG);
9795 }
else if (hexadecimal_length == 0) {
9798 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9802 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9804 pm_parser_err(parser, parser->
current.end, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE);
9805 pm_parser_err(parser, parser->
current.end, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9811 parser->
current.end += hexadecimal_length;
9813 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count == 2) {
9814 extra_codepoints_start = unicode_start;
9817 uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length);
9818 escape_write_unicode(parser, buffer, flags, unicode_start, parser->
current.end, value);
9825 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count > 1) {
9826 pm_parser_err(parser, extra_codepoints_start, parser->
current.end - 1, PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL);
9830 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_LIST, (
int) (parser->
current.end - start), start);
9831 }
else if (peek(parser) ==
'}') {
9834 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9838 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9840 pm_parser_err(parser, unicode_codepoints_start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9844 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9845 pm_buffer_append_bytes(regular_expression_buffer, unicode_codepoints_start, (
size_t) (parser->
current.end - unicode_codepoints_start));
9848 size_t length = pm_strspn_hexadecimal_digit(parser->
current.end, MIN(parser->
end - parser->
current.end, 4));
9851 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9852 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9854 const uint8_t *start = parser->
current.end - 2;
9855 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9857 }
else if (length == 4) {
9858 uint32_t value = escape_unicode(parser, parser->
current.end, 4);
9860 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9861 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end + 4 - start));
9864 escape_write_unicode(parser, buffer, flags, start, parser->
current.end + 4, value);
9867 parser->
current.end += length;
9869 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9873 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9875 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_UNICODE);
9884 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9885 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9889 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9893 uint8_t peeked = peek(parser);
9897 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9903 if (match(parser,
'u') || match(parser,
'U')) {
9904 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9908 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9912 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9913 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9917 escape_read_warn(parser, flags, 0,
"\\t");
9918 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9921 if (!char_is_ascii_printable(peeked)) {
9922 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9927 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9934 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9935 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9938 if (peek(parser) !=
'-') {
9940 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9946 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9950 uint8_t peeked = peek(parser);
9954 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9960 if (match(parser,
'u') || match(parser,
'U')) {
9961 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9965 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9969 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9970 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9974 escape_read_warn(parser, flags, 0,
"\\t");
9975 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9978 if (!char_is_ascii_printable(peeked)) {
9980 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9985 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9992 if (flags & PM_ESCAPE_FLAG_META) {
9993 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META_REPEAT);
9996 if (peek(parser) !=
'-') {
9998 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
10004 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
10008 uint8_t peeked = peek(parser);
10013 if (match(parser,
'u') || match(parser,
'U')) {
10014 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
10018 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_META);
10022 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_META,
"\\s");
10023 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10027 escape_read_warn(parser, flags & ((uint8_t) ~PM_ESCAPE_FLAG_CONTROL), PM_ESCAPE_FLAG_META,
"\\t");
10028 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10031 if (!char_is_ascii_printable(peeked)) {
10033 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
10038 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10043 if (peek_offset(parser, 1) ==
'\n') {
10045 escape_write_byte_encoded(parser, buffer, escape_byte(
'\n', flags));
10051 if ((flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) && !char_is_ascii_printable(peeked)) {
10053 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
10057 escape_write_escape_encoded(parser, buffer, regular_expression_buffer, flags);
10059 pm_parser_err_current(parser, PM_ERR_INVALID_ESCAPE_CHARACTER);
10091static pm_token_type_t
10093 if (lex_state_end_p(parser)) {
10094 lex_state_set(parser, PM_LEX_STATE_BEG);
10095 return PM_TOKEN_QUESTION_MARK;
10099 pm_parser_err_current(parser, PM_ERR_INCOMPLETE_QUESTION_MARK);
10101 return PM_TOKEN_CHARACTER_LITERAL;
10104 if (pm_char_is_whitespace(*parser->
current.end)) {
10105 lex_state_set(parser, PM_LEX_STATE_BEG);
10106 return PM_TOKEN_QUESTION_MARK;
10109 lex_state_set(parser, PM_LEX_STATE_BEG);
10111 if (match(parser,
'\\')) {
10112 lex_state_set(parser, PM_LEX_STATE_END);
10115 pm_buffer_init_capacity(&buffer, 3);
10117 escape_read(parser, &buffer, NULL, PM_ESCAPE_FLAG_SINGLE);
10120 return PM_TOKEN_CHARACTER_LITERAL;
10129 (parser->
current.end + encoding_width >= parser->
end) ||
10130 !char_is_identifier(parser, parser->
current.end + encoding_width, parser->
end - (parser->
current.end + encoding_width))
10133 lex_state_set(parser, PM_LEX_STATE_END);
10134 parser->
current.end += encoding_width;
10136 return PM_TOKEN_CHARACTER_LITERAL;
10140 return PM_TOKEN_QUESTION_MARK;
10147static pm_token_type_t
10149 pm_token_type_t
type = match(parser,
'@') ? PM_TOKEN_CLASS_VARIABLE : PM_TOKEN_INSTANCE_VARIABLE;
10150 const uint8_t *end = parser->
end;
10153 if ((width = char_is_identifier_start(parser, parser->
current.end, end - parser->
current.end)) > 0) {
10154 parser->
current.end += width;
10156 while ((width = char_is_identifier(parser, parser->
current.end, end - parser->
current.end)) > 0) {
10157 parser->
current.end += width;
10159 }
else if (parser->
current.end < end && pm_char_is_decimal_digit(*parser->
current.end)) {
10160 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE;
10162 diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS_3_3 : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE_3_3;
10166 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, diag_id, (
int) ((parser->
current.end + width) - parser->
current.start), (
const char *) parser->
current.start);
10168 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_CLASS_VARIABLE_BARE : PM_ERR_INSTANCE_VARIABLE_BARE;
10169 pm_parser_err_token(parser, &parser->
current, diag_id);
10175 lex_mode_pop(parser);
10197 if (comment == NULL)
return NULL;
10212static pm_token_type_t
10215 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10217 if (newline == NULL) {
10220 pm_newline_list_append(&parser->
newline_list, newline);
10221 parser->
current.end = newline + 1;
10224 parser->
current.type = PM_TOKEN_EMBDOC_BEGIN;
10225 parser_lex_callback(parser);
10228 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_EMBDOC);
10229 if (comment == NULL)
return PM_TOKEN_EOF;
10233 while (parser->
current.end + 4 <= parser->
end) {
10239 (memcmp(parser->
current.end,
"=end", 4) == 0) &&
10242 pm_char_is_whitespace(parser->
current.end[4]) ||
10243 (parser->
current.end[4] ==
'\0') ||
10244 (parser->
current.end[4] ==
'\004') ||
10245 (parser->
current.end[4] ==
'\032')
10248 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10250 if (newline == NULL) {
10253 pm_newline_list_append(&parser->
newline_list, newline);
10254 parser->
current.end = newline + 1;
10257 parser->
current.type = PM_TOKEN_EMBDOC_END;
10258 parser_lex_callback(parser);
10263 return PM_TOKEN_EMBDOC_END;
10268 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10270 if (newline == NULL) {
10273 pm_newline_list_append(&parser->
newline_list, newline);
10274 parser->
current.end = newline + 1;
10277 parser->
current.type = PM_TOKEN_EMBDOC_LINE;
10278 parser_lex_callback(parser);
10281 pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
10286 return PM_TOKEN_EOF;
10296 parser->
current.type = PM_TOKEN_IGNORED_NEWLINE;
10297 parser_lex_callback(parser);
10321 const uint8_t *cursor = parser->
current.end;
10323 while (cursor < parser->end && *cursor !=
'\n' && *cursor !=
'#') {
10324 if (!pm_char_is_inline_whitespace(*cursor++))
return false;
10387 pm_buffer_append_byte(&token_buffer->
buffer,
byte);
10398static inline size_t
10404 width = pm_encoding_utf_8_char_width(parser->
current.end, parser->
end - parser->
current.end);
10409 return (width == 0 ? 1 : width);
10417 size_t width = parser_char_width(parser);
10418 pm_buffer_append_bytes(&token_buffer->
buffer, parser->
current.end, width);
10419 parser->
current.end += width;
10424 size_t width = parser_char_width(parser);
10425 pm_buffer_append_bytes(&token_buffer->
base.
buffer, parser->
current.end, width);
10427 parser->
current.end += width;
10431pm_slice_ascii_only_p(
const uint8_t *value,
size_t length) {
10432 for (
size_t index = 0; index < length; index++) {
10433 if (value[index] & 0x80)
return false;
10447 pm_string_owned_init(&parser->
current_string, (uint8_t *) pm_buffer_value(&token_buffer->
buffer), pm_buffer_length(&token_buffer->
buffer));
10468 if (token_buffer->
cursor == NULL) {
10471 pm_buffer_append_bytes(&token_buffer->
buffer, token_buffer->
cursor, (
size_t) (parser->
current.end - token_buffer->
cursor));
10472 pm_token_buffer_copy(parser, token_buffer);
10484 pm_regexp_token_buffer_copy(parser, token_buffer);
10488#define PM_TOKEN_BUFFER_DEFAULT_SIZE 16
10500 const uint8_t *start;
10501 if (token_buffer->
cursor == NULL) {
10502 pm_buffer_init_capacity(&token_buffer->
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10503 start = parser->
current.start;
10505 start = token_buffer->
cursor;
10508 const uint8_t *end = parser->
current.end - 1;
10509 assert(end >= start);
10510 pm_buffer_append_bytes(&token_buffer->
buffer, start, (
size_t) (end - start));
10512 token_buffer->
cursor = end;
10517 const uint8_t *start;
10519 pm_buffer_init_capacity(&token_buffer->
base.
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10520 pm_buffer_init_capacity(&token_buffer->
regexp_buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10521 start = parser->
current.start;
10526 const uint8_t *end = parser->
current.end - 1;
10527 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, (
size_t) (end - start));
10528 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, (
size_t) (end - start));
10533#undef PM_TOKEN_BUFFER_DEFAULT_SIZE
10539static inline size_t
10541 size_t whitespace = 0;
10544 case PM_HEREDOC_INDENT_NONE:
10549 case PM_HEREDOC_INDENT_DASH:
10551 *cursor += pm_strspn_inline_whitespace(*cursor, parser->
end - *cursor);
10553 case PM_HEREDOC_INDENT_TILDE:
10556 while (*cursor < parser->end && pm_char_is_inline_whitespace(**cursor)) {
10557 if (**cursor ==
'\t') {
10558 whitespace = (whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
10577 size_t eol_length = match_eol(parser);
10584 parser_flush_heredoc_end(parser);
10590 uint8_t delimiter = *parser->
current.end;
10594 if (eol_length == 2) {
10595 delimiter = *(parser->
current.end + 1);
10598 parser->
current.end += eol_length;
10602 return *parser->
current.end++;
10609#define LEX(token_type) parser->current.type = token_type; parser_lex_callback(parser); return
10628 bool lexed_comment =
false;
10636 case PM_LEX_DEFAULT:
10637 case PM_LEX_EMBEXPR:
10638 case PM_LEX_EMBVAR:
10654 bool space_seen =
false;
10658 bool chomping =
true;
10659 while (parser->
current.end < parser->
end && chomping) {
10660 switch (*parser->
current.end) {
10669 if (match_eol_offset(parser, 1)) {
10672 pm_parser_warn(parser, parser->
current.end, parser->
current.end + 1, PM_WARN_UNEXPECTED_CARRIAGE_RETURN);
10678 size_t eol_length = match_eol_offset(parser, 1);
10684 parser->
current.end += eol_length + 1;
10688 }
else if (pm_char_is_inline_whitespace(*parser->
current.end)) {
10721 switch (*parser->
current.end++) {
10729 const uint8_t *ending = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10730 parser->
current.end = ending == NULL ? parser->
end : ending;
10735 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_INLINE);
10738 if (ending) parser->
current.end++;
10739 parser->
current.type = PM_TOKEN_COMMENT;
10740 parser_lex_callback(parser);
10752 parser_lex_magic_comment_encoding(parser);
10756 lexed_comment =
true;
10762 size_t eol_length = match_eol_at(parser, parser->
current.end - 1);
10774 if (!lexed_comment) {
10775 parser->
current.end += eol_length - 1;
10784 parser_flush_heredoc_end(parser);
10789 switch (lex_state_ignored_p(parser)) {
10790 case PM_IGNORED_NEWLINE_NONE:
10792 case PM_IGNORED_NEWLINE_PATTERN:
10794 if (!lexed_comment) parser_lex_ignored_newline(parser);
10795 lex_state_set(parser, PM_LEX_STATE_BEG);
10797 parser->
current.type = PM_TOKEN_NEWLINE;
10801 case PM_IGNORED_NEWLINE_ALL:
10802 if (!lexed_comment) parser_lex_ignored_newline(parser);
10803 lexed_comment =
false;
10804 goto lex_next_token;
10812 next_content += pm_strspn_inline_whitespace(next_content, parser->
end - next_content);
10814 if (next_content < parser->end) {
10820 if (next_content[0] ==
'#') {
10822 const uint8_t *following = next_newline(next_content, parser->
end - next_content);
10824 while (following && (following + 1 < parser->
end)) {
10826 following += pm_strspn_inline_whitespace(following, parser->
end - following);
10830 if (peek_at(parser, following) !=
'#')
break;
10834 following = next_newline(following, parser->
end - following);
10840 lex_state_ignored_p(parser) ||
10842 (peek_at(parser, following) ==
'.') ||
10843 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'.')
10846 if (!lexed_comment) parser_lex_ignored_newline(parser);
10847 lexed_comment =
false;
10848 goto lex_next_token;
10854 if (next_content[0] ==
'.') {
10858 if (peek_at(parser, next_content + 1) ==
'.') {
10859 if (!lexed_comment) parser_lex_ignored_newline(parser);
10860 lex_state_set(parser, PM_LEX_STATE_BEG);
10862 parser->
current.type = PM_TOKEN_NEWLINE;
10866 if (!lexed_comment) parser_lex_ignored_newline(parser);
10867 lex_state_set(parser, PM_LEX_STATE_DOT);
10868 parser->
current.start = next_content;
10869 parser->
current.end = next_content + 1;
10876 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'.') {
10877 if (!lexed_comment) parser_lex_ignored_newline(parser);
10878 lex_state_set(parser, PM_LEX_STATE_DOT);
10879 parser->
current.start = next_content;
10880 parser->
current.end = next_content + 2;
10882 LEX(PM_TOKEN_AMPERSAND_DOT);
10888 lex_state_set(parser, PM_LEX_STATE_BEG);
10890 parser->
current.type = PM_TOKEN_NEWLINE;
10891 if (!lexed_comment) parser_lex_callback(parser);
10901 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10902 LEX(PM_TOKEN_COMMA);
10906 pm_token_type_t
type = PM_TOKEN_PARENTHESIS_LEFT;
10908 if (space_seen && (lex_state_arg_p(parser) || parser->
lex_state == (PM_LEX_STATE_END | PM_LEX_STATE_LABEL))) {
10909 type = PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES;
10913 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10914 pm_do_loop_stack_push(parser,
false);
10921 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10922 pm_do_loop_stack_pop(parser);
10923 LEX(PM_TOKEN_PARENTHESIS_RIGHT);
10927 lex_state_set(parser, PM_LEX_STATE_BEG);
10929 LEX(PM_TOKEN_SEMICOLON);
10934 pm_token_type_t
type = PM_TOKEN_BRACKET_LEFT;
10936 if (lex_state_operator_p(parser)) {
10937 if (match(parser,
']')) {
10939 lex_state_set(parser, PM_LEX_STATE_ARG);
10940 LEX(match(parser,
'=') ? PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL : PM_TOKEN_BRACKET_LEFT_RIGHT);
10943 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABEL);
10947 if (lex_state_beg_p(parser) || (lex_state_arg_p(parser) && (space_seen || lex_state_p(parser, PM_LEX_STATE_LABELED)))) {
10948 type = PM_TOKEN_BRACKET_LEFT_ARRAY;
10951 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10952 pm_do_loop_stack_push(parser,
false);
10958 lex_state_set(parser, PM_LEX_STATE_END);
10959 pm_do_loop_stack_pop(parser);
10960 LEX(PM_TOKEN_BRACKET_RIGHT);
10964 pm_token_type_t
type = PM_TOKEN_BRACE_LEFT;
10969 lex_state_set(parser, PM_LEX_STATE_BEG);
10970 type = PM_TOKEN_LAMBDA_BEGIN;
10971 }
else if (lex_state_p(parser, PM_LEX_STATE_LABELED)) {
10973 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10974 }
else if (lex_state_p(parser, PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_END | PM_LEX_STATE_ENDFN)) {
10977 lex_state_set(parser, PM_LEX_STATE_BEG);
10978 }
else if (lex_state_p(parser, PM_LEX_STATE_ENDARG)) {
10981 lex_state_set(parser, PM_LEX_STATE_BEG);
10984 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10989 pm_do_loop_stack_push(parser,
false);
10997 pm_do_loop_stack_pop(parser);
11000 lex_mode_pop(parser);
11001 LEX(PM_TOKEN_EMBEXPR_END);
11005 lex_state_set(parser, PM_LEX_STATE_END);
11006 LEX(PM_TOKEN_BRACE_RIGHT);
11010 if (match(parser,
'*')) {
11011 if (match(parser,
'=')) {
11012 lex_state_set(parser, PM_LEX_STATE_BEG);
11013 LEX(PM_TOKEN_STAR_STAR_EQUAL);
11016 pm_token_type_t
type = PM_TOKEN_STAR_STAR;
11018 if (lex_state_spcarg_p(parser, space_seen)) {
11019 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR_STAR);
11020 type = PM_TOKEN_USTAR_STAR;
11021 }
else if (lex_state_beg_p(parser)) {
11022 type = PM_TOKEN_USTAR_STAR;
11023 }
else if (ambiguous_operator_p(parser, space_seen)) {
11024 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"**",
"argument prefix");
11027 if (lex_state_operator_p(parser)) {
11028 lex_state_set(parser, PM_LEX_STATE_ARG);
11030 lex_state_set(parser, PM_LEX_STATE_BEG);
11036 if (match(parser,
'=')) {
11037 lex_state_set(parser, PM_LEX_STATE_BEG);
11038 LEX(PM_TOKEN_STAR_EQUAL);
11041 pm_token_type_t
type = PM_TOKEN_STAR;
11043 if (lex_state_spcarg_p(parser, space_seen)) {
11044 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR);
11045 type = PM_TOKEN_USTAR;
11046 }
else if (lex_state_beg_p(parser)) {
11047 type = PM_TOKEN_USTAR;
11048 }
else if (ambiguous_operator_p(parser, space_seen)) {
11049 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"*",
"argument prefix");
11052 if (lex_state_operator_p(parser)) {
11053 lex_state_set(parser, PM_LEX_STATE_ARG);
11055 lex_state_set(parser, PM_LEX_STATE_BEG);
11063 if (lex_state_operator_p(parser)) {
11064 lex_state_set(parser, PM_LEX_STATE_ARG);
11065 if (match(parser,
'@')) {
11066 LEX(PM_TOKEN_BANG);
11069 lex_state_set(parser, PM_LEX_STATE_BEG);
11072 if (match(parser,
'=')) {
11073 LEX(PM_TOKEN_BANG_EQUAL);
11076 if (match(parser,
'~')) {
11077 LEX(PM_TOKEN_BANG_TILDE);
11080 LEX(PM_TOKEN_BANG);
11085 current_token_starts_line(parser) &&
11087 memcmp(parser->
current.end,
"begin", 5) == 0 &&
11088 (pm_char_is_whitespace(peek_offset(parser, 5)) || (peek_offset(parser, 5) ==
'\0'))
11090 pm_token_type_t
type = lex_embdoc(parser);
11091 if (
type == PM_TOKEN_EOF) {
11095 goto lex_next_token;
11098 if (lex_state_operator_p(parser)) {
11099 lex_state_set(parser, PM_LEX_STATE_ARG);
11101 lex_state_set(parser, PM_LEX_STATE_BEG);
11104 if (match(parser,
'>')) {
11105 LEX(PM_TOKEN_EQUAL_GREATER);
11108 if (match(parser,
'~')) {
11109 LEX(PM_TOKEN_EQUAL_TILDE);
11112 if (match(parser,
'=')) {
11113 LEX(match(parser,
'=') ? PM_TOKEN_EQUAL_EQUAL_EQUAL : PM_TOKEN_EQUAL_EQUAL);
11116 LEX(PM_TOKEN_EQUAL);
11120 if (match(parser,
'<')) {
11122 !lex_state_p(parser, PM_LEX_STATE_DOT | PM_LEX_STATE_CLASS) &&
11123 !lex_state_end_p(parser) &&
11124 (!lex_state_p(parser, PM_LEX_STATE_ARG_ANY) || lex_state_p(parser, PM_LEX_STATE_LABELED) || space_seen)
11126 const uint8_t *end = parser->
current.end;
11131 if (match(parser,
'-')) {
11132 indent = PM_HEREDOC_INDENT_DASH;
11134 else if (match(parser,
'~')) {
11135 indent = PM_HEREDOC_INDENT_TILDE;
11138 if (match(parser,
'`')) {
11139 quote = PM_HEREDOC_QUOTE_BACKTICK;
11141 else if (match(parser,
'"')) {
11142 quote = PM_HEREDOC_QUOTE_DOUBLE;
11144 else if (match(parser,
'\'')) {
11145 quote = PM_HEREDOC_QUOTE_SINGLE;
11148 const uint8_t *ident_start = parser->
current.end;
11153 }
else if (quote == PM_HEREDOC_QUOTE_NONE && (width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) == 0) {
11156 if (quote == PM_HEREDOC_QUOTE_NONE) {
11157 parser->
current.end += width;
11159 while ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end))) {
11160 parser->
current.end += width;
11166 if (*parser->
current.end ==
'\r' || *parser->
current.end ==
'\n')
break;
11171 size_t ident_length = (size_t) (parser->
current.end - ident_start);
11172 bool ident_error =
false;
11174 if (quote != PM_HEREDOC_QUOTE_NONE && !match(parser, (uint8_t) quote)) {
11175 pm_parser_err(parser, ident_start, ident_start + ident_length, PM_ERR_HEREDOC_IDENTIFIER);
11176 ident_error =
true;
11181 .mode = PM_LEX_HEREDOC,
11184 .ident_start = ident_start,
11185 .ident_length = ident_length,
11189 .next_start = parser->
current.end,
11191 .line_continuation =
false
11196 const uint8_t *body_start = next_newline(parser->
current.end, parser->
end - parser->
current.end);
11198 if (body_start == NULL) {
11203 if (!ident_error) pm_parser_err_heredoc_term(parser, ident_start, ident_length);
11204 body_start = parser->
end;
11208 pm_newline_list_append(&parser->
newline_list, body_start);
11217 LEX(PM_TOKEN_HEREDOC_START);
11221 if (match(parser,
'=')) {
11222 lex_state_set(parser, PM_LEX_STATE_BEG);
11223 LEX(PM_TOKEN_LESS_LESS_EQUAL);
11226 if (ambiguous_operator_p(parser, space_seen)) {
11227 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"<<",
"here document");
11230 if (lex_state_operator_p(parser)) {
11231 lex_state_set(parser, PM_LEX_STATE_ARG);
11233 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
11234 lex_state_set(parser, PM_LEX_STATE_BEG);
11237 LEX(PM_TOKEN_LESS_LESS);
11240 if (lex_state_operator_p(parser)) {
11241 lex_state_set(parser, PM_LEX_STATE_ARG);
11243 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
11244 lex_state_set(parser, PM_LEX_STATE_BEG);
11247 if (match(parser,
'=')) {
11248 if (match(parser,
'>')) {
11249 LEX(PM_TOKEN_LESS_EQUAL_GREATER);
11252 LEX(PM_TOKEN_LESS_EQUAL);
11255 LEX(PM_TOKEN_LESS);
11259 if (match(parser,
'>')) {
11260 if (lex_state_operator_p(parser)) {
11261 lex_state_set(parser, PM_LEX_STATE_ARG);
11263 lex_state_set(parser, PM_LEX_STATE_BEG);
11265 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_GREATER_EQUAL : PM_TOKEN_GREATER_GREATER);
11268 if (lex_state_operator_p(parser)) {
11269 lex_state_set(parser, PM_LEX_STATE_ARG);
11271 lex_state_set(parser, PM_LEX_STATE_BEG);
11274 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_EQUAL : PM_TOKEN_GREATER);
11278 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
11279 lex_mode_push_string(parser,
true, label_allowed,
'\0',
'"');
11280 LEX(PM_TOKEN_STRING_BEGIN);
11285 if (lex_state_p(parser, PM_LEX_STATE_FNAME)) {
11286 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11287 LEX(PM_TOKEN_BACKTICK);
11290 if (lex_state_p(parser, PM_LEX_STATE_DOT)) {
11291 if (previous_command_start) {
11292 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11294 lex_state_set(parser, PM_LEX_STATE_ARG);
11297 LEX(PM_TOKEN_BACKTICK);
11300 lex_mode_push_string(parser,
true,
false,
'\0',
'`');
11301 LEX(PM_TOKEN_BACKTICK);
11306 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
11307 lex_mode_push_string(parser,
false, label_allowed,
'\0',
'\'');
11308 LEX(PM_TOKEN_STRING_BEGIN);
11313 LEX(lex_question_mark(parser));
11317 if (match(parser,
'&')) {
11318 lex_state_set(parser, PM_LEX_STATE_BEG);
11320 if (match(parser,
'=')) {
11321 LEX(PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
11324 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
11327 if (match(parser,
'=')) {
11328 lex_state_set(parser, PM_LEX_STATE_BEG);
11329 LEX(PM_TOKEN_AMPERSAND_EQUAL);
11332 if (match(parser,
'.')) {
11333 lex_state_set(parser, PM_LEX_STATE_DOT);
11334 LEX(PM_TOKEN_AMPERSAND_DOT);
11337 pm_token_type_t
type = PM_TOKEN_AMPERSAND;
11338 if (lex_state_spcarg_p(parser, space_seen)) {
11339 if ((peek(parser) !=
':') || (peek_offset(parser, 1) ==
'\0')) {
11340 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
11342 const uint8_t delim = peek_offset(parser, 1);
11344 if ((delim !=
'\'') && (delim !=
'"') && !char_is_identifier(parser, parser->
current.end + 1, parser->
end - (parser->
current.end + 1))) {
11345 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
11349 type = PM_TOKEN_UAMPERSAND;
11350 }
else if (lex_state_beg_p(parser)) {
11351 type = PM_TOKEN_UAMPERSAND;
11352 }
else if (ambiguous_operator_p(parser, space_seen)) {
11353 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"&",
"argument prefix");
11356 if (lex_state_operator_p(parser)) {
11357 lex_state_set(parser, PM_LEX_STATE_ARG);
11359 lex_state_set(parser, PM_LEX_STATE_BEG);
11367 if (match(parser,
'|')) {
11368 if (match(parser,
'=')) {
11369 lex_state_set(parser, PM_LEX_STATE_BEG);
11370 LEX(PM_TOKEN_PIPE_PIPE_EQUAL);
11373 if (lex_state_p(parser, PM_LEX_STATE_BEG)) {
11375 LEX(PM_TOKEN_PIPE);
11378 lex_state_set(parser, PM_LEX_STATE_BEG);
11379 LEX(PM_TOKEN_PIPE_PIPE);
11382 if (match(parser,
'=')) {
11383 lex_state_set(parser, PM_LEX_STATE_BEG);
11384 LEX(PM_TOKEN_PIPE_EQUAL);
11387 if (lex_state_operator_p(parser)) {
11388 lex_state_set(parser, PM_LEX_STATE_ARG);
11390 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
11393 LEX(PM_TOKEN_PIPE);
11397 if (lex_state_operator_p(parser)) {
11398 lex_state_set(parser, PM_LEX_STATE_ARG);
11400 if (match(parser,
'@')) {
11401 LEX(PM_TOKEN_UPLUS);
11404 LEX(PM_TOKEN_PLUS);
11407 if (match(parser,
'=')) {
11408 lex_state_set(parser, PM_LEX_STATE_BEG);
11409 LEX(PM_TOKEN_PLUS_EQUAL);
11413 lex_state_beg_p(parser) ||
11414 (lex_state_spcarg_p(parser, space_seen) ? (pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS),
true) : false)
11416 lex_state_set(parser, PM_LEX_STATE_BEG);
11418 if (pm_char_is_decimal_digit(peek(parser))) {
11420 pm_token_type_t
type = lex_numeric(parser);
11421 lex_state_set(parser, PM_LEX_STATE_END);
11425 LEX(PM_TOKEN_UPLUS);
11428 if (ambiguous_operator_p(parser, space_seen)) {
11429 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"+",
"unary operator");
11432 lex_state_set(parser, PM_LEX_STATE_BEG);
11433 LEX(PM_TOKEN_PLUS);
11438 if (lex_state_operator_p(parser)) {
11439 lex_state_set(parser, PM_LEX_STATE_ARG);
11441 if (match(parser,
'@')) {
11442 LEX(PM_TOKEN_UMINUS);
11445 LEX(PM_TOKEN_MINUS);
11448 if (match(parser,
'=')) {
11449 lex_state_set(parser, PM_LEX_STATE_BEG);
11450 LEX(PM_TOKEN_MINUS_EQUAL);
11453 if (match(parser,
'>')) {
11454 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11455 LEX(PM_TOKEN_MINUS_GREATER);
11458 bool spcarg = lex_state_spcarg_p(parser, space_seen);
11459 bool is_beg = lex_state_beg_p(parser);
11460 if (!is_beg && spcarg) {
11461 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS);
11464 if (is_beg || spcarg) {
11465 lex_state_set(parser, PM_LEX_STATE_BEG);
11466 LEX(pm_char_is_decimal_digit(peek(parser)) ? PM_TOKEN_UMINUS_NUM : PM_TOKEN_UMINUS);
11469 if (ambiguous_operator_p(parser, space_seen)) {
11470 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"-",
"unary operator");
11473 lex_state_set(parser, PM_LEX_STATE_BEG);
11474 LEX(PM_TOKEN_MINUS);
11479 bool beg_p = lex_state_beg_p(parser);
11481 if (match(parser,
'.')) {
11482 if (match(parser,
'.')) {
11485 if (lex_state_p(parser, PM_LEX_STATE_END)) {
11486 lex_state_set(parser, PM_LEX_STATE_BEG);
11488 lex_state_set(parser, PM_LEX_STATE_ENDARG);
11490 LEX(PM_TOKEN_UDOT_DOT_DOT);
11494 pm_parser_warn_token(parser, &parser->
current, PM_WARN_DOT_DOT_DOT_EOL);
11497 lex_state_set(parser, PM_LEX_STATE_BEG);
11498 LEX(beg_p ? PM_TOKEN_UDOT_DOT_DOT : PM_TOKEN_DOT_DOT_DOT);
11501 lex_state_set(parser, PM_LEX_STATE_BEG);
11502 LEX(beg_p ? PM_TOKEN_UDOT_DOT : PM_TOKEN_DOT_DOT);
11505 lex_state_set(parser, PM_LEX_STATE_DOT);
11520 pm_token_type_t
type = lex_numeric(parser);
11521 lex_state_set(parser, PM_LEX_STATE_END);
11527 if (match(parser,
':')) {
11528 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)) {
11529 lex_state_set(parser, PM_LEX_STATE_BEG);
11530 LEX(PM_TOKEN_UCOLON_COLON);
11533 lex_state_set(parser, PM_LEX_STATE_DOT);
11534 LEX(PM_TOKEN_COLON_COLON);
11537 if (lex_state_end_p(parser) || pm_char_is_whitespace(peek(parser)) || peek(parser) ==
'#') {
11538 lex_state_set(parser, PM_LEX_STATE_BEG);
11539 LEX(PM_TOKEN_COLON);
11542 if (peek(parser) ==
'"' || peek(parser) ==
'\'') {
11543 lex_mode_push_string(parser, peek(parser) ==
'"',
false,
'\0', *parser->
current.end);
11547 lex_state_set(parser, PM_LEX_STATE_FNAME);
11548 LEX(PM_TOKEN_SYMBOL_BEGIN);
11552 if (lex_state_beg_p(parser)) {
11553 lex_mode_push_regexp(parser,
'\0',
'/');
11554 LEX(PM_TOKEN_REGEXP_BEGIN);
11557 if (match(parser,
'=')) {
11558 lex_state_set(parser, PM_LEX_STATE_BEG);
11559 LEX(PM_TOKEN_SLASH_EQUAL);
11562 if (lex_state_spcarg_p(parser, space_seen)) {
11563 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_SLASH);
11564 lex_mode_push_regexp(parser,
'\0',
'/');
11565 LEX(PM_TOKEN_REGEXP_BEGIN);
11568 if (ambiguous_operator_p(parser, space_seen)) {
11569 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"/",
"regexp literal");
11572 if (lex_state_operator_p(parser)) {
11573 lex_state_set(parser, PM_LEX_STATE_ARG);
11575 lex_state_set(parser, PM_LEX_STATE_BEG);
11578 LEX(PM_TOKEN_SLASH);
11582 if (lex_state_operator_p(parser)) {
11583 lex_state_set(parser, PM_LEX_STATE_ARG);
11585 lex_state_set(parser, PM_LEX_STATE_BEG);
11587 LEX(match(parser,
'=') ? PM_TOKEN_CARET_EQUAL : PM_TOKEN_CARET);
11591 if (lex_state_operator_p(parser)) {
11592 (void) match(parser,
'@');
11593 lex_state_set(parser, PM_LEX_STATE_ARG);
11595 lex_state_set(parser, PM_LEX_STATE_BEG);
11598 LEX(PM_TOKEN_TILDE);
11606 if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->
current.end >= parser->
end)) {
11607 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT_EOF);
11608 LEX(PM_TOKEN_PERCENT);
11611 if (!lex_state_beg_p(parser) && match(parser,
'=')) {
11612 lex_state_set(parser, PM_LEX_STATE_BEG);
11613 LEX(PM_TOKEN_PERCENT_EQUAL);
11615 lex_state_beg_p(parser) ||
11616 (lex_state_p(parser, PM_LEX_STATE_FITEM) && (peek(parser) ==
's')) ||
11617 lex_state_spcarg_p(parser, space_seen)
11620 if (*parser->
current.end >= 0x80) {
11621 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11624 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11625 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11626 LEX(PM_TOKEN_STRING_BEGIN);
11631 uint8_t delimiter = peek_offset(parser, 1);
11633 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11634 goto lex_next_token;
11637 switch (peek(parser)) {
11642 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11644 lex_mode_push_list_eof(parser);
11647 LEX(PM_TOKEN_PERCENT_LOWER_I);
11653 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11655 lex_mode_push_list_eof(parser);
11658 LEX(PM_TOKEN_PERCENT_UPPER_I);
11664 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11665 lex_mode_push_regexp(parser, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11667 lex_mode_push_regexp(parser,
'\0',
'\0');
11670 LEX(PM_TOKEN_REGEXP_BEGIN);
11676 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11677 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11679 lex_mode_push_string_eof(parser);
11682 LEX(PM_TOKEN_STRING_BEGIN);
11688 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11689 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11691 lex_mode_push_string_eof(parser);
11694 LEX(PM_TOKEN_STRING_BEGIN);
11700 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11701 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11702 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
11704 lex_mode_push_string_eof(parser);
11707 LEX(PM_TOKEN_SYMBOL_BEGIN);
11713 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11715 lex_mode_push_list_eof(parser);
11718 LEX(PM_TOKEN_PERCENT_LOWER_W);
11724 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11726 lex_mode_push_list_eof(parser);
11729 LEX(PM_TOKEN_PERCENT_UPPER_W);
11735 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11736 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11738 lex_mode_push_string_eof(parser);
11741 LEX(PM_TOKEN_PERCENT_LOWER_X);
11748 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11749 goto lex_next_token;
11753 if (ambiguous_operator_p(parser, space_seen)) {
11754 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"%",
"string literal");
11757 lex_state_set(parser, lex_state_operator_p(parser) ? PM_LEX_STATE_ARG : PM_LEX_STATE_BEG);
11758 LEX(PM_TOKEN_PERCENT);
11763 pm_token_type_t
type = lex_global_variable(parser);
11768 lex_mode_pop(parser);
11771 lex_state_set(parser, PM_LEX_STATE_END);
11777 lex_state_set(parser, parser->
lex_state & PM_LEX_STATE_FNAME ? PM_LEX_STATE_ENDFN : PM_LEX_STATE_END);
11778 LEX(lex_at_variable(parser));
11781 if (*parser->
current.start !=
'_') {
11782 size_t width = char_is_identifier_start(parser, parser->
current.start, parser->
end - parser->
current.start);
11789 if (*parser->
current.start >= 0x80) {
11790 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *parser->
current.start);
11791 }
else if (*parser->
current.start ==
'\\') {
11792 switch (peek_at(parser, parser->
current.start + 1)) {
11795 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped space");
11799 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped form feed");
11803 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped horizontal tab");
11807 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped vertical tab");
11810 if (peek_at(parser, parser->
current.start + 2) !=
'\n') {
11812 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped carriage return");
11817 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"backslash");
11820 }
else if (char_is_ascii_printable(*parser->
current.start)) {
11821 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_PRINTABLE_CHARACTER, *parser->
current.start);
11823 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_CHARACTER, *parser->
current.start);
11826 goto lex_next_token;
11832 pm_token_type_t
type = lex_identifier(parser, previous_command_start);
11840 current_token_starts_line(parser) &&
11841 (memcmp(parser->
current.start,
"__END__", 7) == 0) &&
11842 (parser->
current.end == parser->
end || match_eol(parser))
11847 const uint8_t *cursor = parser->
current.end;
11848 while ((cursor = next_newline(cursor, parser->
end - cursor)) != NULL) {
11849 pm_newline_list_append(&parser->
newline_list, cursor++);
11853 parser->
current.type = PM_TOKEN___END__;
11854 parser_lex_callback(parser);
11864 if (
type == PM_TOKEN_IDENTIFIER ||
type == PM_TOKEN_CONSTANT ||
type == PM_TOKEN_METHOD_NAME) {
11865 if (lex_state_p(parser, PM_LEX_STATE_BEG_ANY | PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_DOT)) {
11866 if (previous_command_start) {
11867 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11869 lex_state_set(parser, PM_LEX_STATE_ARG);
11871 }
else if (parser->
lex_state == PM_LEX_STATE_FNAME) {
11872 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11874 lex_state_set(parser, PM_LEX_STATE_END);
11879 !(last_state & (PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME)) &&
11880 (
type == PM_TOKEN_IDENTIFIER) &&
11881 ((pm_parser_local_depth(parser, &parser->
current) != -1) ||
11882 pm_token_is_numbered_parameter(parser->
current.start, parser->
current.end))
11884 lex_state_set(parser, PM_LEX_STATE_END | PM_LEX_STATE_LABEL);
11891 case PM_LEX_LIST: {
11905 whitespace = pm_strspn_inline_whitespace(parser->
current.end, parser->
end - parser->
current.end);
11906 if (peek_offset(parser, (ptrdiff_t)whitespace) ==
'\n') {
11913 if (whitespace > 0) {
11914 parser->
current.end += whitespace;
11915 if (peek_offset(parser, -1) ==
'\n') {
11917 parser_flush_heredoc_end(parser);
11919 LEX(PM_TOKEN_WORDS_SEP);
11931 const uint8_t *breakpoints = lex_mode->
as.list.
breakpoints;
11932 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11938 while (breakpoint != NULL) {
11941 if (pm_char_is_whitespace(*breakpoint)) {
11942 parser->
current.end = breakpoint;
11943 pm_token_buffer_flush(parser, &token_buffer);
11944 LEX(PM_TOKEN_STRING_CONTENT);
11953 parser->
current.end = breakpoint + 1;
11954 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11961 if (breakpoint > parser->
current.start) {
11962 parser->
current.end = breakpoint;
11963 pm_token_buffer_flush(parser, &token_buffer);
11964 LEX(PM_TOKEN_STRING_CONTENT);
11969 parser->
current.end = breakpoint + 1;
11970 lex_mode_pop(parser);
11971 lex_state_set(parser, PM_LEX_STATE_END);
11972 LEX(PM_TOKEN_STRING_END);
11976 if (*breakpoint ==
'\0') {
11977 breakpoint = pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->
end - (breakpoint + 1),
true);
11984 if (*breakpoint ==
'\\') {
11985 parser->
current.end = breakpoint + 1;
11994 pm_token_buffer_escape(parser, &token_buffer);
11995 uint8_t peeked = peek(parser);
12003 pm_token_buffer_push_byte(&token_buffer, peeked);
12008 if (peek(parser) !=
'\n') {
12009 pm_token_buffer_push_byte(&token_buffer,
'\r');
12014 pm_token_buffer_push_byte(&token_buffer,
'\n');
12020 parser_flush_heredoc_end(parser);
12021 pm_token_buffer_copy(parser, &token_buffer);
12022 LEX(PM_TOKEN_STRING_CONTENT);
12032 pm_token_buffer_push_byte(&token_buffer, peeked);
12035 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12037 pm_token_buffer_push_byte(&token_buffer,
'\\');
12038 pm_token_buffer_push_escaped(&token_buffer, parser);
12045 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12050 if (*breakpoint ==
'#') {
12051 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12053 if (
type == PM_TOKEN_NOT_PROVIDED) {
12058 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12062 if (
type == PM_TOKEN_STRING_CONTENT) {
12063 pm_token_buffer_flush(parser, &token_buffer);
12072 parser->
current.end = breakpoint + 1;
12073 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12079 pm_token_buffer_flush(parser, &token_buffer);
12080 LEX(PM_TOKEN_STRING_CONTENT);
12086 pm_token_buffer_flush(parser, &token_buffer);
12087 LEX(PM_TOKEN_STRING_CONTENT);
12089 case PM_LEX_REGEXP: {
12111 const uint8_t *breakpoints = lex_mode->
as.regexp.
breakpoints;
12112 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12115 while (breakpoint != NULL) {
12117 bool is_terminator = (*breakpoint == term);
12122 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
12123 if (term ==
'\n') {
12124 is_terminator =
true;
12130 if (term ==
'\r') {
12131 is_terminator =
false;
12137 if (is_terminator) {
12139 parser->
current.end = breakpoint + 1;
12140 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12148 if (breakpoint > parser->
current.start) {
12149 parser->
current.end = breakpoint;
12150 pm_regexp_token_buffer_flush(parser, &token_buffer);
12151 LEX(PM_TOKEN_STRING_CONTENT);
12155 size_t eol_length = match_eol_at(parser, breakpoint);
12157 parser->
current.end = breakpoint + eol_length;
12160 parser->
current.end = breakpoint + 1;
12167 lex_mode_pop(parser);
12168 lex_state_set(parser, PM_LEX_STATE_END);
12169 LEX(PM_TOKEN_REGEXP_END);
12174 if (*breakpoint && *breakpoint == lex_mode->
as.regexp.
incrementor) {
12175 parser->
current.end = breakpoint + 1;
12176 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12181 switch (*breakpoint) {
12184 parser->
current.end = breakpoint + 1;
12185 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12188 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12189 parser->
current.end = breakpoint + 1;
12190 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12195 parser->
current.end = breakpoint;
12196 pm_regexp_token_buffer_escape(parser, &token_buffer);
12204 pm_newline_list_append(&parser->
newline_list, breakpoint);
12205 parser->
current.end = breakpoint + 1;
12206 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12210 parser->
current.end = breakpoint + 1;
12211 parser_flush_heredoc_end(parser);
12212 pm_regexp_token_buffer_flush(parser, &token_buffer);
12213 LEX(PM_TOKEN_STRING_CONTENT);
12218 parser->
current.end = breakpoint + 1;
12227 pm_regexp_token_buffer_escape(parser, &token_buffer);
12228 uint8_t peeked = peek(parser);
12233 if (peek(parser) !=
'\n') {
12235 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12237 pm_regexp_token_buffer_push_byte(&token_buffer,
'\r');
12238 pm_token_buffer_push_byte(&token_buffer.
base,
'\r');
12247 parser_flush_heredoc_end(parser);
12248 pm_regexp_token_buffer_copy(parser, &token_buffer);
12249 LEX(PM_TOKEN_STRING_CONTENT);
12270 case '$':
case ')':
case '*':
case '+':
12271 case '.':
case '>':
case '?':
case ']':
12272 case '^':
case '|':
case '}':
12273 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12279 pm_regexp_token_buffer_push_byte(&token_buffer, peeked);
12280 pm_token_buffer_push_byte(&token_buffer.
base, peeked);
12285 if (peeked < 0x80) pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12286 pm_regexp_token_buffer_push_escaped(&token_buffer, parser);
12291 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12297 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12299 if (
type == PM_TOKEN_NOT_PROVIDED) {
12304 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12308 if (
type == PM_TOKEN_STRING_CONTENT) {
12309 pm_regexp_token_buffer_flush(parser, &token_buffer);
12315 assert(
false &&
"unreachable");
12321 pm_regexp_token_buffer_flush(parser, &token_buffer);
12322 LEX(PM_TOKEN_STRING_CONTENT);
12328 pm_regexp_token_buffer_flush(parser, &token_buffer);
12329 LEX(PM_TOKEN_STRING_CONTENT);
12331 case PM_LEX_STRING: {
12350 const uint8_t *breakpoints = lex_mode->
as.string.
breakpoints;
12351 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12357 while (breakpoint != NULL) {
12362 parser->
current.end = breakpoint + 1;
12363 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12368 bool is_terminator = (*breakpoint == term);
12373 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
12374 if (term ==
'\n') {
12375 is_terminator =
true;
12381 if (term ==
'\r') {
12382 is_terminator =
false;
12389 if (is_terminator) {
12393 parser->
current.end = breakpoint + 1;
12394 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12401 if (breakpoint > parser->
current.start) {
12402 parser->
current.end = breakpoint;
12403 pm_token_buffer_flush(parser, &token_buffer);
12404 LEX(PM_TOKEN_STRING_CONTENT);
12409 size_t eol_length = match_eol_at(parser, breakpoint);
12411 parser->
current.end = breakpoint + eol_length;
12414 parser->
current.end = breakpoint + 1;
12417 if (lex_mode->
as.string.
label_allowed && (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')) {
12419 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
12420 lex_mode_pop(parser);
12421 LEX(PM_TOKEN_LABEL_END);
12424 lex_state_set(parser, PM_LEX_STATE_END);
12425 lex_mode_pop(parser);
12426 LEX(PM_TOKEN_STRING_END);
12429 switch (*breakpoint) {
12432 parser->
current.end = breakpoint + 1;
12433 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12436 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12437 parser->
current.end = breakpoint + 1;
12438 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12445 parser->
current.end = breakpoint;
12446 pm_token_buffer_escape(parser, &token_buffer);
12447 token_buffer.
cursor = breakpoint;
12456 pm_newline_list_append(&parser->
newline_list, breakpoint);
12457 parser->
current.end = breakpoint + 1;
12458 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12462 parser->
current.end = breakpoint + 1;
12463 parser_flush_heredoc_end(parser);
12464 pm_token_buffer_flush(parser, &token_buffer);
12465 LEX(PM_TOKEN_STRING_CONTENT);
12468 parser->
current.end = breakpoint + 1;
12477 pm_token_buffer_escape(parser, &token_buffer);
12478 uint8_t peeked = peek(parser);
12482 pm_token_buffer_push_byte(&token_buffer,
'\\');
12487 if (peek(parser) !=
'\n') {
12489 pm_token_buffer_push_byte(&token_buffer,
'\\');
12491 pm_token_buffer_push_byte(&token_buffer,
'\r');
12497 pm_token_buffer_push_byte(&token_buffer,
'\\');
12498 pm_token_buffer_push_byte(&token_buffer,
'\n');
12505 parser_flush_heredoc_end(parser);
12506 pm_token_buffer_copy(parser, &token_buffer);
12507 LEX(PM_TOKEN_STRING_CONTENT);
12517 pm_token_buffer_push_byte(&token_buffer, peeked);
12520 pm_token_buffer_push_byte(&token_buffer, peeked);
12523 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12525 pm_token_buffer_push_byte(&token_buffer,
'\\');
12526 pm_token_buffer_push_escaped(&token_buffer, parser);
12533 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12537 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12539 if (
type == PM_TOKEN_NOT_PROVIDED) {
12544 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12548 if (
type == PM_TOKEN_STRING_CONTENT) {
12549 pm_token_buffer_flush(parser, &token_buffer);
12555 assert(
false &&
"unreachable");
12560 pm_token_buffer_flush(parser, &token_buffer);
12561 LEX(PM_TOKEN_STRING_CONTENT);
12567 pm_token_buffer_flush(parser, &token_buffer);
12568 LEX(PM_TOKEN_STRING_CONTENT);
12570 case PM_LEX_HEREDOC: {
12597 lex_state_set(parser, PM_LEX_STATE_END);
12598 lex_mode_pop(parser);
12599 LEX(PM_TOKEN_HEREDOC_END);
12602 const uint8_t *ident_start = heredoc_lex_mode->
ident_start;
12607 if (current_token_starts_line(parser)) {
12608 const uint8_t *start = parser->
current.start;
12610 if (!line_continuation && (start + ident_length <= parser->end)) {
12611 const uint8_t *newline = next_newline(start, parser->
end - start);
12612 const uint8_t *ident_end = newline;
12613 const uint8_t *terminator_end = newline;
12615 if (newline == NULL) {
12616 terminator_end = parser->
end;
12617 ident_end = parser->
end;
12620 if (newline[-1] ==
'\r') {
12625 const uint8_t *terminator_start = ident_end - ident_length;
12626 const uint8_t *cursor = start;
12628 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12629 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12635 (cursor == terminator_start) &&
12636 (memcmp(terminator_start, ident_start, ident_length) == 0)
12638 if (newline != NULL) {
12639 pm_newline_list_append(&parser->
newline_list, newline);
12642 parser->
current.end = terminator_end;
12650 lex_state_set(parser, PM_LEX_STATE_END);
12651 lex_mode_pop(parser);
12652 LEX(PM_TOKEN_HEREDOC_END);
12656 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, heredoc_lex_mode->
indent);
12658 heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE &&
12661 peek_at(parser, start) !=
'\n'
12670 uint8_t breakpoints[] =
"\r\n\\#";
12673 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12674 breakpoints[3] =
'\0';
12677 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12679 bool was_line_continuation =
false;
12681 while (breakpoint != NULL) {
12682 switch (*breakpoint) {
12685 parser->
current.end = breakpoint + 1;
12686 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12689 parser->
current.end = breakpoint + 1;
12691 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12692 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12699 pm_token_buffer_escape(parser, &token_buffer);
12700 token_buffer.
cursor = breakpoint;
12705 parser_flush_heredoc_end(parser);
12706 parser->
current.end = breakpoint + 1;
12707 pm_token_buffer_flush(parser, &token_buffer);
12708 LEX(PM_TOKEN_STRING_CONTENT);
12711 pm_newline_list_append(&parser->
newline_list, breakpoint);
12715 const uint8_t *start = breakpoint + 1;
12717 if (!was_line_continuation && (start + ident_length <= parser->end)) {
12720 const uint8_t *newline = next_newline(start, parser->
end - start);
12722 if (newline == NULL) {
12723 newline = parser->
end;
12724 }
else if (newline[-1] ==
'\r') {
12729 const uint8_t *terminator_start = newline - ident_length;
12733 const uint8_t *cursor = start;
12735 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12736 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12742 cursor == terminator_start &&
12743 (memcmp(terminator_start, ident_start, ident_length) == 0)
12745 parser->
current.end = breakpoint + 1;
12746 pm_token_buffer_flush(parser, &token_buffer);
12747 LEX(PM_TOKEN_STRING_CONTENT);
12751 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->
as.heredoc.
base.
indent);
12758 if (lex_mode->
as.heredoc.
base.
indent == PM_HEREDOC_INDENT_TILDE) {
12763 parser->
current.end = breakpoint + 1;
12764 pm_token_buffer_flush(parser, &token_buffer);
12765 LEX(PM_TOKEN_STRING_CONTENT);
12770 parser->
current.end = breakpoint + 1;
12771 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12781 parser->
current.end = breakpoint + 1;
12790 pm_token_buffer_escape(parser, &token_buffer);
12791 uint8_t peeked = peek(parser);
12793 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12797 if (peek(parser) !=
'\n') {
12798 pm_token_buffer_push_byte(&token_buffer,
'\\');
12799 pm_token_buffer_push_byte(&token_buffer,
'\r');
12804 pm_token_buffer_push_byte(&token_buffer,
'\\');
12805 pm_token_buffer_push_byte(&token_buffer,
'\n');
12807 breakpoint = parser->
current.end;
12810 pm_token_buffer_push_byte(&token_buffer,
'\\');
12811 pm_token_buffer_push_escaped(&token_buffer, parser);
12818 if (peek(parser) !=
'\n') {
12819 pm_token_buffer_push_byte(&token_buffer,
'\r');
12827 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12828 const uint8_t *end = parser->
current.end;
12833 parser->
current.end = breakpoint;
12834 pm_token_buffer_flush(parser, &token_buffer);
12838 parser->
current.end = end + 1;
12840 LEX(PM_TOKEN_STRING_CONTENT);
12843 was_line_continuation =
true;
12845 breakpoint = parser->
current.end;
12848 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12854 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12858 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12860 if (
type == PM_TOKEN_NOT_PROVIDED) {
12866 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12870 if (
type == PM_TOKEN_STRING_CONTENT) {
12871 pm_token_buffer_flush(parser, &token_buffer);
12877 assert(
false &&
"unreachable");
12880 was_line_continuation =
false;
12885 pm_token_buffer_flush(parser, &token_buffer);
12886 LEX(PM_TOKEN_STRING_CONTENT);
12892 pm_token_buffer_flush(parser, &token_buffer);
12893 LEX(PM_TOKEN_STRING_CONTENT);
12897 assert(
false &&
"unreachable");
12915 PM_BINDING_POWER_UNSET = 0,
12916 PM_BINDING_POWER_STATEMENT = 2,
12917 PM_BINDING_POWER_MODIFIER_RESCUE = 4,
12918 PM_BINDING_POWER_MODIFIER = 6,
12919 PM_BINDING_POWER_COMPOSITION = 8,
12920 PM_BINDING_POWER_NOT = 10,
12921 PM_BINDING_POWER_MATCH = 12,
12922 PM_BINDING_POWER_DEFINED = 14,
12923 PM_BINDING_POWER_MULTI_ASSIGNMENT = 16,
12924 PM_BINDING_POWER_ASSIGNMENT = 18,
12925 PM_BINDING_POWER_TERNARY = 20,
12926 PM_BINDING_POWER_RANGE = 22,
12927 PM_BINDING_POWER_LOGICAL_OR = 24,
12928 PM_BINDING_POWER_LOGICAL_AND = 26,
12929 PM_BINDING_POWER_EQUALITY = 28,
12930 PM_BINDING_POWER_COMPARISON = 30,
12931 PM_BINDING_POWER_BITWISE_OR = 32,
12932 PM_BINDING_POWER_BITWISE_AND = 34,
12933 PM_BINDING_POWER_SHIFT = 36,
12934 PM_BINDING_POWER_TERM = 38,
12935 PM_BINDING_POWER_FACTOR = 40,
12936 PM_BINDING_POWER_UMINUS = 42,
12937 PM_BINDING_POWER_EXPONENT = 44,
12938 PM_BINDING_POWER_UNARY = 46,
12939 PM_BINDING_POWER_INDEX = 48,
12940 PM_BINDING_POWER_CALL = 50,
12941 PM_BINDING_POWER_MAX = 52
12942} pm_binding_power_t;
12965#define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true, false }
12966#define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, false }
12967#define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true, false }
12968#define NON_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, true }
12969#define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false, false }
12973 [PM_TOKEN_KEYWORD_RESCUE_MODIFIER] = { PM_BINDING_POWER_MODIFIER_RESCUE, PM_BINDING_POWER_COMPOSITION,
true,
false },
12976 [PM_TOKEN_KEYWORD_IF_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12977 [PM_TOKEN_KEYWORD_UNLESS_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12978 [PM_TOKEN_KEYWORD_UNTIL_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12979 [PM_TOKEN_KEYWORD_WHILE_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12982 [PM_TOKEN_KEYWORD_AND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
12983 [PM_TOKEN_KEYWORD_OR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
12986 [PM_TOKEN_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
12987 [PM_TOKEN_KEYWORD_IN] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
12990 [PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
12991 [PM_TOKEN_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
12992 [PM_TOKEN_CARET_EQUAL] = BINDING_POWER_ASSIGNMENT,
12993 [PM_TOKEN_EQUAL] = BINDING_POWER_ASSIGNMENT,
12994 [PM_TOKEN_GREATER_GREATER_EQUAL] = BINDING_POWER_ASSIGNMENT,
12995 [PM_TOKEN_LESS_LESS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12996 [PM_TOKEN_MINUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12997 [PM_TOKEN_PERCENT_EQUAL] = BINDING_POWER_ASSIGNMENT,
12998 [PM_TOKEN_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
12999 [PM_TOKEN_PIPE_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
13000 [PM_TOKEN_PLUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
13001 [PM_TOKEN_SLASH_EQUAL] = BINDING_POWER_ASSIGNMENT,
13002 [PM_TOKEN_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
13003 [PM_TOKEN_STAR_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
13006 [PM_TOKEN_QUESTION_MARK] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_TERNARY),
13009 [PM_TOKEN_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
13010 [PM_TOKEN_DOT_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
13011 [PM_TOKEN_UDOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
13012 [PM_TOKEN_UDOT_DOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
13015 [PM_TOKEN_PIPE_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_OR),
13018 [PM_TOKEN_AMPERSAND_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_AND),
13021 [PM_TOKEN_BANG_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
13022 [PM_TOKEN_BANG_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
13023 [PM_TOKEN_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
13024 [PM_TOKEN_EQUAL_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
13025 [PM_TOKEN_EQUAL_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
13026 [PM_TOKEN_LESS_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
13029 [PM_TOKEN_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
13030 [PM_TOKEN_GREATER_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
13031 [PM_TOKEN_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
13032 [PM_TOKEN_LESS_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
13035 [PM_TOKEN_CARET] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
13036 [PM_TOKEN_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
13039 [PM_TOKEN_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_AND),
13042 [PM_TOKEN_GREATER_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
13043 [PM_TOKEN_LESS_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
13046 [PM_TOKEN_MINUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
13047 [PM_TOKEN_PLUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
13050 [PM_TOKEN_PERCENT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
13051 [PM_TOKEN_SLASH] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
13052 [PM_TOKEN_STAR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
13053 [PM_TOKEN_USTAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_FACTOR),
13056 [PM_TOKEN_UMINUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UMINUS),
13057 [PM_TOKEN_UMINUS_NUM] = { PM_BINDING_POWER_UMINUS, PM_BINDING_POWER_MAX,
false,
false },
13060 [PM_TOKEN_STAR_STAR] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_EXPONENT),
13061 [PM_TOKEN_USTAR_STAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13064 [PM_TOKEN_BANG] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13065 [PM_TOKEN_TILDE] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13066 [PM_TOKEN_UPLUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13069 [PM_TOKEN_BRACKET_LEFT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_INDEX),
13072 [PM_TOKEN_COLON_COLON] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
13073 [PM_TOKEN_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
13074 [PM_TOKEN_AMPERSAND_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL)
13077#undef BINDING_POWER_ASSIGNMENT
13078#undef LEFT_ASSOCIATIVE
13079#undef RIGHT_ASSOCIATIVE
13080#undef RIGHT_ASSOCIATIVE_UNARY
13094match2(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
13095 return match1(parser, type1) || match1(parser, type2);
13102match3(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3) {
13103 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3);
13110match4(
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) {
13111 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4);
13118match7(
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) {
13119 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7);
13126match8(
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) {
13127 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);
13138 if (match1(parser,
type)) {
13139 parser_lex(parser);
13150accept2(
pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
13151 if (match2(parser, type1, type2)) {
13152 parser_lex(parser);
13171 if (accept1(parser,
type))
return;
13174 pm_parser_err(parser, location, location, diag_id);
13186 if (accept2(parser, type1, type2))
return;
13189 pm_parser_err(parser, location, location, diag_id);
13200expect1_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
13201 if (match1(parser, PM_TOKEN_HEREDOC_END)) {
13202 parser_lex(parser);
13204 pm_parser_err_heredoc_term(parser, ident_start, ident_length);
13211parse_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);
13218parse_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) {
13219 pm_node_t *node = parse_expression(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
13220 pm_assert_value_expression(parser, node);
13243token_begins_expression_p(pm_token_type_t
type) {
13245 case PM_TOKEN_EQUAL_GREATER:
13246 case PM_TOKEN_KEYWORD_IN:
13250 case PM_TOKEN_BRACE_RIGHT:
13251 case PM_TOKEN_BRACKET_RIGHT:
13252 case PM_TOKEN_COLON:
13253 case PM_TOKEN_COMMA:
13254 case PM_TOKEN_EMBEXPR_END:
13256 case PM_TOKEN_LAMBDA_BEGIN:
13257 case PM_TOKEN_KEYWORD_DO:
13258 case PM_TOKEN_KEYWORD_DO_LOOP:
13259 case PM_TOKEN_KEYWORD_END:
13260 case PM_TOKEN_KEYWORD_ELSE:
13261 case PM_TOKEN_KEYWORD_ELSIF:
13262 case PM_TOKEN_KEYWORD_ENSURE:
13263 case PM_TOKEN_KEYWORD_THEN:
13264 case PM_TOKEN_KEYWORD_RESCUE:
13265 case PM_TOKEN_KEYWORD_WHEN:
13266 case PM_TOKEN_NEWLINE:
13267 case PM_TOKEN_PARENTHESIS_RIGHT:
13268 case PM_TOKEN_SEMICOLON:
13274 assert(pm_binding_powers[
type].left == PM_BINDING_POWER_UNSET);
13276 case PM_TOKEN_UAMPERSAND:
13280 case PM_TOKEN_UCOLON_COLON:
13281 case PM_TOKEN_UMINUS:
13282 case PM_TOKEN_UMINUS_NUM:
13283 case PM_TOKEN_UPLUS:
13284 case PM_TOKEN_BANG:
13285 case PM_TOKEN_TILDE:
13286 case PM_TOKEN_UDOT_DOT:
13287 case PM_TOKEN_UDOT_DOT_DOT:
13294 return pm_binding_powers[
type].
left == PM_BINDING_POWER_UNSET;
13303parse_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) {
13304 if (accept1(parser, PM_TOKEN_USTAR)) {
13306 pm_node_t *expression = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13307 return (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
13310 return parse_value_expression(parser, binding_power, accepts_command_call,
false, diag_id, depth);
13324 size_t length = constant->
length;
13325 uint8_t *name =
xcalloc(length + 1,
sizeof(uint8_t));
13326 if (name == NULL)
return;
13328 memcpy(name, constant->
start, length);
13329 name[length] =
'=';
13334 *name_field = pm_constant_pool_insert_owned(&parser->
constant_pool, name, length + 1);
13345 switch (PM_NODE_TYPE(target)) {
13346 case PM_SOURCE_ENCODING_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13347 case PM_FALSE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13348 case PM_SOURCE_FILE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13349 case PM_SOURCE_LINE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13350 case PM_NIL_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13351 case PM_SELF_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13352 case PM_TRUE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13359 pm_node_destroy(parser, target);
13372 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
13373 if (implicit_parameters->
nodes[index] == node) {
13377 if (index != implicit_parameters->
size - 1) {
13378 memcpy(&implicit_parameters->
nodes[index], &implicit_parameters->
nodes[index + 1], (implicit_parameters->
size - index - 1) *
sizeof(
pm_node_t *));
13381 implicit_parameters->
size--;
13397 switch (PM_NODE_TYPE(target)) {
13398 case PM_MISSING_NODE:
13400 case PM_SOURCE_ENCODING_NODE:
13401 case PM_FALSE_NODE:
13402 case PM_SOURCE_FILE_NODE:
13403 case PM_SOURCE_LINE_NODE:
13406 case PM_TRUE_NODE: {
13409 return parse_unwriteable_target(parser, target);
13411 case PM_CLASS_VARIABLE_READ_NODE:
13413 target->
type = PM_CLASS_VARIABLE_TARGET_NODE;
13415 case PM_CONSTANT_PATH_NODE:
13416 if (context_def_p(parser)) {
13417 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13421 target->
type = PM_CONSTANT_PATH_TARGET_NODE;
13424 case PM_CONSTANT_READ_NODE:
13425 if (context_def_p(parser)) {
13426 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13430 target->
type = PM_CONSTANT_TARGET_NODE;
13433 case PM_BACK_REFERENCE_READ_NODE:
13434 case PM_NUMBERED_REFERENCE_READ_NODE:
13435 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13437 case PM_GLOBAL_VARIABLE_READ_NODE:
13439 target->
type = PM_GLOBAL_VARIABLE_TARGET_NODE;
13441 case PM_LOCAL_VARIABLE_READ_NODE: {
13444 parse_target_implicit_parameter(parser, target);
13448 uint32_t name = cast->
name;
13449 uint32_t depth = cast->
depth;
13450 pm_locals_unread(&pm_parser_scope_find(parser, depth)->locals, name);
13453 target->
type = PM_LOCAL_VARIABLE_TARGET_NODE;
13457 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
13461 parse_target_implicit_parameter(parser, target);
13462 pm_node_destroy(parser, target);
13466 case PM_INSTANCE_VARIABLE_READ_NODE:
13468 target->
type = PM_INSTANCE_VARIABLE_TARGET_NODE;
13470 case PM_MULTI_TARGET_NODE:
13471 if (splat_parent) {
13474 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13478 case PM_SPLAT_NODE: {
13487 case PM_CALL_NODE: {
13499 (call->
block == NULL)
13514 pm_node_destroy(parser, target);
13516 return (
pm_node_t *) pm_local_variable_target_node_create(parser, &message_loc, name, 0);
13520 if (multiple && PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
13521 pm_parser_err_node(parser, (
const pm_node_t *) call, PM_ERR_UNEXPECTED_SAFE_NAVIGATION);
13524 parse_write_name(parser, &call->
name);
13525 return (
pm_node_t *) pm_call_target_node_create(parser, call);
13532 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
13533 return (
pm_node_t *) pm_index_target_node_create(parser, call);
13541 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13552 pm_node_t *result = parse_target(parser, target, multiple,
false);
13557 !match1(parser, PM_TOKEN_EQUAL) &&
13559 !(context_p(parser,
PM_CONTEXT_PARENS) && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
13561 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13575 if (shareable_constant != PM_SCOPE_SHAREABLE_CONSTANT_NONE) {
13576 return (
pm_node_t *) pm_shareable_constant_node_create(parser, write, shareable_constant);
13587 switch (PM_NODE_TYPE(target)) {
13588 case PM_MISSING_NODE:
13589 pm_node_destroy(parser, value);
13591 case PM_CLASS_VARIABLE_READ_NODE: {
13593 pm_node_destroy(parser, target);
13596 case PM_CONSTANT_PATH_NODE: {
13599 if (context_def_p(parser)) {
13600 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13603 return parse_shareable_constant_write(parser, node);
13605 case PM_CONSTANT_READ_NODE: {
13608 if (context_def_p(parser)) {
13609 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13612 pm_node_destroy(parser, target);
13613 return parse_shareable_constant_write(parser, node);
13615 case PM_BACK_REFERENCE_READ_NODE:
13616 case PM_NUMBERED_REFERENCE_READ_NODE:
13617 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13619 case PM_GLOBAL_VARIABLE_READ_NODE: {
13621 pm_node_destroy(parser, target);
13624 case PM_LOCAL_VARIABLE_READ_NODE: {
13630 uint32_t depth = local_read->
depth;
13631 pm_scope_t *scope = pm_parser_scope_find(parser, depth);
13634 pm_diagnostic_id_t diag_id = (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND) ? PM_ERR_EXPRESSION_NOT_WRITABLE_NUMBERED : PM_ERR_PARAMETER_NUMBERED_RESERVED;
13636 parse_target_implicit_parameter(parser, target);
13639 pm_locals_unread(&scope->
locals, name);
13640 pm_node_destroy(parser, target);
13642 return (
pm_node_t *) pm_local_variable_write_node_create(parser, name, depth, value, &name_loc,
operator);
13644 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
13648 parse_target_implicit_parameter(parser, target);
13649 pm_node_destroy(parser, target);
13653 case PM_INSTANCE_VARIABLE_READ_NODE: {
13655 pm_node_destroy(parser, target);
13658 case PM_MULTI_TARGET_NODE:
13660 case PM_SPLAT_NODE: {
13668 pm_multi_target_node_targets_append(parser, multi_target, (
pm_node_t *) splat);
13670 return (
pm_node_t *) pm_multi_write_node_create(parser, multi_target,
operator, value);
13672 case PM_CALL_NODE: {
13684 (call->
block == NULL)
13698 pm_parser_local_add_location(parser, message.
start, message.
end, 0);
13699 pm_node_destroy(parser, target);
13702 target = (
pm_node_t *) pm_local_variable_write_node_create(parser, constant_id, 0, value, &message,
operator);
13704 pm_refute_numbered_parameter(parser, message.
start, message.
end);
13722 pm_arguments_node_arguments_append(arguments, value);
13725 parse_write_name(parser, &call->
name);
13726 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));
13735 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
13737 call->
arguments = pm_arguments_node_create(parser);
13740 pm_arguments_node_arguments_append(call->
arguments, value);
13744 call->
name = pm_parser_constant_id_constant(parser,
"[]=", 3);
13748 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));
13758 pm_node_destroy(parser, value);
13765 pm_parser_err_token(parser,
operator, PM_ERR_WRITE_TARGET_UNEXPECTED);
13778 switch (PM_NODE_TYPE(target)) {
13779 case PM_SOURCE_ENCODING_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13780 case PM_FALSE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13781 case PM_SOURCE_FILE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13782 case PM_SOURCE_LINE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13783 case PM_NIL_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13784 case PM_SELF_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13785 case PM_TRUE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13792 pm_node_destroy(parser, target);
13807parse_targets(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13808 bool has_rest = PM_NODE_TYPE_P(first_target, PM_SPLAT_NODE);
13811 pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target,
true,
false));
13813 while (accept1(parser, PM_TOKEN_COMMA)) {
13814 if (accept1(parser, PM_TOKEN_USTAR)) {
13819 pm_parser_err_previous(parser, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
13825 if (token_begins_expression_p(parser->
current.type)) {
13826 name = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13827 name = parse_target(parser, name,
true,
true);
13830 pm_node_t *splat = (
pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
13831 pm_multi_target_node_targets_append(parser, result, splat);
13833 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
13835 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13836 target = parse_target(parser, target,
true,
false);
13838 pm_multi_target_node_targets_append(parser, result, target);
13839 context_pop(parser);
13840 }
else if (token_begins_expression_p(parser->
current.type)) {
13841 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13842 target = parse_target(parser, target,
true,
false);
13844 pm_multi_target_node_targets_append(parser, result, target);
13845 }
else if (!match1(parser, PM_TOKEN_EOF)) {
13849 pm_multi_target_node_targets_append(parser, result, rest);
13862parse_targets_validate(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13863 pm_node_t *result = parse_targets(parser, first_target, binding_power, depth);
13864 accept1(parser, PM_TOKEN_NEWLINE);
13867 if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
13868 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13881 while (accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE));
13884 if (context_terminator(context, &parser->
current))
return NULL;
13890 context_push(parser, context);
13893 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
13894 pm_statements_node_body_append(parser, statements, node,
true);
13907 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
13910 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13911 if (context_terminator(context, &parser->
current))
break;
13921 if (context_terminator(context, &parser->
current))
break;
13933 if (PM_NODE_TYPE_P(node, PM_MISSING_NODE)) {
13934 parser_lex(parser);
13940 if (match1(parser, PM_TOKEN_EOF)) {
13945 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13946 if (context_terminator(context, &parser->
current))
break;
13947 }
else if (!accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_EOF)) {
13957 context_pop(parser);
13958 bool last_value =
true;
13962 last_value =
false;
13967 pm_void_statements_check(parser, statements, last_value);
13980 if (duplicated != NULL) {
13984 pm_diagnostic_list_append_format(
13988 PM_WARN_DUPLICATED_HASH_KEY,
13989 (
int) pm_buffer_length(&buffer),
13990 pm_buffer_value(&buffer),
13994 pm_buffer_free(&buffer);
14006 if ((previous = pm_static_literals_add(&parser->
newline_list, parser->
start_line, literals, node,
false)) != NULL) {
14007 pm_diagnostic_list_append_format(
14011 PM_WARN_DUPLICATED_WHEN_CLAUSE,
14023 assert(PM_NODE_TYPE_P(node, PM_HASH_NODE) || PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE));
14024 bool contains_keyword_splat =
false;
14029 switch (parser->
current.type) {
14030 case PM_TOKEN_USTAR_STAR: {
14031 parser_lex(parser);
14035 if (match1(parser, PM_TOKEN_BRACE_LEFT)) {
14041 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
14042 }
else if (token_begins_expression_p(parser->
current.type)) {
14043 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
14045 pm_parser_scope_forwarding_keywords_check(parser, &
operator);
14048 element = (
pm_node_t *) pm_assoc_splat_node_create(parser, value, &
operator);
14049 contains_keyword_splat =
true;
14052 case PM_TOKEN_LABEL: {
14054 parser_lex(parser);
14057 pm_hash_key_static_literals_add(parser, literals, key);
14062 if (token_begins_expression_p(parser->
current.type)) {
14063 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_EXPRESSION_AFTER_LABEL, (uint16_t) (depth + 1));
14066 pm_token_t constant = { .type = PM_TOKEN_CONSTANT, .start = label.
start, .end = label.
end - 1 };
14067 value = (
pm_node_t *) pm_constant_read_node_create(parser, &constant);
14072 if (identifier.
end[-1] ==
'!' || identifier.
end[-1] ==
'?') {
14073 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, identifier, PM_ERR_INVALID_LOCAL_VARIABLE_READ);
14075 depth = pm_parser_local_depth(parser, &identifier);
14079 value = (
pm_node_t *) pm_call_node_variable_call_create(parser, &identifier);
14081 value = (
pm_node_t *) pm_local_variable_read_node_create(parser, &identifier, (uint32_t) depth);
14086 value = (
pm_node_t *) pm_implicit_node_create(parser, value);
14089 element = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
14093 pm_node_t *key = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_HASH_KEY, (uint16_t) (depth + 1));
14097 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
14098 pm_node_flag_set(key, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
14101 pm_hash_key_static_literals_add(parser, literals, key);
14104 if (pm_symbol_node_label_p(key)) {
14105 operator = not_provided(parser);
14107 expect1(parser, PM_TOKEN_EQUAL_GREATER, PM_ERR_HASH_ROCKET);
14111 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
14112 element = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
14117 if (PM_NODE_TYPE_P(node, PM_HASH_NODE)) {
14124 if (!accept1(parser, PM_TOKEN_COMMA))
break;
14128 if (match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL))
continue;
14132 if (token_begins_expression_p(parser->
current.type))
continue;
14138 return contains_keyword_splat;
14147 arguments->
arguments = pm_arguments_node_create(parser);
14150 pm_arguments_node_arguments_append(arguments->
arguments, argument);
14157parse_arguments(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_forwarding, pm_token_type_t terminator, uint16_t depth) {
14158 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].
left;
14163 match2(parser, terminator, PM_TOKEN_EOF) ||
14164 (binding_power != PM_BINDING_POWER_UNSET && binding_power < PM_BINDING_POWER_RANGE) ||
14170 bool parsed_first_argument =
false;
14171 bool parsed_bare_hash =
false;
14172 bool parsed_block_argument =
false;
14173 bool parsed_forwarding_arguments =
false;
14175 while (!match1(parser, PM_TOKEN_EOF)) {
14176 if (parsed_forwarding_arguments) {
14177 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES);
14182 switch (parser->
current.type) {
14183 case PM_TOKEN_USTAR_STAR:
14184 case PM_TOKEN_LABEL: {
14185 if (parsed_bare_hash) {
14186 pm_parser_err_current(parser, PM_ERR_ARGUMENT_BARE_HASH);
14193 bool contains_keyword_splat = parse_assocs(parser, &hash_keys, (
pm_node_t *) hash, (uint16_t) (depth + 1));
14195 parse_arguments_append(parser, arguments, argument);
14197 pm_node_flags_t flags = PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
14198 if (contains_keyword_splat) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
14201 pm_static_literals_free(&hash_keys);
14202 parsed_bare_hash =
true;
14206 case PM_TOKEN_UAMPERSAND: {
14207 parser_lex(parser);
14211 if (token_begins_expression_p(parser->
current.type)) {
14212 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14214 pm_parser_scope_forwarding_block_check(parser, &
operator);
14217 argument = (
pm_node_t *) pm_block_argument_node_create(parser, &
operator, expression);
14218 if (parsed_block_argument) {
14219 parse_arguments_append(parser, arguments, argument);
14221 arguments->
block = argument;
14224 if (match1(parser, PM_TOKEN_COMMA)) {
14225 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK);
14228 parsed_block_argument =
true;
14231 case PM_TOKEN_USTAR: {
14232 parser_lex(parser);
14235 if (match4(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_SEMICOLON, PM_TOKEN_BRACKET_RIGHT)) {
14236 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
14237 argument = (
pm_node_t *) pm_splat_node_create(parser, &
operator, NULL);
14238 if (parsed_bare_hash) {
14239 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
14242 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT, (uint16_t) (depth + 1));
14244 if (parsed_bare_hash) {
14245 pm_parser_err(parser,
operator.start, expression->
location.
end, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
14248 argument = (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
14251 parse_arguments_append(parser, arguments, argument);
14254 case PM_TOKEN_UDOT_DOT_DOT: {
14255 if (accepts_forwarding) {
14256 parser_lex(parser);
14258 if (token_begins_expression_p(parser->
current.type)) {
14263 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_RANGE,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
14268 if (PM_NODE_TYPE_P(right, PM_RANGE_NODE)) {
14270 pm_parser_err(parser, range->operator_loc.start, range->operator_loc.end, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
14273 argument = (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
14275 pm_parser_scope_forwarding_all_check(parser, &parser->
previous);
14276 if (parsed_first_argument && terminator == PM_TOKEN_EOF) {
14277 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORWARDING_UNBOUND);
14280 argument = (
pm_node_t *) pm_forwarding_arguments_node_create(parser, &parser->
previous);
14281 parse_arguments_append(parser, arguments, argument);
14282 pm_node_flag_set((
pm_node_t *) arguments->
arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING);
14284 parsed_forwarding_arguments =
true;
14291 if (argument == NULL) {
14292 argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, !parsed_first_argument,
true, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14295 bool contains_keywords =
false;
14296 bool contains_keyword_splat =
false;
14298 if (pm_symbol_node_label_p(argument) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
14299 if (parsed_bare_hash) {
14300 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
14304 if (parser->
previous.
type == PM_TOKEN_EQUAL_GREATER) {
14307 operator = not_provided(parser);
14311 contains_keywords =
true;
14315 pm_hash_key_static_literals_add(parser, &hash_keys, argument);
14318 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
14319 argument = (
pm_node_t *) pm_assoc_node_create(parser, argument, &
operator, value);
14321 pm_keyword_hash_node_elements_append(bare_hash, argument);
14325 if (accept1(parser, PM_TOKEN_COMMA) && (
14326 token_begins_expression_p(parser->
current.type) ||
14327 match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL)
14329 contains_keyword_splat = parse_assocs(parser, &hash_keys, (
pm_node_t *) bare_hash, (uint16_t) (depth + 1));
14332 pm_static_literals_free(&hash_keys);
14333 parsed_bare_hash =
true;
14336 parse_arguments_append(parser, arguments, argument);
14338 pm_node_flags_t flags = 0;
14339 if (contains_keywords) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
14340 if (contains_keyword_splat) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
14347 parsed_first_argument =
true;
14350 if (PM_NODE_TYPE_P(argument, PM_MISSING_NODE) || parser->
recovering)
break;
14355 bool accepted_newline =
false;
14356 if (terminator != PM_TOKEN_EOF) {
14357 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
14360 if (parser->
previous.
type == PM_TOKEN_COMMA && parsed_bare_hash) {
14364 }
else if (accept1(parser, PM_TOKEN_COMMA)) {
14367 if (accepted_newline) {
14368 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14378 if (match1(parser, terminator))
break;
14393parse_required_destructured_parameter(
pm_parser_t *parser) {
14394 expect1(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_ERR_EXPECT_LPAREN_REQ_PARAMETER);
14397 pm_multi_target_node_opening_set(node, &parser->
previous);
14406 if (node->
lefts.
size > 0 && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
14408 pm_multi_target_node_targets_append(parser, node, param);
14409 pm_parser_err_current(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14413 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
14414 param = (
pm_node_t *) parse_required_destructured_parameter(parser);
14415 }
else if (accept1(parser, PM_TOKEN_USTAR)) {
14419 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14421 value = (
pm_node_t *) pm_required_parameter_node_create(parser, &name);
14422 if (pm_parser_parameter_name_check(parser, &name)) {
14423 pm_node_flag_set_repeated_parameter(value);
14425 pm_parser_local_add_token(parser, &name, 1);
14428 param = (
pm_node_t *) pm_splat_node_create(parser, &star, value);
14430 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EXPECT_IDENT_REQ_PARAMETER);
14433 param = (
pm_node_t *) pm_required_parameter_node_create(parser, &name);
14434 if (pm_parser_parameter_name_check(parser, &name)) {
14435 pm_node_flag_set_repeated_parameter(param);
14437 pm_parser_local_add_token(parser, &name, 1);
14440 pm_multi_target_node_targets_append(parser, node, param);
14441 }
while (accept1(parser, PM_TOKEN_COMMA));
14443 accept1(parser, PM_TOKEN_NEWLINE);
14444 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN_REQ_PARAMETER);
14445 pm_multi_target_node_closing_set(node, &parser->
previous);
14455 PM_PARAMETERS_NO_CHANGE = 0,
14456 PM_PARAMETERS_ORDER_NOTHING_AFTER = 1,
14457 PM_PARAMETERS_ORDER_KEYWORDS_REST,
14458 PM_PARAMETERS_ORDER_KEYWORDS,
14459 PM_PARAMETERS_ORDER_REST,
14460 PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14461 PM_PARAMETERS_ORDER_OPTIONAL,
14462 PM_PARAMETERS_ORDER_NAMED,
14463 PM_PARAMETERS_ORDER_NONE,
14464} pm_parameters_order_t;
14469static pm_parameters_order_t parameters_ordering[PM_TOKEN_MAXIMUM] = {
14470 [0] = PM_PARAMETERS_NO_CHANGE,
14471 [PM_TOKEN_UAMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14472 [PM_TOKEN_AMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14473 [PM_TOKEN_UDOT_DOT_DOT] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14474 [PM_TOKEN_IDENTIFIER] = PM_PARAMETERS_ORDER_NAMED,
14475 [PM_TOKEN_PARENTHESIS_LEFT] = PM_PARAMETERS_ORDER_NAMED,
14476 [PM_TOKEN_EQUAL] = PM_PARAMETERS_ORDER_OPTIONAL,
14477 [PM_TOKEN_LABEL] = PM_PARAMETERS_ORDER_KEYWORDS,
14478 [PM_TOKEN_USTAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14479 [PM_TOKEN_STAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14480 [PM_TOKEN_USTAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST,
14481 [PM_TOKEN_STAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST
14493 pm_parameters_order_t state = parameters_ordering[token->type];
14494 if (state == PM_PARAMETERS_NO_CHANGE)
return true;
14498 if (*current == PM_PARAMETERS_ORDER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14499 *current = PM_PARAMETERS_ORDER_AFTER_OPTIONAL;
14501 }
else if (*current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14505 if (token->type == PM_TOKEN_USTAR && *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14506 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_STAR);
14508 }
else if (token->type == PM_TOKEN_UDOT_DOT_DOT && (*current >= PM_PARAMETERS_ORDER_KEYWORDS_REST && *current <= PM_PARAMETERS_ORDER_AFTER_OPTIONAL)) {
14509 pm_parser_err_token(parser, token, *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL ? PM_ERR_PARAMETER_FORWARDING_AFTER_REST : PM_ERR_PARAMETER_ORDER);
14511 }
else if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
14513 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_ORDER);
14517 if (state < *current) *current = state;
14527 pm_binding_power_t binding_power,
14528 bool uses_parentheses,
14529 bool allows_trailing_comma,
14530 bool allows_forwarding_parameters,
14531 bool accepts_blocks_in_defaults,
14535 pm_do_loop_stack_push(parser,
false);
14538 pm_parameters_order_t order = PM_PARAMETERS_ORDER_NONE;
14541 bool parsing =
true;
14543 switch (parser->
current.type) {
14544 case PM_TOKEN_PARENTHESIS_LEFT: {
14545 update_parameter_state(parser, &parser->
current, &order);
14548 if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14549 pm_parameters_node_requireds_append(params, param);
14551 pm_parameters_node_posts_append(params, param);
14555 case PM_TOKEN_UAMPERSAND:
14556 case PM_TOKEN_AMPERSAND: {
14557 update_parameter_state(parser, &parser->
current, &order);
14558 parser_lex(parser);
14563 bool repeated =
false;
14564 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14566 repeated = pm_parser_parameter_name_check(parser, &name);
14567 pm_parser_local_add_token(parser, &name, 1);
14569 name = not_provided(parser);
14575 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14577 if (params->
block == NULL) {
14578 pm_parameters_node_block_set(params, param);
14580 pm_parser_err_node(parser, (
pm_node_t *) param, PM_ERR_PARAMETER_BLOCK_MULTI);
14581 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14586 case PM_TOKEN_UDOT_DOT_DOT: {
14587 if (!allows_forwarding_parameters) {
14588 pm_parser_err_current(parser, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
14591 bool succeeded = update_parameter_state(parser, &parser->
current, &order);
14592 parser_lex(parser);
14601 pm_parameters_node_posts_append(params, keyword_rest);
14602 if (succeeded) pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD);
14606 pm_parameters_node_keyword_rest_set(params, (
pm_node_t *) param);
14609 case PM_TOKEN_CLASS_VARIABLE:
14610 case PM_TOKEN_IDENTIFIER:
14611 case PM_TOKEN_CONSTANT:
14612 case PM_TOKEN_INSTANCE_VARIABLE:
14613 case PM_TOKEN_GLOBAL_VARIABLE:
14614 case PM_TOKEN_METHOD_NAME: {
14615 parser_lex(parser);
14617 case PM_TOKEN_CONSTANT:
14618 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14620 case PM_TOKEN_INSTANCE_VARIABLE:
14621 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
14623 case PM_TOKEN_GLOBAL_VARIABLE:
14624 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
14626 case PM_TOKEN_CLASS_VARIABLE:
14627 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
14629 case PM_TOKEN_METHOD_NAME:
14630 pm_parser_err_previous(parser, PM_ERR_PARAMETER_METHOD_NAME);
14635 if (parser->
current.type == PM_TOKEN_EQUAL) {
14636 update_parameter_state(parser, &parser->
current, &order);
14638 update_parameter_state(parser, &parser->
previous, &order);
14642 bool repeated = pm_parser_parameter_name_check(parser, &name);
14643 pm_parser_local_add_token(parser, &name, 1);
14645 if (match1(parser, PM_TOKEN_EQUAL)) {
14648 parser_lex(parser);
14653 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14654 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
14655 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14660 pm_node_flag_set_repeated_parameter((
pm_node_t *) param);
14662 pm_parameters_node_optionals_append(params, param);
14668 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, name, PM_ERR_PARAMETER_CIRCULAR);
14671 context_pop(parser);
14680 }
else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14683 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14685 pm_parameters_node_requireds_append(params, (
pm_node_t *) param);
14689 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14691 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14696 case PM_TOKEN_LABEL: {
14697 if (!uses_parentheses && !in_block) parser->
in_keyword_arg =
true;
14698 update_parameter_state(parser, &parser->
current, &order);
14701 parser_lex(parser);
14708 pm_parser_err(parser, local.
start, local.
end, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14709 }
else if (local.
end[-1] ==
'!' || local.
end[-1] ==
'?') {
14710 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
14713 bool repeated = pm_parser_parameter_name_check(parser, &local);
14714 pm_parser_local_add_token(parser, &local, 1);
14716 switch (parser->
current.type) {
14717 case PM_TOKEN_COMMA:
14718 case PM_TOKEN_PARENTHESIS_RIGHT:
14719 case PM_TOKEN_PIPE: {
14720 context_pop(parser);
14722 pm_node_t *param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14724 pm_node_flag_set_repeated_parameter(param);
14727 pm_parameters_node_keywords_append(params, param);
14730 case PM_TOKEN_SEMICOLON:
14731 case PM_TOKEN_NEWLINE: {
14732 context_pop(parser);
14734 if (uses_parentheses) {
14739 pm_node_t *param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14741 pm_node_flag_set_repeated_parameter(param);
14744 pm_parameters_node_keywords_append(params, param);
14750 if (token_begins_expression_p(parser->
current.type)) {
14754 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14755 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT_KW, (uint16_t) (depth + 1));
14756 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14759 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_PARAMETER_CIRCULAR);
14762 param = (
pm_node_t *) pm_optional_keyword_parameter_node_create(parser, &name, value);
14765 param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14769 pm_node_flag_set_repeated_parameter(param);
14772 context_pop(parser);
14773 pm_parameters_node_keywords_append(params, param);
14788 case PM_TOKEN_USTAR:
14789 case PM_TOKEN_STAR: {
14790 update_parameter_state(parser, &parser->
current, &order);
14791 parser_lex(parser);
14795 bool repeated =
false;
14797 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14799 repeated = pm_parser_parameter_name_check(parser, &name);
14800 pm_parser_local_add_token(parser, &name, 1);
14802 name = not_provided(parser);
14806 pm_node_t *param = (
pm_node_t *) pm_rest_parameter_node_create(parser, &
operator, &name);
14808 pm_node_flag_set_repeated_parameter(param);
14811 if (params->
rest == NULL) {
14812 pm_parameters_node_rest_set(params, param);
14814 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_SPLAT_MULTI);
14815 pm_parameters_node_posts_append(params, param);
14820 case PM_TOKEN_STAR_STAR:
14821 case PM_TOKEN_USTAR_STAR: {
14822 pm_parameters_order_t previous_order = order;
14823 update_parameter_state(parser, &parser->
current, &order);
14824 parser_lex(parser);
14829 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
14830 if (previous_order <= PM_PARAMETERS_ORDER_KEYWORDS) {
14831 pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_NO_KW);
14834 param = (
pm_node_t *) pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous);
14838 bool repeated =
false;
14839 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14841 repeated = pm_parser_parameter_name_check(parser, &name);
14842 pm_parser_local_add_token(parser, &name, 1);
14844 name = not_provided(parser);
14848 param = (
pm_node_t *) pm_keyword_rest_parameter_node_create(parser, &
operator, &name);
14850 pm_node_flag_set_repeated_parameter(param);
14855 pm_parameters_node_keyword_rest_set(params, param);
14857 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI);
14858 pm_parameters_node_posts_append(params, param);
14865 if (allows_trailing_comma && order >= PM_PARAMETERS_ORDER_NAMED) {
14870 if (params->
rest == NULL) {
14871 pm_parameters_node_rest_set(params, param);
14873 pm_parser_err_node(parser, (
pm_node_t *) param, PM_ERR_PARAMETER_SPLAT_MULTI);
14874 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14877 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14888 if (!parsing)
break;
14890 bool accepted_newline =
false;
14891 if (uses_parentheses) {
14892 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
14895 if (accept1(parser, PM_TOKEN_COMMA)) {
14898 if (accepted_newline) {
14899 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14907 pm_do_loop_stack_pop(parser);
14911 pm_node_destroy(parser, (
pm_node_t *) params);
14943token_column(
const pm_parser_t *parser,
size_t newline_index,
const pm_token_t *token,
bool break_on_non_space) {
14945 const uint8_t *end = token->start;
14949 newline_index == 0 &&
14950 parser->
start[0] == 0xef &&
14951 parser->
start[1] == 0xbb &&
14952 parser->
start[2] == 0xbf
14955 int64_t column = 0;
14956 for (; cursor < end; cursor++) {
14959 column = ((column / PM_TAB_WHITESPACE_SIZE) + 1) * PM_TAB_WHITESPACE_SIZE;
14966 if (break_on_non_space)
return -1;
14979parser_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) {
14984 size_t closing_newline_index = token_newline_index(parser);
14985 if (opening_newline_index == closing_newline_index)
return;
14990 int64_t opening_column = token_column(parser, opening_newline_index, opening_token, !if_after_else);
14991 if (!if_after_else && (opening_column == -1))
return;
14998 int64_t closing_column = token_column(parser, closing_newline_index, closing_token,
true);
14999 if ((closing_column == -1) || (opening_column == closing_column))
return;
15003 if (allow_indent && (closing_column > opening_column))
return;
15006 PM_PARSER_WARN_FORMAT(
15008 closing_token->
start,
15009 closing_token->
end,
15010 PM_WARN_INDENTATION_MISMATCH,
15011 (
int) (closing_token->
end - closing_token->
start),
15012 (
const char *) closing_token->
start,
15013 (
int) (opening_token->
end - opening_token->
start),
15014 (
const char *) opening_token->
start,
15015 ((int32_t) opening_newline_index) + parser->
start_line
15020 PM_RESCUES_BEGIN = 1,
15027} pm_rescues_type_t;
15037 while (match1(parser, PM_TOKEN_KEYWORD_RESCUE)) {
15038 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15039 parser_lex(parser);
15043 switch (parser->
current.type) {
15044 case PM_TOKEN_EQUAL_GREATER: {
15048 parser_lex(parser);
15049 pm_rescue_node_operator_set(rescue, &parser->
previous);
15051 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15052 reference = parse_target(parser, reference,
false,
false);
15054 pm_rescue_node_reference_set(rescue, reference);
15057 case PM_TOKEN_NEWLINE:
15058 case PM_TOKEN_SEMICOLON:
15059 case PM_TOKEN_KEYWORD_THEN:
15064 if (token_begins_expression_p(parser->
current.type) || match1(parser, PM_TOKEN_USTAR)) {
15069 pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED,
false, PM_ERR_RESCUE_EXPRESSION, (uint16_t) (depth + 1));
15070 pm_rescue_node_exceptions_append(rescue, expression);
15074 if (match3(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_THEN))
break;
15078 if (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
15079 pm_rescue_node_operator_set(rescue, &parser->
previous);
15081 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15082 reference = parse_target(parser, reference,
false,
false);
15084 pm_rescue_node_reference_set(rescue, reference);
15087 }
while (accept1(parser, PM_TOKEN_COMMA));
15092 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
15093 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
15097 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_RESCUE_TERM);
15101 if (!match3(parser, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_END)) {
15102 pm_accepts_block_stack_push(parser,
true);
15117 if (statements != NULL) pm_rescue_node_statements_set(rescue, statements);
15119 pm_accepts_block_stack_pop(parser);
15120 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15123 if (current == NULL) {
15124 pm_begin_node_rescue_clause_set(parent_node, rescue);
15126 pm_rescue_node_subsequent_set(current, rescue);
15135 if (current != NULL) {
15139 while (clause != NULL) {
15146 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
15147 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15148 opening_newline_index = token_newline_index(parser);
15150 else_keyword = parser->
current;
15151 opening = &else_keyword;
15153 parser_lex(parser);
15154 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15157 if (!match2(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_ENSURE)) {
15158 pm_accepts_block_stack_push(parser,
true);
15172 else_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15173 pm_accepts_block_stack_pop(parser);
15175 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15178 pm_else_node_t *else_clause = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
current);
15179 pm_begin_node_else_clause_set(parent_node, else_clause);
15183 if (current == NULL) pm_parser_err_node(parser, (
pm_node_t *) else_clause, PM_ERR_BEGIN_LONELY_ELSE);
15186 if (match1(parser, PM_TOKEN_KEYWORD_ENSURE)) {
15187 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15190 parser_lex(parser);
15191 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15194 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
15195 pm_accepts_block_stack_push(parser,
true);
15209 ensure_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15210 pm_accepts_block_stack_pop(parser);
15212 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15215 pm_ensure_node_t *ensure_clause = pm_ensure_node_create(parser, &ensure_keyword, ensure_statements, &parser->
current);
15216 pm_begin_node_ensure_clause_set(parent_node, ensure_clause);
15219 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
15220 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15221 pm_begin_node_end_keyword_set(parent_node, &parser->
current);
15224 pm_begin_node_end_keyword_set(parent_node, &end_keyword);
15234 pm_token_t begin_keyword = not_provided(parser);
15235 pm_begin_node_t *node = pm_begin_node_create(parser, &begin_keyword, statements);
15237 parse_rescues(parser, opening_newline_index, opening, node,
type, (uint16_t) (depth + 1));
15247parse_block_parameters(
15249 bool allows_trailing_comma,
15251 bool is_lambda_literal,
15252 bool accepts_blocks_in_defaults,
15256 if (!match1(parser, PM_TOKEN_SEMICOLON)) {
15257 parameters = parse_parameters(
15259 is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
15261 allows_trailing_comma,
15263 accepts_blocks_in_defaults,
15265 (uint16_t) (depth + 1)
15270 if ((opening->
type != PM_TOKEN_NOT_PROVIDED)) {
15271 accept1(parser, PM_TOKEN_NEWLINE);
15273 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
15275 switch (parser->
current.type) {
15276 case PM_TOKEN_CONSTANT:
15277 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
15278 parser_lex(parser);
15280 case PM_TOKEN_INSTANCE_VARIABLE:
15281 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
15282 parser_lex(parser);
15284 case PM_TOKEN_GLOBAL_VARIABLE:
15285 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
15286 parser_lex(parser);
15288 case PM_TOKEN_CLASS_VARIABLE:
15289 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
15290 parser_lex(parser);
15293 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_BLOCK_PARAM_LOCAL_VARIABLE);
15297 bool repeated = pm_parser_parameter_name_check(parser, &parser->
previous);
15298 pm_parser_local_add_token(parser, &parser->
previous, 1);
15301 if (repeated) pm_node_flag_set_repeated_parameter((
pm_node_t *) local);
15303 pm_block_parameters_node_append_local(block_parameters, local);
15304 }
while (accept1(parser, PM_TOKEN_COMMA));
15308 return block_parameters;
15316outer_scope_using_numbered_parameters_p(
pm_parser_t *parser) {
15318 if (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND)
return true;
15329static const char *
const pm_numbered_parameter_names[] = {
15330 "_1",
"_2",
"_3",
"_4",
"_5",
"_6",
"_7",
"_8",
"_9"
15344 if (parameters != NULL) {
15346 if (implicit_parameters->
size > 0) {
15349 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
15350 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_ORDINARY);
15351 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
15352 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_ORDINARY);
15354 assert(
false &&
"unreachable");
15363 if (implicit_parameters->
size == 0) {
15370 uint8_t numbered_parameter = 0;
15371 bool it_parameter =
false;
15373 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
15376 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
15377 if (it_parameter) {
15378 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_IT);
15379 }
else if (outer_scope_using_numbered_parameters_p(parser)) {
15380 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_OUTER_BLOCK);
15382 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK);
15384 numbered_parameter = MAX(numbered_parameter, (uint8_t) (node->
location.
start[1] -
'0'));
15386 assert(
false &&
"unreachable");
15388 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
15389 if (numbered_parameter > 0) {
15390 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_NUMBERED);
15392 it_parameter =
true;
15397 if (numbered_parameter > 0) {
15401 scope->
parameters |= PM_SCOPE_PARAMETERS_NUMBERED_INNER;
15405 return (
pm_node_t *) pm_numbered_parameters_node_create(parser, &location, numbered_parameter);
15408 if (it_parameter) {
15409 return (
pm_node_t *) pm_it_parameters_node_create(parser, opening, closing);
15419parse_block(
pm_parser_t *parser, uint16_t depth) {
15421 accept1(parser, PM_TOKEN_NEWLINE);
15423 pm_accepts_block_stack_push(parser,
true);
15424 pm_parser_scope_push(parser,
false);
15428 if (accept1(parser, PM_TOKEN_PIPE)) {
15430 if (match1(parser, PM_TOKEN_PIPE)) {
15431 block_parameters = pm_block_parameters_node_create(parser, NULL, &block_parameters_opening);
15433 parser_lex(parser);
15435 block_parameters = parse_block_parameters(parser,
true, &block_parameters_opening,
false,
true, (uint16_t) (depth + 1));
15436 accept1(parser, PM_TOKEN_NEWLINE);
15438 expect1(parser, PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM);
15441 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
15444 accept1(parser, PM_TOKEN_NEWLINE);
15447 if (opening.
type == PM_TOKEN_BRACE_LEFT) {
15448 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
15452 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE);
15454 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
15455 if (!match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE)) {
15456 pm_accepts_block_stack_push(parser,
true);
15458 pm_accepts_block_stack_pop(parser);
15461 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
15462 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
15463 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));
15467 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END);
15471 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
15474 pm_parser_scope_pop(parser);
15475 pm_accepts_block_stack_pop(parser);
15477 return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->
previous);
15486parse_arguments_list(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_block,
bool accepts_command_call, uint16_t depth) {
15487 bool found =
false;
15489 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
15493 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
15496 pm_accepts_block_stack_push(parser,
true);
15497 parse_arguments(parser, arguments, accepts_block, PM_TOKEN_PARENTHESIS_RIGHT, (uint16_t) (depth + 1));
15499 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
15505 pm_accepts_block_stack_pop(parser);
15508 }
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)) {
15510 pm_accepts_block_stack_push(parser,
false);
15515 parse_arguments(parser, arguments, accepts_block, PM_TOKEN_EOF, (uint16_t) (depth + 1));
15520 if (parser->
previous.
type == PM_TOKEN_COMMA && !match1(parser, PM_TOKEN_SEMICOLON)) {
15524 pm_accepts_block_stack_pop(parser);
15530 if (accepts_block) {
15533 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
15535 block = parse_block(parser, (uint16_t) (depth + 1));
15536 pm_arguments_validate_block(parser, arguments, block);
15537 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
15539 block = parse_block(parser, (uint16_t) (depth + 1));
15542 if (block != NULL) {
15546 pm_parser_err_node(parser, (
pm_node_t *) block, PM_ERR_ARGUMENT_BLOCK_MULTI);
15548 if (arguments->
block != NULL) {
15550 arguments->
arguments = pm_arguments_node_create(parser);
15552 pm_arguments_node_arguments_append(arguments->
arguments, arguments->
block);
15568 bool in_sclass =
false;
15570 switch (context_node->
context) {
15615 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15637 assert(
false &&
"unreachable");
15642 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15653 switch (context_node->
context) {
15727 assert(
false &&
"unreachable");
15741 return previous_block_exits;
15755 switch (PM_NODE_TYPE(block_exit)) {
15756 case PM_BREAK_NODE:
type =
"break";
break;
15757 case PM_NEXT_NODE:
type =
"next";
break;
15758 case PM_REDO_NODE:
type =
"redo";
break;
15759 default: assert(
false &&
"unreachable");
type =
"";
break;
15762 PM_PARSER_ERR_NODE_FORMAT(parser, block_exit, PM_ERR_INVALID_BLOCK_EXIT,
type);
15774 if (match2(parser, PM_TOKEN_KEYWORD_WHILE_MODIFIER, PM_TOKEN_KEYWORD_UNTIL_MODIFIER)) {
15779 }
else if (previous_block_exits != NULL) {
15791 flush_block_exits(parser, previous_block_exits);
15799 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, error_id, (uint16_t) (depth + 1));
15802 bool predicate_closed = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15804 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
15805 predicate_closed =
true;
15809 if (!predicate_closed) {
15810 pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
15813 context_pop(parser);
15818parse_conditional(
pm_parser_t *parser,
pm_context_t context,
size_t opening_newline_index,
bool if_after_else, uint16_t depth) {
15820 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
15823 pm_token_t then_keyword = not_provided(parser);
15825 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context, &then_keyword, (uint16_t) (depth + 1));
15828 if (!match3(parser, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
15829 pm_accepts_block_stack_push(parser,
true);
15830 statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15831 pm_accepts_block_stack_pop(parser);
15832 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15835 pm_token_t end_keyword = not_provided(parser);
15840 parent = (
pm_node_t *) pm_if_node_create(parser, &keyword, predicate, &then_keyword, statements, NULL, &end_keyword);
15843 parent = (
pm_node_t *) pm_unless_node_create(parser, &keyword, predicate, &then_keyword, statements);
15846 assert(
false &&
"unreachable");
15855 while (match1(parser, PM_TOKEN_KEYWORD_ELSIF)) {
15856 if (parser_end_of_line_p(parser)) {
15857 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
15860 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15862 parser_lex(parser);
15864 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER,
PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1));
15865 pm_accepts_block_stack_push(parser,
true);
15868 pm_accepts_block_stack_pop(parser);
15869 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15871 pm_node_t *elsif = (
pm_node_t *) pm_if_node_create(parser, &elsif_keyword, predicate, &then_keyword, statements, NULL, &end_keyword);
15877 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
15878 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15879 opening_newline_index = token_newline_index(parser);
15881 parser_lex(parser);
15884 pm_accepts_block_stack_push(parser,
true);
15886 pm_accepts_block_stack_pop(parser);
15888 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15889 parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword,
false,
false);
15890 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE);
15892 pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
previous);
15902 assert(
false &&
"unreachable");
15906 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else,
false);
15907 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM);
15914 bool recursing =
true;
15916 while (recursing) {
15917 switch (PM_NODE_TYPE(current)) {
15921 recursing = current != NULL;
15939 assert(
false &&
"unreachable");
15943 pop_block_exits(parser, previous_block_exits);
15944 pm_node_list_free(¤t_block_exits);
15953#define PM_CASE_KEYWORD PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15954 case PM_TOKEN_KEYWORD_ALIAS: case PM_TOKEN_KEYWORD_AND: case PM_TOKEN_KEYWORD_BEGIN: case PM_TOKEN_KEYWORD_BEGIN_UPCASE: \
15955 case PM_TOKEN_KEYWORD_BREAK: case PM_TOKEN_KEYWORD_CASE: case PM_TOKEN_KEYWORD_CLASS: case PM_TOKEN_KEYWORD_DEF: \
15956 case PM_TOKEN_KEYWORD_DEFINED: case PM_TOKEN_KEYWORD_DO: case PM_TOKEN_KEYWORD_DO_LOOP: case PM_TOKEN_KEYWORD_ELSE: \
15957 case PM_TOKEN_KEYWORD_ELSIF: case PM_TOKEN_KEYWORD_END: case PM_TOKEN_KEYWORD_END_UPCASE: case PM_TOKEN_KEYWORD_ENSURE: \
15958 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD_FOR: case PM_TOKEN_KEYWORD_IF: case PM_TOKEN_KEYWORD_IN: \
15959 case PM_TOKEN_KEYWORD_MODULE: case PM_TOKEN_KEYWORD_NEXT: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_NOT: \
15960 case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_KEYWORD_REDO: case PM_TOKEN_KEYWORD_RESCUE: case PM_TOKEN_KEYWORD_RETRY: \
15961 case PM_TOKEN_KEYWORD_RETURN: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_SUPER: case PM_TOKEN_KEYWORD_THEN: \
15962 case PM_TOKEN_KEYWORD_TRUE: case PM_TOKEN_KEYWORD_UNDEF: case PM_TOKEN_KEYWORD_UNLESS: case PM_TOKEN_KEYWORD_UNTIL: \
15963 case PM_TOKEN_KEYWORD_WHEN: case PM_TOKEN_KEYWORD_WHILE: case PM_TOKEN_KEYWORD_YIELD
15969#define PM_CASE_OPERATOR PM_TOKEN_AMPERSAND: case PM_TOKEN_BACKTICK: case PM_TOKEN_BANG_EQUAL: \
15970 case PM_TOKEN_BANG_TILDE: case PM_TOKEN_BANG: case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL: \
15971 case PM_TOKEN_BRACKET_LEFT_RIGHT: case PM_TOKEN_CARET: case PM_TOKEN_EQUAL_EQUAL_EQUAL: case PM_TOKEN_EQUAL_EQUAL: \
15972 case PM_TOKEN_EQUAL_TILDE: case PM_TOKEN_GREATER_EQUAL: case PM_TOKEN_GREATER_GREATER: case PM_TOKEN_GREATER: \
15973 case PM_TOKEN_LESS_EQUAL_GREATER: case PM_TOKEN_LESS_EQUAL: case PM_TOKEN_LESS_LESS: case PM_TOKEN_LESS: \
15974 case PM_TOKEN_MINUS: case PM_TOKEN_PERCENT: case PM_TOKEN_PIPE: case PM_TOKEN_PLUS: case PM_TOKEN_SLASH: \
15975 case PM_TOKEN_STAR_STAR: case PM_TOKEN_STAR: case PM_TOKEN_TILDE: case PM_TOKEN_UAMPERSAND: case PM_TOKEN_UMINUS: \
15976 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_UPLUS: case PM_TOKEN_USTAR: case PM_TOKEN_USTAR_STAR
15983#define PM_CASE_PRIMITIVE PM_TOKEN_INTEGER: case PM_TOKEN_INTEGER_IMAGINARY: case PM_TOKEN_INTEGER_RATIONAL: \
15984 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: case PM_TOKEN_FLOAT: case PM_TOKEN_FLOAT_IMAGINARY: \
15985 case PM_TOKEN_FLOAT_RATIONAL: case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY: case PM_TOKEN_SYMBOL_BEGIN: \
15986 case PM_TOKEN_REGEXP_BEGIN: case PM_TOKEN_BACKTICK: case PM_TOKEN_PERCENT_LOWER_X: case PM_TOKEN_PERCENT_LOWER_I: \
15987 case PM_TOKEN_PERCENT_LOWER_W: case PM_TOKEN_PERCENT_UPPER_I: case PM_TOKEN_PERCENT_UPPER_W: \
15988 case PM_TOKEN_STRING_BEGIN: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_TRUE: \
15989 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15990 case PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_MINUS_GREATER: case PM_TOKEN_HEREDOC_START: \
15991 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_CHARACTER_LITERAL
15997#define PM_CASE_PARAMETER PM_TOKEN_UAMPERSAND: case PM_TOKEN_AMPERSAND: case PM_TOKEN_UDOT_DOT_DOT: \
15998 case PM_TOKEN_IDENTIFIER: case PM_TOKEN_LABEL: case PM_TOKEN_USTAR: case PM_TOKEN_STAR: case PM_TOKEN_STAR_STAR: \
15999 case PM_TOKEN_USTAR_STAR: case PM_TOKEN_CONSTANT: case PM_TOKEN_INSTANCE_VARIABLE: case PM_TOKEN_GLOBAL_VARIABLE: \
16000 case PM_TOKEN_CLASS_VARIABLE
16006#define PM_CASE_WRITABLE PM_CLASS_VARIABLE_READ_NODE: case PM_CONSTANT_PATH_NODE: \
16007 case PM_CONSTANT_READ_NODE: case PM_GLOBAL_VARIABLE_READ_NODE: case PM_LOCAL_VARIABLE_READ_NODE: \
16008 case PM_INSTANCE_VARIABLE_READ_NODE: case PM_MULTI_TARGET_NODE: case PM_BACK_REFERENCE_READ_NODE: \
16009 case PM_NUMBERED_REFERENCE_READ_NODE: case PM_IT_LOCAL_VARIABLE_READ_NODE
16013PM_STATIC_ASSERT(__LINE__, ((
int) PM_STRING_FLAGS_FORCED_UTF8_ENCODING) == ((
int) PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING),
"Expected the flags to match.");
16019static inline pm_node_flags_t
16020parse_unescaped_encoding(
const pm_parser_t *parser) {
16025 return PM_STRING_FLAGS_FORCED_UTF8_ENCODING;
16031 return PM_STRING_FLAGS_FORCED_BINARY_ENCODING;
16042parse_string_part(
pm_parser_t *parser, uint16_t depth) {
16043 switch (parser->
current.type) {
16050 case PM_TOKEN_STRING_CONTENT: {
16055 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16057 parser_lex(parser);
16066 case PM_TOKEN_EMBEXPR_BEGIN: {
16075 lex_state_set(parser, PM_LEX_STATE_BEG);
16076 parser_lex(parser);
16081 if (!match1(parser, PM_TOKEN_EMBEXPR_END)) {
16082 pm_accepts_block_stack_push(parser,
true);
16084 pm_accepts_block_stack_pop(parser);
16088 lex_state_set(parser, state);
16090 expect1(parser, PM_TOKEN_EMBEXPR_END, PM_ERR_EMBEXPR_END);
16096 if (statements != NULL && statements->
body.
size == 1) {
16097 pm_node_flag_unset(statements->
body.
nodes[0], PM_NODE_FLAG_NEWLINE);
16100 return (
pm_node_t *) pm_embedded_statements_node_create(parser, &opening, statements, &closing);
16109 case PM_TOKEN_EMBVAR: {
16114 lex_state_set(parser, PM_LEX_STATE_BEG);
16115 parser_lex(parser);
16120 switch (parser->
current.type) {
16123 case PM_TOKEN_BACK_REFERENCE:
16124 parser_lex(parser);
16125 variable = (
pm_node_t *) pm_back_reference_read_node_create(parser, &parser->
previous);
16129 case PM_TOKEN_NUMBERED_REFERENCE:
16130 parser_lex(parser);
16131 variable = (
pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->
previous);
16135 case PM_TOKEN_GLOBAL_VARIABLE:
16136 parser_lex(parser);
16137 variable = (
pm_node_t *) pm_global_variable_read_node_create(parser, &parser->
previous);
16141 case PM_TOKEN_INSTANCE_VARIABLE:
16142 parser_lex(parser);
16143 variable = (
pm_node_t *) pm_instance_variable_read_node_create(parser, &parser->
previous);
16147 case PM_TOKEN_CLASS_VARIABLE:
16148 parser_lex(parser);
16149 variable = (
pm_node_t *) pm_class_variable_read_node_create(parser, &parser->
previous);
16155 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EMBVAR_INVALID);
16160 return (
pm_node_t *) pm_embedded_variable_node_create(parser, &
operator, variable);
16163 parser_lex(parser);
16164 pm_parser_err_previous(parser, PM_ERR_CANNOT_PARSE_STRING_PART);
16174static const uint8_t *
16175parse_operator_symbol_name(
const pm_token_t *name) {
16176 switch (name->
type) {
16177 case PM_TOKEN_TILDE:
16178 case PM_TOKEN_BANG:
16179 if (name->
end[-1] ==
'@')
return name->
end - 1;
16191 const uint8_t *end = parse_operator_symbol_name(&parser->
current);
16193 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16194 parser_lex(parser);
16197 pm_node_flag_set((
pm_node_t *) symbol, PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING);
16211 if (lex_mode->
mode != PM_LEX_STRING) {
16212 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16214 switch (parser->
current.type) {
16215 case PM_CASE_OPERATOR:
16216 return parse_operator_symbol(parser, &opening, next_state == PM_LEX_STATE_NONE ? PM_LEX_STATE_ENDFN : next_state);
16217 case PM_TOKEN_IDENTIFIER:
16218 case PM_TOKEN_CONSTANT:
16219 case PM_TOKEN_INSTANCE_VARIABLE:
16220 case PM_TOKEN_METHOD_NAME:
16221 case PM_TOKEN_CLASS_VARIABLE:
16222 case PM_TOKEN_GLOBAL_VARIABLE:
16223 case PM_TOKEN_NUMBERED_REFERENCE:
16224 case PM_TOKEN_BACK_REFERENCE:
16225 case PM_CASE_KEYWORD:
16226 parser_lex(parser);
16229 expect2(parser, PM_TOKEN_IDENTIFIER, PM_TOKEN_METHOD_NAME, PM_ERR_SYMBOL_INVALID);
16237 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16244 if (match1(parser, PM_TOKEN_STRING_END)) {
16245 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16246 parser_lex(parser);
16250 return (
pm_node_t *) pm_symbol_node_create(parser, &opening, &content, &closing);
16254 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
16258 if (part && PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16259 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16260 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16266 if (part) pm_interpolated_symbol_node_append(symbol, part);
16268 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16269 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16270 pm_interpolated_symbol_node_append(symbol, part);
16274 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16275 if (match1(parser, PM_TOKEN_EOF)) {
16276 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16278 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16281 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
16288 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16291 parser_lex(parser);
16302 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16306 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &unescaped);
16307 pm_interpolated_symbol_node_append(symbol, part);
16310 pm_interpolated_symbol_node_append(symbol, part);
16312 if (next_state != PM_LEX_STATE_NONE) {
16313 lex_state_set(parser, next_state);
16316 parser_lex(parser);
16317 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
16319 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
16324 pm_string_shared_init(&unescaped, content.
start, content.
end);
16327 if (next_state != PM_LEX_STATE_NONE) {
16328 lex_state_set(parser, next_state);
16331 if (match1(parser, PM_TOKEN_EOF)) {
16332 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_DYNAMIC);
16334 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
16337 return (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
false));
16345parse_undef_argument(
pm_parser_t *parser, uint16_t depth) {
16346 switch (parser->
current.type) {
16347 case PM_CASE_OPERATOR: {
16348 const pm_token_t opening = not_provided(parser);
16349 return parse_operator_symbol(parser, &opening, PM_LEX_STATE_NONE);
16351 case PM_CASE_KEYWORD:
16352 case PM_TOKEN_CONSTANT:
16353 case PM_TOKEN_IDENTIFIER:
16354 case PM_TOKEN_METHOD_NAME: {
16355 parser_lex(parser);
16362 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16366 case PM_TOKEN_SYMBOL_BEGIN: {
16368 parser_lex(parser);
16370 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16373 pm_parser_err_current(parser, PM_ERR_UNDEF_ARGUMENT);
16385parse_alias_argument(
pm_parser_t *parser,
bool first, uint16_t depth) {
16386 switch (parser->
current.type) {
16387 case PM_CASE_OPERATOR: {
16388 const pm_token_t opening = not_provided(parser);
16389 return parse_operator_symbol(parser, &opening, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
16391 case PM_CASE_KEYWORD:
16392 case PM_TOKEN_CONSTANT:
16393 case PM_TOKEN_IDENTIFIER:
16394 case PM_TOKEN_METHOD_NAME: {
16395 if (first) lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
16396 parser_lex(parser);
16403 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16407 case PM_TOKEN_SYMBOL_BEGIN: {
16409 parser_lex(parser);
16411 return parse_symbol(parser, &lex_mode, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16413 case PM_TOKEN_BACK_REFERENCE:
16414 parser_lex(parser);
16415 return (
pm_node_t *) pm_back_reference_read_node_create(parser, &parser->
previous);
16416 case PM_TOKEN_NUMBERED_REFERENCE:
16417 parser_lex(parser);
16418 return (
pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->
previous);
16419 case PM_TOKEN_GLOBAL_VARIABLE:
16420 parser_lex(parser);
16421 return (
pm_node_t *) pm_global_variable_read_node_create(parser, &parser->
previous);
16423 pm_parser_err_current(parser, PM_ERR_ALIAS_ARGUMENT);
16438 if (!is_numbered_param && ((depth = pm_parser_local_depth_constant_id(parser, name_id)) != -1)) {
16439 return (
pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, (uint32_t) depth,
false);
16443 if (!current_scope->
closed && !(current_scope->
parameters & PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED)) {
16444 if (is_numbered_param) {
16449 uint8_t maximum = (uint8_t) (parser->
previous.
start[1] -
'0');
16450 for (uint8_t number = 1; number <= maximum; number++) {
16451 pm_parser_local_add_constant(parser, pm_numbered_parameter_names[number - 1], 2);
16454 if (!match1(parser, PM_TOKEN_EQUAL)) {
16458 pm_node_t *node = (
pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, 0,
false);
16478 pm_node_flags_t flags = 0;
16480 if (!match1(parser, PM_TOKEN_PARENTHESIS_LEFT) && (parser->
previous.
end[-1] !=
'!') && (parser->
previous.
end[-1] !=
'?')) {
16481 pm_node_t *node = parse_variable(parser);
16482 if (node != NULL)
return node;
16483 flags |= PM_CALL_NODE_FLAGS_VARIABLE_CALL;
16487 pm_node_flag_set((
pm_node_t *)node, flags);
16498parse_method_definition_name(
pm_parser_t *parser) {
16499 switch (parser->
current.type) {
16500 case PM_CASE_KEYWORD:
16501 case PM_TOKEN_CONSTANT:
16502 case PM_TOKEN_METHOD_NAME:
16503 parser_lex(parser);
16505 case PM_TOKEN_IDENTIFIER:
16506 pm_refute_numbered_parameter(parser, parser->
current.start, parser->
current.end);
16507 parser_lex(parser);
16509 case PM_CASE_OPERATOR:
16510 lex_state_set(parser, PM_LEX_STATE_ENDFN);
16511 parser_lex(parser);
16520parse_heredoc_dedent_string(
pm_string_t *
string,
size_t common_whitespace) {
16523 pm_string_ensure_owned(
string);
16528 size_t dest_length = pm_string_length(
string);
16529 const uint8_t *source_cursor = (uint8_t *) string->
source;
16530 const uint8_t *source_end = source_cursor + dest_length;
16535 size_t trimmed_whitespace = 0;
16541 while ((source_cursor < source_end) && pm_char_is_inline_whitespace(*source_cursor) && trimmed_whitespace < common_whitespace) {
16542 if (*source_cursor ==
'\t') {
16543 trimmed_whitespace = (trimmed_whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
16544 if (trimmed_whitespace > common_whitespace)
break;
16546 trimmed_whitespace++;
16553 memmove((uint8_t *) string->source, source_cursor, (
size_t) (source_end - source_cursor));
16554 string->length = dest_length;
16564 bool dedent_next =
true;
16569 size_t write_index = 0;
16576 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE)) {
16577 nodes->
nodes[write_index++] = node;
16578 dedent_next =
false;
16584 parse_heredoc_dedent_string(&string_node->
unescaped, common_whitespace);
16588 pm_node_destroy(parser, node);
16590 nodes->
nodes[write_index++] = node;
16594 dedent_next =
true;
16597 nodes->
size = write_index;
16604parse_strings_empty_content(
const uint8_t *location) {
16605 return (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = location, .end = location };
16613 assert(parser->
current.type == PM_TOKEN_STRING_BEGIN);
16614 bool concating =
false;
16616 while (match1(parser, PM_TOKEN_STRING_BEGIN)) {
16622 assert(lex_mode->
mode == PM_LEX_STRING);
16624 bool label_allowed = lex_mode->
as.string.
label_allowed && accepts_label;
16627 parser_lex(parser);
16629 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16630 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16639 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16649 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16650 }
else if (!lex_interpolation) {
16656 if (match1(parser, PM_TOKEN_EOF)) {
16658 content = not_provided(parser);
16661 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_EXPECT_STRING_CONTENT);
16676 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16679 pm_token_t delimiters = not_provided(parser);
16680 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &delimiters, &content, &delimiters, &unescaped);
16681 pm_node_list_append(&parts, part);
16684 part = (
pm_node_t *) pm_string_node_create_current_string(parser, &delimiters, &parser->
current, &delimiters);
16685 pm_node_list_append(&parts, part);
16686 parser_lex(parser);
16687 }
while (match1(parser, PM_TOKEN_STRING_CONTENT));
16689 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16690 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16692 pm_node_list_free(&parts);
16693 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16694 node = (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true));
16695 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16696 }
else if (match1(parser, PM_TOKEN_EOF)) {
16697 pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
16698 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
16699 }
else if (accept1(parser, PM_TOKEN_STRING_END)) {
16700 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped);
16705 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped);
16707 }
else if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16714 parser_lex(parser);
16716 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16717 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
16718 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16724 if (!accept1(parser, PM_TOKEN_STRING_END)) {
16726 if (location > parser->
start && location[-1] ==
'\n') location--;
16727 pm_parser_err(parser, location, location, PM_ERR_STRING_LITERAL_EOF);
16732 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16733 node = (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true));
16734 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16739 pm_token_t string_opening = not_provided(parser);
16740 pm_token_t string_closing = not_provided(parser);
16742 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &string_opening, &parser->
previous, &string_closing, &unescaped);
16743 pm_node_flag_set(part, parse_unescaped_encoding(parser));
16744 pm_node_list_append(&parts, part);
16746 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16747 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16748 pm_node_list_append(&parts, part);
16752 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16753 node = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous);
16754 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16755 }
else if (match1(parser, PM_TOKEN_EOF)) {
16756 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16757 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current);
16759 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16760 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16763 pm_node_list_free(&parts);
16772 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16773 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16774 pm_node_list_append(&parts, part);
16778 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16779 node = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous);
16780 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16781 }
else if (match1(parser, PM_TOKEN_EOF)) {
16782 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16783 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current);
16785 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16786 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16789 pm_node_list_free(&parts);
16792 if (current == NULL) {
16796 if (PM_NODE_TYPE_P(node, PM_SYMBOL_NODE) || PM_NODE_TYPE_P(node, PM_INTERPOLATED_SYMBOL_NODE)) {
16807 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE) && !PM_NODE_TYPE_P(node, PM_INTERPOLATED_STRING_NODE)) {
16808 pm_parser_err_node(parser, node, PM_ERR_STRING_CONCATENATION);
16814 if (!PM_NODE_TYPE_P(current, PM_STRING_NODE) && !PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
16815 pm_parser_err_node(parser, current, PM_ERR_STRING_CONCATENATION);
16822 pm_interpolated_string_node_append(container, current);
16833#define PM_PARSE_PATTERN_SINGLE 0
16834#define PM_PARSE_PATTERN_TOP 1
16835#define PM_PARSE_PATTERN_MULTI 2
16848 if (*location->
start ==
'_')
return;
16850 if (pm_constant_id_list_includes(captures, capture)) {
16851 pm_parser_err(parser, location->
start, location->
end, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
16853 pm_constant_id_list_append(captures, capture);
16864 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
16866 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
16867 node = (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
16873 if (!match2(parser, PM_TOKEN_BRACKET_LEFT, PM_TOKEN_PARENTHESIS_LEFT)) {
16881 if (accept1(parser, PM_TOKEN_BRACKET_LEFT)) {
16883 accept1(parser, PM_TOKEN_NEWLINE);
16885 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
16886 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16887 accept1(parser, PM_TOKEN_NEWLINE);
16888 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET);
16893 parser_lex(parser);
16895 accept1(parser, PM_TOKEN_NEWLINE);
16897 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
16898 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
16899 accept1(parser, PM_TOKEN_NEWLINE);
16900 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
16909 return (
pm_node_t *) pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
16916 switch (PM_NODE_TYPE(inner)) {
16917 case PM_ARRAY_PATTERN_NODE: {
16925 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16926 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16933 case PM_FIND_PATTERN_NODE: {
16941 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16942 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16949 case PM_HASH_PATTERN_NODE: {
16957 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16958 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16972 pm_array_pattern_node_t *pattern_node = pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
16973 pm_array_pattern_node_requireds_append(pattern_node, inner);
16989 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
16991 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &identifier);
16994 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16995 pm_parser_local_add(parser, constant_id, identifier.
start, identifier.
end, 0);
16998 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&identifier));
16999 name = (
pm_node_t *) pm_local_variable_target_node_create(
17001 &PM_LOCATION_TOKEN_VALUE(&identifier),
17003 (uint32_t) (depth == -1 ? 0 : depth)
17008 return pm_splat_node_create(parser, &
operator, name);
17016 assert(parser->
current.type == PM_TOKEN_USTAR_STAR);
17017 parser_lex(parser);
17022 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
17023 return (
pm_node_t *) pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous);
17026 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
17030 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17034 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17035 value = (
pm_node_t *) pm_local_variable_target_node_create(
17037 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17039 (uint32_t) (depth == -1 ? 0 : depth)
17043 return (
pm_node_t *) pm_assoc_splat_node_create(parser, value, &
operator);
17051pm_slice_is_valid_local(
const pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
17052 ptrdiff_t length = end - start;
17053 if (length == 0)
return false;
17056 size_t width = char_is_identifier_start(parser, start, end - start);
17057 if (width == 0)
return false;
17063 if (pm_encoding_utf_8_isupper_char(start, length))
return false;
17068 const uint8_t *cursor = start + width;
17069 while ((width = char_is_identifier(parser, cursor, end - cursor))) cursor += width;
17070 return cursor == end;
17084 if (pm_slice_is_valid_local(parser, value_loc->
start, value_loc->
end)) {
17085 depth = pm_parser_local_depth_constant_id(parser, constant_id);
17087 pm_parser_err(parser, key->base.location.start, key->base.location.end, PM_ERR_PATTERN_HASH_KEY_LOCALS);
17089 if ((value_loc->
end > value_loc->
start) && ((value_loc->
end[-1] ==
'!') || (value_loc->
end[-1] ==
'?'))) {
17090 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);
17095 pm_parser_local_add(parser, constant_id, value_loc->
start, value_loc->
end, 0);
17098 parse_pattern_capture(parser, captures, constant_id, value_loc);
17103 (uint32_t) (depth == -1 ? 0 : depth)
17116 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
17129 switch (PM_NODE_TYPE(first_node)) {
17130 case PM_ASSOC_SPLAT_NODE:
17131 case PM_NO_KEYWORDS_PARAMETER_NODE:
17134 case PM_SYMBOL_NODE: {
17135 if (pm_symbol_node_label_p(first_node)) {
17136 parse_pattern_hash_key(parser, &keys, first_node);
17139 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)) {
17142 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) first_node);
17146 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17150 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, first_node, &
operator, value);
17152 pm_node_list_append(&assocs, assoc);
17161 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;
17162 pm_parser_err_node(parser, first_node, diag_id);
17166 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, first_node, &
operator, value);
17168 pm_node_list_append(&assocs, assoc);
17174 while (accept1(parser, PM_TOKEN_COMMA)) {
17176 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)) {
17178 if (rest != NULL) {
17179 pm_parser_err_token(parser, &parser->
current, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17185 if (match1(parser, PM_TOKEN_USTAR_STAR)) {
17186 pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures);
17188 if (rest == NULL) {
17191 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17192 pm_node_list_append(&assocs, assoc);
17197 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
17198 key = parse_strings(parser, NULL,
true, (uint16_t) (depth + 1));
17200 if (PM_NODE_TYPE_P(key, PM_INTERPOLATED_SYMBOL_NODE)) {
17201 pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
17202 }
else if (!pm_symbol_node_label_p(key)) {
17203 pm_parser_err_node(parser, key, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17206 expect1(parser, PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17210 parse_pattern_hash_key(parser, &keys, key);
17213 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)) {
17214 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) key);
17216 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17220 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
17222 if (rest != NULL) {
17223 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17226 pm_node_list_append(&assocs, assoc);
17233 pm_static_literals_free(&keys);
17242 switch (parser->
current.type) {
17243 case PM_TOKEN_IDENTIFIER:
17244 case PM_TOKEN_METHOD_NAME: {
17245 parser_lex(parser);
17249 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17253 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17254 return (
pm_node_t *) pm_local_variable_target_node_create(
17256 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17258 (uint32_t) (depth == -1 ? 0 : depth)
17261 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
17263 parser_lex(parser);
17265 if (accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17268 return (
pm_node_t *) pm_array_pattern_node_empty_create(parser, &opening, &parser->
previous);
17273 pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
17275 accept1(parser, PM_TOKEN_NEWLINE);
17276 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET);
17279 switch (PM_NODE_TYPE(inner)) {
17280 case PM_ARRAY_PATTERN_NODE: {
17286 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17287 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17294 case PM_FIND_PATTERN_NODE: {
17300 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17301 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17313 pm_array_pattern_node_requireds_append(node, inner);
17316 case PM_TOKEN_BRACE_LEFT: {
17322 parser_lex(parser);
17324 if (accept1(parser, PM_TOKEN_BRACE_RIGHT)) {
17327 node = pm_hash_pattern_node_empty_create(parser, &opening, &parser->
previous);
17331 switch (parser->
current.type) {
17332 case PM_TOKEN_LABEL:
17333 parser_lex(parser);
17334 first_node = (
pm_node_t *) pm_symbol_node_label_create(parser, &parser->
previous);
17336 case PM_TOKEN_USTAR_STAR:
17337 first_node = parse_pattern_keyword_rest(parser, captures);
17339 case PM_TOKEN_STRING_BEGIN:
17340 first_node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, PM_ERR_PATTERN_HASH_KEY_LABEL, (uint16_t) (depth + 1));
17344 parser_lex(parser);
17351 node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
17353 accept1(parser, PM_TOKEN_NEWLINE);
17354 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE);
17360 node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17361 node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17367 case PM_TOKEN_UDOT_DOT:
17368 case PM_TOKEN_UDOT_DOT_DOT: {
17370 parser_lex(parser);
17374 switch (parser->
current.type) {
17375 case PM_CASE_PRIMITIVE: {
17376 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
17377 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
17380 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
17381 pm_node_t *right = (
pm_node_t *) pm_missing_node_create(parser,
operator.start,
operator.end);
17382 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
17386 case PM_CASE_PRIMITIVE: {
17387 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, diag_id, (uint16_t) (depth + 1));
17390 if (pm_symbol_node_label_p(node))
return node;
17393 if (PM_NODE_TYPE(node) == PM_CALL_NODE) {
17394 pm_parser_err_node(parser, node, diag_id);
17396 pm_node_destroy(parser, node);
17401 if (accept2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
17407 switch (parser->
current.type) {
17408 case PM_CASE_PRIMITIVE: {
17409 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
17410 return (
pm_node_t *) pm_range_node_create(parser, node, &
operator, right);
17413 return (
pm_node_t *) pm_range_node_create(parser, node, &
operator, NULL);
17419 case PM_TOKEN_CARET: {
17420 parser_lex(parser);
17425 switch (parser->
current.type) {
17426 case PM_TOKEN_IDENTIFIER: {
17427 parser_lex(parser);
17430 if (variable == NULL) {
17431 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
previous, PM_ERR_NO_LOCAL_VARIABLE);
17432 variable = (
pm_node_t *) pm_local_variable_read_node_missing_create(parser, &parser->
previous, 0);
17435 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17437 case PM_TOKEN_INSTANCE_VARIABLE: {
17438 parser_lex(parser);
17441 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17443 case PM_TOKEN_CLASS_VARIABLE: {
17444 parser_lex(parser);
17447 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17449 case PM_TOKEN_GLOBAL_VARIABLE: {
17450 parser_lex(parser);
17453 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17455 case PM_TOKEN_NUMBERED_REFERENCE: {
17456 parser_lex(parser);
17459 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17461 case PM_TOKEN_BACK_REFERENCE: {
17462 parser_lex(parser);
17465 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17467 case PM_TOKEN_PARENTHESIS_LEFT: {
17472 parser_lex(parser);
17474 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN, (uint16_t) (depth + 1));
17477 accept1(parser, PM_TOKEN_NEWLINE);
17478 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
17479 return (
pm_node_t *) pm_pinned_expression_node_create(parser, expression, &
operator, &lparen, &parser->
previous);
17484 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
17485 pm_node_t *variable = (
pm_node_t *) pm_missing_node_create(parser,
operator.start,
operator.end);
17486 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17490 case PM_TOKEN_UCOLON_COLON: {
17492 parser_lex(parser);
17494 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
17497 return parse_pattern_constant_path(parser, captures, (
pm_node_t *) node, (uint16_t) (depth + 1));
17499 case PM_TOKEN_CONSTANT: {
17501 parser_lex(parser);
17504 return parse_pattern_constant_path(parser, captures, node, (uint16_t) (depth + 1));
17507 pm_parser_err_current(parser, diag_id);
17520 while ((node == NULL) || accept1(parser, PM_TOKEN_PIPE)) {
17523 switch (parser->
current.type) {
17524 case PM_TOKEN_IDENTIFIER:
17525 case PM_TOKEN_BRACKET_LEFT_ARRAY:
17526 case PM_TOKEN_BRACE_LEFT:
17527 case PM_TOKEN_CARET:
17528 case PM_TOKEN_CONSTANT:
17529 case PM_TOKEN_UCOLON_COLON:
17530 case PM_TOKEN_UDOT_DOT:
17531 case PM_TOKEN_UDOT_DOT_DOT:
17532 case PM_CASE_PRIMITIVE: {
17533 if (node == NULL) {
17534 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17536 pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
17537 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17542 case PM_TOKEN_PARENTHESIS_LEFT:
17543 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
17545 parser_lex(parser);
17547 pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
17548 accept1(parser, PM_TOKEN_NEWLINE);
17549 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
17552 if (node == NULL) {
17555 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17561 pm_parser_err_current(parser, diag_id);
17564 if (node == NULL) {
17567 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17577 while (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
17579 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_PATTERN_IDENT_AFTER_HROCKET);
17584 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17588 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17591 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17593 (uint32_t) (depth == -1 ? 0 : depth)
17596 node = (
pm_node_t *) pm_capture_pattern_node_create(parser, node, target, &
operator);
17609 bool leading_rest =
false;
17610 bool trailing_rest =
false;
17612 switch (parser->
current.type) {
17613 case PM_TOKEN_LABEL: {
17614 parser_lex(parser);
17616 node = (
pm_node_t *) parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1));
17618 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17619 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17624 case PM_TOKEN_USTAR_STAR: {
17625 node = parse_pattern_keyword_rest(parser, captures);
17626 node = (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17628 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17629 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17634 case PM_TOKEN_STRING_BEGIN: {
17637 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17639 if (pm_symbol_node_label_p(node)) {
17640 node = (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17642 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17643 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17649 node = parse_pattern_primitives(parser, captures, node, diag_id, (uint16_t) (depth + 1));
17652 case PM_TOKEN_USTAR: {
17653 if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
17654 parser_lex(parser);
17655 node = (
pm_node_t *) parse_pattern_rest(parser, captures);
17656 leading_rest =
true;
17662 node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1));
17668 if (pm_symbol_node_label_p(node)) {
17669 return (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17672 if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser, PM_TOKEN_COMMA)) {
17677 pm_node_list_append(&nodes, node);
17680 while (accept1(parser, PM_TOKEN_COMMA)) {
17682 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)) {
17684 pm_node_list_append(&nodes, node);
17685 trailing_rest =
true;
17689 if (accept1(parser, PM_TOKEN_USTAR)) {
17690 node = (
pm_node_t *) parse_pattern_rest(parser, captures);
17695 if (trailing_rest) {
17696 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
17699 trailing_rest =
true;
17701 node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
17704 pm_node_list_append(&nodes, node);
17711 if (leading_rest && PM_NODE_TYPE_P(nodes.
nodes[nodes.
size - 1], PM_SPLAT_NODE)) {
17712 node = (
pm_node_t *) pm_find_pattern_node_create(parser, &nodes);
17714 if (nodes.
size == 2) {
17715 pm_parser_err_node(parser, node, PM_ERR_PATTERN_FIND_MISSING_INNER);
17718 node = (
pm_node_t *) pm_array_pattern_node_node_list_create(parser, &nodes);
17720 if (leading_rest && trailing_rest) {
17721 pm_parser_err_node(parser, node, PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS);
17726 }
else if (leading_rest) {
17729 node = (
pm_node_t *) pm_array_pattern_node_rest_create(parser, node);
17741parse_negative_numeric(
pm_node_t *node) {
17742 switch (PM_NODE_TYPE(node)) {
17743 case PM_INTEGER_NODE: {
17749 case PM_FLOAT_NODE: {
17755 case PM_RATIONAL_NODE: {
17761 case PM_IMAGINARY_NODE:
17766 assert(
false &&
"unreachable");
17779 case PM_ERR_HASH_KEY: {
17783 case PM_ERR_HASH_VALUE:
17784 case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: {
17788 case PM_ERR_UNARY_RECEIVER: {
17793 case PM_ERR_UNARY_DISALLOWED:
17794 case PM_ERR_EXPECT_ARGUMENT: {
17799 pm_parser_err_previous(parser, diag_id);
17809#define CONTEXT_NONE 0
17810#define CONTEXT_THROUGH_ENSURE 1
17811#define CONTEXT_THROUGH_ELSE 2
17814 int context = CONTEXT_NONE;
17816 while (context_node != NULL) {
17817 switch (context_node->
context) {
17838 if (context == CONTEXT_NONE) {
17839 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_WITHOUT_RESCUE);
17840 }
else if (context == CONTEXT_THROUGH_ENSURE) {
17841 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ENSURE);
17842 }
else if (context == CONTEXT_THROUGH_ELSE) {
17843 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ELSE);
17855 context = CONTEXT_THROUGH_ELSE;
17866 context = CONTEXT_THROUGH_ENSURE;
17870 assert(
false &&
"unreachable");
17900 context_node = context_node->
prev;
17904#undef CONTEXT_ENSURE
17915 while (context_node != NULL) {
17916 switch (context_node->
context) {
17941 pm_parser_err_node(parser, node, PM_ERR_INVALID_YIELD);
17945 assert(
false &&
"unreachable");
17986 context_node = context_node->
prev;
18018parse_regular_expression_error(
const uint8_t *start,
const uint8_t *end,
const char *message,
void *data) {
18022 if (callback_data->
shared) {
18028 PM_PARSER_ERR_FORMAT(callback_data->
parser, location.
start, location.
end, PM_ERR_REGEXP_PARSE_ERROR, message);
18041 .shared = unescaped->
type == PM_STRING_SHARED
18044 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);
18051parse_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) {
18052 switch (parser->
current.type) {
18053 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
18054 parser_lex(parser);
18057 pm_accepts_block_stack_push(parser,
true);
18058 bool parsed_bare_hash =
false;
18060 while (!match2(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_EOF)) {
18061 bool accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
18065 if (accepted_newline && match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
18071 if (accept1(parser, PM_TOKEN_COMMA)) {
18074 if (accepted_newline) {
18075 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
18091 if (match1(parser, PM_TOKEN_BRACKET_RIGHT))
break;
18095 if (accept1(parser, PM_TOKEN_USTAR)) {
18099 if (match3(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_EOF)) {
18100 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
18102 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
18105 element = (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
18106 }
else if (match2(parser, PM_TOKEN_LABEL, PM_TOKEN_USTAR_STAR)) {
18107 if (parsed_bare_hash) {
18108 pm_parser_err_current(parser, PM_ERR_EXPRESSION_BARE_HASH);
18111 element = (
pm_node_t *) pm_keyword_hash_node_create(parser);
18114 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)) {
18115 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
18118 pm_static_literals_free(&hash_keys);
18119 parsed_bare_hash =
true;
18121 element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_ARRAY_EXPRESSION, (uint16_t) (depth + 1));
18123 if (pm_symbol_node_label_p(element) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
18124 if (parsed_bare_hash) {
18125 pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
18130 pm_hash_key_static_literals_add(parser, &hash_keys, element);
18133 if (parser->
previous.
type == PM_TOKEN_EQUAL_GREATER) {
18136 operator = not_provided(parser);
18139 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
18140 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, element, &
operator, value);
18141 pm_keyword_hash_node_elements_append(hash, assoc);
18144 if (accept1(parser, PM_TOKEN_COMMA) && !match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
18145 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
18148 pm_static_literals_free(&hash_keys);
18149 parsed_bare_hash =
true;
18153 pm_array_node_elements_append(array, element);
18154 if (PM_NODE_TYPE_P(element, PM_MISSING_NODE))
break;
18157 accept1(parser, PM_TOKEN_NEWLINE);
18159 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
18165 pm_array_node_close_set(array, &parser->
previous);
18166 pm_accepts_block_stack_pop(parser);
18170 case PM_TOKEN_PARENTHESIS_LEFT:
18171 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
18173 pm_node_flags_t flags = 0;
18176 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18178 parser_lex(parser);
18180 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
18181 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
18182 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
18189 if (match2(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_EOF)) {
18190 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
18192 pop_block_exits(parser, previous_block_exits);
18193 pm_node_list_free(¤t_block_exits);
18195 return (
pm_node_t *) pm_parentheses_node_create(parser, &opening, NULL, &parser->
previous, flags);
18200 pm_accepts_block_stack_push(parser,
true);
18202 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
18203 context_pop(parser);
18208 bool terminator_found =
false;
18210 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
18211 terminator_found =
true;
18212 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
18213 }
else if (accept1(parser, PM_TOKEN_NEWLINE)) {
18214 terminator_found =
true;
18217 if (terminator_found) {
18219 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
18220 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
18221 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
18230 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18231 if (opening.
type == PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
18232 lex_state_set(parser, PM_LEX_STATE_ENDARG);
18235 parser_lex(parser);
18236 pm_accepts_block_stack_pop(parser);
18238 pop_block_exits(parser, previous_block_exits);
18239 pm_node_list_free(¤t_block_exits);
18241 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) || PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
18247 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) && ((
pm_multi_target_node_t *) statement)->lparen_loc.start == NULL) {
18250 multi_target = pm_multi_target_node_create(parser);
18251 pm_multi_target_node_targets_append(parser, multi_target, statement);
18254 pm_location_t lparen_loc = PM_LOCATION_TOKEN_VALUE(&opening);
18263 if (match1(parser, PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
18264 result = parse_targets(parser, (
pm_node_t *) multi_target, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18265 accept1(parser, PM_TOKEN_NEWLINE);
18276 }
else if (binding_power != PM_BINDING_POWER_STATEMENT) {
18279 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
18280 }
else if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
18284 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
18294 pm_statements_node_body_append(parser, statements, statement,
true);
18303 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
18306 pm_statements_node_body_append(parser, statements, statement,
true);
18310 if (!terminator_found && !match1(parser, PM_TOKEN_EOF)) {
18316 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
18317 pm_statements_node_body_append(parser, statements, node,
true);
18324 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) parser->
recovering =
false;
18330 if (PM_NODE_TYPE_P(node, PM_MISSING_NODE))
break;
18334 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18335 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18336 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
break;
18337 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18339 }
else if (!match1(parser, PM_TOKEN_EOF)) {
18346 context_pop(parser);
18347 pm_accepts_block_stack_pop(parser);
18348 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
18357 if (PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
18359 pm_multi_target_node_targets_append(parser, multi_target, statement);
18361 statement = (
pm_node_t *) multi_target;
18365 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE)) {
18367 pm_token_t operator = { .
type = PM_TOKEN_EQUAL, .start = offset, .end = offset };
18373 pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
18377 pop_block_exits(parser, previous_block_exits);
18378 pm_node_list_free(¤t_block_exits);
18380 pm_void_statements_check(parser, statements,
true);
18383 case PM_TOKEN_BRACE_LEFT: {
18394 pm_accepts_block_stack_push(parser,
true);
18395 parser_lex(parser);
18399 if (!match2(parser, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_EOF)) {
18400 if (current_hash_keys != NULL) {
18401 parse_assocs(parser, current_hash_keys, (
pm_node_t *) node, (uint16_t) (depth + 1));
18404 parse_assocs(parser, &hash_keys, (
pm_node_t *) node, (uint16_t) (depth + 1));
18405 pm_static_literals_free(&hash_keys);
18408 accept1(parser, PM_TOKEN_NEWLINE);
18411 pm_accepts_block_stack_pop(parser);
18412 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM);
18413 pm_hash_node_closing_loc_set(node, &parser->
previous);
18417 case PM_TOKEN_CHARACTER_LITERAL: {
18418 parser_lex(parser);
18421 opening.
type = PM_TOKEN_STRING_BEGIN;
18425 content.
type = PM_TOKEN_STRING_CONTENT;
18429 pm_node_t *node = (
pm_node_t *) pm_string_node_create_current_string(parser, &opening, &content, &closing);
18430 pm_node_flag_set(node, parse_unescaped_encoding(parser));
18434 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
18435 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18440 case PM_TOKEN_CLASS_VARIABLE: {
18441 parser_lex(parser);
18444 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18445 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18450 case PM_TOKEN_CONSTANT: {
18451 parser_lex(parser);
18457 match1(parser, PM_TOKEN_PARENTHESIS_LEFT) ||
18458 (accepts_command_call && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
18459 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
18460 match1(parser, PM_TOKEN_BRACE_LEFT)
18463 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18464 return (
pm_node_t *) pm_call_node_fcall_create(parser, &constant, &arguments);
18469 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
18472 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18477 case PM_TOKEN_UCOLON_COLON: {
18478 parser_lex(parser);
18481 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
18484 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
18485 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18490 case PM_TOKEN_UDOT_DOT:
18491 case PM_TOKEN_UDOT_DOT_DOT: {
18493 parser_lex(parser);
18495 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));
18501 if (match2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
18502 pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
18505 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
18507 case PM_TOKEN_FLOAT:
18508 parser_lex(parser);
18510 case PM_TOKEN_FLOAT_IMAGINARY:
18511 parser_lex(parser);
18512 return (
pm_node_t *) pm_float_node_imaginary_create(parser, &parser->
previous);
18513 case PM_TOKEN_FLOAT_RATIONAL:
18514 parser_lex(parser);
18516 case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY:
18517 parser_lex(parser);
18518 return (
pm_node_t *) pm_float_node_rational_imaginary_create(parser, &parser->
previous);
18519 case PM_TOKEN_NUMBERED_REFERENCE: {
18520 parser_lex(parser);
18523 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18524 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18529 case PM_TOKEN_GLOBAL_VARIABLE: {
18530 parser_lex(parser);
18533 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18534 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18539 case PM_TOKEN_BACK_REFERENCE: {
18540 parser_lex(parser);
18543 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18544 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18549 case PM_TOKEN_IDENTIFIER:
18550 case PM_TOKEN_METHOD_NAME: {
18551 parser_lex(parser);
18553 pm_node_t *node = parse_variable_call(parser);
18555 if (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
18563 if (parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1))) {
18566 pm_node_flag_unset((
pm_node_t *)call, PM_CALL_NODE_FLAGS_VARIABLE_CALL);
18573 if (arguments.
block != NULL) {
18590 (accepts_command_call && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
18591 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
18592 match1(parser, PM_TOKEN_BRACE_LEFT)
18595 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18596 pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
18598 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
18602 parse_target_implicit_parameter(parser, node);
18608 assert(PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE));
18610 if (pm_token_is_numbered_parameter(identifier.
start, identifier.
end)) {
18611 parse_target_implicit_parameter(parser, node);
18614 pm_locals_unread(&pm_parser_scope_find(parser, cast->
depth)->
locals, cast->
name);
18618 pm_node_destroy(parser, node);
18623 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
18624 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18629 case PM_TOKEN_HEREDOC_START: {
18635 size_t common_whitespace = (size_t) -1;
18638 parser_lex(parser);
18644 if (match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18650 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18657 }
else if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) == NULL) {
18665 }
else if (PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18670 pm_node_flag_set(part, parse_unescaped_encoding(parser));
18673 cast->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
18677 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18679 cast->
base.
type = PM_X_STRING_NODE;
18682 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18683 parse_heredoc_dedent_string(&cast->
unescaped, common_whitespace);
18693 pm_node_list_append(&parts, part);
18695 while (!match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18696 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
18697 pm_node_list_append(&parts, part);
18703 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18705 cast->
parts = parts;
18708 pm_interpolated_xstring_node_closing_set(cast, &parser->
previous);
18714 pm_node_list_free(&parts);
18717 pm_interpolated_string_node_closing_set(cast, &parser->
previous);
18725 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18727 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18733 parse_heredoc_dedent(parser, nodes, common_whitespace);
18737 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
18738 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18743 case PM_TOKEN_INSTANCE_VARIABLE: {
18744 parser_lex(parser);
18747 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18748 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18753 case PM_TOKEN_INTEGER: {
18755 parser_lex(parser);
18758 case PM_TOKEN_INTEGER_IMAGINARY: {
18760 parser_lex(parser);
18761 return (
pm_node_t *) pm_integer_node_imaginary_create(parser, base, &parser->
previous);
18763 case PM_TOKEN_INTEGER_RATIONAL: {
18765 parser_lex(parser);
18766 return (
pm_node_t *) pm_integer_node_rational_create(parser, base, &parser->
previous);
18768 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: {
18770 parser_lex(parser);
18771 return (
pm_node_t *) pm_integer_node_rational_imaginary_create(parser, base, &parser->
previous);
18773 case PM_TOKEN_KEYWORD___ENCODING__:
18774 parser_lex(parser);
18775 return (
pm_node_t *) pm_source_encoding_node_create(parser, &parser->
previous);
18776 case PM_TOKEN_KEYWORD___FILE__:
18777 parser_lex(parser);
18779 case PM_TOKEN_KEYWORD___LINE__:
18780 parser_lex(parser);
18782 case PM_TOKEN_KEYWORD_ALIAS: {
18783 if (binding_power != PM_BINDING_POWER_STATEMENT) {
18784 pm_parser_err_current(parser, PM_ERR_STATEMENT_ALIAS);
18787 parser_lex(parser);
18790 pm_node_t *new_name = parse_alias_argument(parser,
true, (uint16_t) (depth + 1));
18791 pm_node_t *old_name = parse_alias_argument(parser,
false, (uint16_t) (depth + 1));
18793 switch (PM_NODE_TYPE(new_name)) {
18794 case PM_BACK_REFERENCE_READ_NODE:
18795 case PM_NUMBERED_REFERENCE_READ_NODE:
18796 case PM_GLOBAL_VARIABLE_READ_NODE: {
18797 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)) {
18798 if (PM_NODE_TYPE_P(old_name, PM_NUMBERED_REFERENCE_READ_NODE)) {
18799 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE);
18802 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18805 return (
pm_node_t *) pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name);
18807 case PM_SYMBOL_NODE:
18808 case PM_INTERPOLATED_SYMBOL_NODE: {
18809 if (!PM_NODE_TYPE_P(old_name, PM_SYMBOL_NODE) && !PM_NODE_TYPE_P(old_name, PM_INTERPOLATED_SYMBOL_NODE)) {
18810 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18815 return (
pm_node_t *) pm_alias_method_node_create(parser, &keyword, new_name, old_name);
18818 case PM_TOKEN_KEYWORD_CASE: {
18819 size_t opening_newline_index = token_newline_index(parser);
18820 parser_lex(parser);
18826 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18828 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18829 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18831 }
else if (match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_END)) {
18833 }
else if (!token_begins_expression_p(parser->
current.type)) {
18836 predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CASE_EXPRESSION_AFTER_CASE, (uint16_t) (depth + 1));
18837 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18840 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
18841 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18842 parser_lex(parser);
18844 pop_block_exits(parser, previous_block_exits);
18845 pm_node_list_free(¤t_block_exits);
18847 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18848 return (
pm_node_t *) pm_case_node_create(parser, &case_keyword, predicate, &parser->
previous);
18853 pm_token_t end_keyword = not_provided(parser);
18856 if (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18857 pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, &end_keyword);
18863 while (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18864 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18865 parser_lex(parser);
18868 pm_when_node_t *when_node = pm_when_node_create(parser, &when_keyword);
18871 if (accept1(parser, PM_TOKEN_USTAR)) {
18873 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
18875 pm_splat_node_t *splat_node = pm_splat_node_create(parser, &
operator, expression);
18876 pm_when_node_conditions_append(when_node, (
pm_node_t *) splat_node);
18878 if (PM_NODE_TYPE_P(expression, PM_MISSING_NODE))
break;
18880 pm_node_t *condition = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_CASE_EXPRESSION_AFTER_WHEN, (uint16_t) (depth + 1));
18881 pm_when_node_conditions_append(when_node, condition);
18885 if (PM_NODE_TYPE_P(condition, PM_MISSING_NODE))
break;
18889 if (PM_NODE_TYPE_P(condition, PM_STRING_NODE)) {
18890 pm_node_flag_set(condition, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
18891 }
else if (PM_NODE_TYPE_P(condition, PM_SOURCE_FILE_NODE)) {
18892 pm_node_flag_set(condition, PM_NODE_FLAG_STATIC_LITERAL);
18895 pm_when_clause_static_literals_add(parser, &literals, condition);
18897 }
while (accept1(parser, PM_TOKEN_COMMA));
18899 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18900 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
18901 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
18904 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_WHEN_DELIMITER);
18905 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
18908 if (!match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18910 if (statements != NULL) {
18911 pm_when_node_statements_set(when_node, statements);
18915 pm_case_node_condition_append(case_node, (
pm_node_t *) when_node);
18921 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18924 pm_static_literals_free(&literals);
18927 pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate, &end_keyword);
18931 if (predicate == NULL) {
18932 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MATCH_MISSING_PREDICATE);
18938 while (match1(parser, PM_TOKEN_KEYWORD_IN)) {
18939 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18944 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
18946 parser_lex(parser);
18951 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));
18954 pm_constant_id_list_free(&captures);
18959 if (accept1(parser, PM_TOKEN_KEYWORD_IF_MODIFIER)) {
18961 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
18962 pattern = (
pm_node_t *) pm_if_node_modifier_create(parser, pattern, &keyword, predicate);
18963 }
else if (accept1(parser, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) {
18965 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
18966 pattern = (
pm_node_t *) pm_unless_node_modifier_create(parser, pattern, &keyword, predicate);
18973 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18974 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
18977 then_keyword = not_provided(parser);
18980 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_IN_DELIMITER);
18987 if (match3(parser, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18995 pm_node_t *condition = (
pm_node_t *) pm_in_node_create(parser, pattern, statements, &in_keyword, &then_keyword);
18996 pm_case_match_node_condition_append(case_node, condition);
19002 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
19008 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19009 if (accept1(parser, PM_TOKEN_KEYWORD_ELSE)) {
19013 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19014 else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser,
PM_CONTEXT_ELSE, (uint16_t) (depth + 1)), &parser->
current);
19016 else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->
current);
19019 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
19020 pm_case_node_else_clause_set((
pm_case_node_t *) node, else_node);
19026 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
19027 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM);
19029 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
19035 pop_block_exits(parser, previous_block_exits);
19036 pm_node_list_free(¤t_block_exits);
19040 case PM_TOKEN_KEYWORD_BEGIN: {
19041 size_t opening_newline_index = token_newline_index(parser);
19042 parser_lex(parser);
19045 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19048 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19051 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19052 pm_accepts_block_stack_push(parser,
true);
19053 begin_statements = parse_statements(parser,
PM_CONTEXT_BEGIN, (uint16_t) (depth + 1));
19054 pm_accepts_block_stack_pop(parser);
19055 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19058 pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
19059 parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
19060 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM);
19063 pm_begin_node_end_keyword_set(begin_node, &parser->
previous);
19065 pop_block_exits(parser, previous_block_exits);
19066 pm_node_list_free(¤t_block_exits);
19070 case PM_TOKEN_KEYWORD_BEGIN_UPCASE: {
19072 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19074 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19075 pm_parser_err_current(parser, PM_ERR_STATEMENT_PREEXE_BEGIN);
19078 parser_lex(parser);
19081 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_BEGIN_UPCASE_BRACE);
19085 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM);
19088 pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
19091 flush_block_exits(parser, previous_block_exits);
19092 pm_node_list_free(¤t_block_exits);
19094 return (
pm_node_t *) pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous);
19096 case PM_TOKEN_KEYWORD_BREAK:
19097 case PM_TOKEN_KEYWORD_NEXT:
19098 case PM_TOKEN_KEYWORD_RETURN: {
19099 parser_lex(parser);
19105 token_begins_expression_p(parser->
current.type) ||
19106 match2(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)
19108 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].
left;
19110 if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
19111 parse_arguments(parser, &arguments,
false, PM_TOKEN_EOF, (uint16_t) (depth + 1));
19115 switch (keyword.
type) {
19116 case PM_TOKEN_KEYWORD_BREAK: {
19121 case PM_TOKEN_KEYWORD_NEXT: {
19126 case PM_TOKEN_KEYWORD_RETURN: {
19128 parse_return(parser, node);
19132 assert(
false &&
"unreachable");
19136 case PM_TOKEN_KEYWORD_SUPER: {
19137 parser_lex(parser);
19141 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
19146 ((arguments.
block == NULL) || PM_NODE_TYPE_P(arguments.
block, PM_BLOCK_NODE))
19148 return (
pm_node_t *) pm_forwarding_super_node_create(parser, &keyword, &arguments);
19151 return (
pm_node_t *) pm_super_node_create(parser, &keyword, &arguments);
19153 case PM_TOKEN_KEYWORD_YIELD: {
19154 parser_lex(parser);
19158 parse_arguments_list(parser, &arguments,
false, accepts_command_call, (uint16_t) (depth + 1));
19164 if (arguments.
block != NULL) {
19165 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
19166 pm_node_destroy(parser, arguments.
block);
19167 arguments.
block = NULL;
19175 case PM_TOKEN_KEYWORD_CLASS: {
19176 size_t opening_newline_index = token_newline_index(parser);
19177 parser_lex(parser);
19180 pm_do_loop_stack_push(parser,
false);
19183 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19185 if (accept1(parser, PM_TOKEN_LESS_LESS)) {
19187 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));
19189 pm_parser_scope_push(parser,
true);
19190 if (!match2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
19195 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19196 pm_accepts_block_stack_push(parser,
true);
19198 pm_accepts_block_stack_pop(parser);
19201 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
19202 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
19203 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));
19205 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
19208 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
19213 pm_parser_scope_pop(parser);
19214 pm_do_loop_stack_pop(parser);
19216 flush_block_exits(parser, previous_block_exits);
19217 pm_node_list_free(¤t_block_exits);
19219 return (
pm_node_t *) pm_singleton_class_node_create(parser, &locals, &class_keyword, &
operator, expression, statements, &parser->
previous);
19222 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_CLASS_NAME, (uint16_t) (depth + 1));
19224 if (name.
type != PM_TOKEN_CONSTANT) {
19225 pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME);
19231 if (match1(parser, PM_TOKEN_LESS)) {
19232 inheritance_operator = parser->
current;
19233 lex_state_set(parser, PM_LEX_STATE_BEG);
19236 parser_lex(parser);
19238 superclass = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CLASS_SUPERCLASS, (uint16_t) (depth + 1));
19240 inheritance_operator = not_provided(parser);
19244 pm_parser_scope_push(parser,
true);
19246 if (inheritance_operator.
type != PM_TOKEN_NOT_PROVIDED) {
19247 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CLASS_UNEXPECTED_END);
19249 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19253 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19254 pm_accepts_block_stack_push(parser,
true);
19256 pm_accepts_block_stack_pop(parser);
19259 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
19260 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
19261 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));
19263 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
19266 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
19268 if (context_def_p(parser)) {
19269 pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
19275 pm_parser_scope_pop(parser);
19276 pm_do_loop_stack_pop(parser);
19278 if (!PM_NODE_TYPE_P(constant_path, PM_CONSTANT_PATH_NODE) && !(PM_NODE_TYPE_P(constant_path, PM_CONSTANT_READ_NODE))) {
19279 pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
19282 pop_block_exits(parser, previous_block_exits);
19283 pm_node_list_free(¤t_block_exits);
19285 return (
pm_node_t *) pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, &inheritance_operator, superclass, statements, &parser->
previous);
19287 case PM_TOKEN_KEYWORD_DEF: {
19289 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19292 size_t opening_newline_index = token_newline_index(parser);
19302 parser_lex(parser);
19306 bool valid_name =
true;
19308 switch (parser->
current.type) {
19309 case PM_CASE_OPERATOR:
19310 pm_parser_scope_push(parser,
true);
19311 lex_state_set(parser, PM_LEX_STATE_ENDFN);
19312 parser_lex(parser);
19316 case PM_TOKEN_IDENTIFIER: {
19317 parser_lex(parser);
19319 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
19320 receiver = parse_variable_call(parser);
19322 pm_parser_scope_push(parser,
true);
19323 lex_state_set(parser, PM_LEX_STATE_FNAME);
19324 parser_lex(parser);
19327 name = parse_method_definition_name(parser);
19330 pm_parser_scope_push(parser,
true);
19337 case PM_TOKEN_INSTANCE_VARIABLE:
19338 case PM_TOKEN_CLASS_VARIABLE:
19339 case PM_TOKEN_GLOBAL_VARIABLE:
19340 valid_name =
false;
19342 case PM_TOKEN_CONSTANT:
19343 case PM_TOKEN_KEYWORD_NIL:
19344 case PM_TOKEN_KEYWORD_SELF:
19345 case PM_TOKEN_KEYWORD_TRUE:
19346 case PM_TOKEN_KEYWORD_FALSE:
19347 case PM_TOKEN_KEYWORD___FILE__:
19348 case PM_TOKEN_KEYWORD___LINE__:
19349 case PM_TOKEN_KEYWORD___ENCODING__: {
19350 pm_parser_scope_push(parser,
true);
19351 parser_lex(parser);
19355 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
19356 lex_state_set(parser, PM_LEX_STATE_FNAME);
19357 parser_lex(parser);
19360 switch (identifier.
type) {
19361 case PM_TOKEN_CONSTANT:
19362 receiver = (
pm_node_t *) pm_constant_read_node_create(parser, &identifier);
19364 case PM_TOKEN_INSTANCE_VARIABLE:
19365 receiver = (
pm_node_t *) pm_instance_variable_read_node_create(parser, &identifier);
19367 case PM_TOKEN_CLASS_VARIABLE:
19368 receiver = (
pm_node_t *) pm_class_variable_read_node_create(parser, &identifier);
19370 case PM_TOKEN_GLOBAL_VARIABLE:
19371 receiver = (
pm_node_t *) pm_global_variable_read_node_create(parser, &identifier);
19373 case PM_TOKEN_KEYWORD_NIL:
19374 receiver = (
pm_node_t *) pm_nil_node_create(parser, &identifier);
19376 case PM_TOKEN_KEYWORD_SELF:
19377 receiver = (
pm_node_t *) pm_self_node_create(parser, &identifier);
19379 case PM_TOKEN_KEYWORD_TRUE:
19380 receiver = (
pm_node_t *) pm_true_node_create(parser, &identifier);
19382 case PM_TOKEN_KEYWORD_FALSE:
19383 receiver = (
pm_node_t *) pm_false_node_create(parser, &identifier);
19385 case PM_TOKEN_KEYWORD___FILE__:
19386 receiver = (
pm_node_t *) pm_source_file_node_create(parser, &identifier);
19388 case PM_TOKEN_KEYWORD___LINE__:
19389 receiver = (
pm_node_t *) pm_source_line_node_create(parser, &identifier);
19391 case PM_TOKEN_KEYWORD___ENCODING__:
19392 receiver = (
pm_node_t *) pm_source_encoding_node_create(parser, &identifier);
19398 name = parse_method_definition_name(parser);
19408 case PM_TOKEN_PARENTHESIS_LEFT: {
19413 context_pop(parser);
19414 parser_lex(parser);
19417 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEF_RECEIVER, (uint16_t) (depth + 1));
19419 accept1(parser, PM_TOKEN_NEWLINE);
19420 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19423 lex_state_set(parser, PM_LEX_STATE_FNAME);
19424 expect2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON, PM_ERR_DEF_RECEIVER_TERM);
19427 receiver = (
pm_node_t *) pm_parentheses_node_create(parser, &lparen, expression, &rparen, 0);
19431 pm_parser_scope_push(parser,
true);
19433 name = parse_method_definition_name(parser);
19437 pm_parser_scope_push(parser,
true);
19438 name = parse_method_definition_name(parser);
19446 switch (parser->
current.type) {
19447 case PM_TOKEN_PARENTHESIS_LEFT: {
19448 parser_lex(parser);
19451 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19454 params = parse_parameters(parser, PM_BINDING_POWER_DEFINED,
true,
false,
true,
true,
false, (uint16_t) (depth + 1));
19457 lex_state_set(parser, PM_LEX_STATE_BEG);
19460 context_pop(parser);
19461 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19470 case PM_CASE_PARAMETER: {
19473 if (parser->
current.type == PM_TOKEN_LABEL) {
19474 lex_state_set(parser, parser->
lex_state | PM_LEX_STATE_LABEL);
19477 lparen = not_provided(parser);
19478 rparen = not_provided(parser);
19479 params = parse_parameters(parser, PM_BINDING_POWER_DEFINED,
false,
false,
true,
true,
false, (uint16_t) (depth + 1));
19481 context_pop(parser);
19485 lparen = not_provided(parser);
19486 rparen = not_provided(parser);
19489 context_pop(parser);
19498 if (accept1(parser, PM_TOKEN_EQUAL)) {
19499 if (token_is_setter_name(&name)) {
19500 pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
19505 pm_do_loop_stack_push(parser,
false);
19506 statements = (
pm_node_t *) pm_statements_node_create(parser);
19513 bool allow_command_call = (binding_power == PM_BINDING_POWER_ASSIGNMENT) ||
19514 (binding_power < PM_BINDING_POWER_COMPOSITION);
19516 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_DEFINED + 1, allow_command_call,
false, PM_ERR_DEF_ENDLESS, (uint16_t) (depth + 1));
19518 if (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
19522 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));
19523 context_pop(parser);
19525 statement = (
pm_node_t *) pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value);
19528 pm_statements_node_body_append(parser, (
pm_statements_node_t *) statements, statement,
false);
19529 pm_do_loop_stack_pop(parser);
19530 context_pop(parser);
19531 end_keyword = not_provided(parser);
19533 equal = not_provided(parser);
19535 if (lparen.
type == PM_TOKEN_NOT_PROVIDED) {
19536 lex_state_set(parser, PM_LEX_STATE_BEG);
19538 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_DEF_PARAMS_TERM);
19540 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19543 pm_accepts_block_stack_push(parser,
true);
19544 pm_do_loop_stack_push(parser,
false);
19546 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19547 pm_accepts_block_stack_push(parser,
true);
19549 pm_accepts_block_stack_pop(parser);
19552 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
19553 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
19554 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));
19556 parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword,
false,
false);
19559 pm_accepts_block_stack_pop(parser);
19560 pm_do_loop_stack_pop(parser);
19562 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_DEF_TERM);
19568 pm_parser_scope_pop(parser);
19575 pm_constant_id_t name_id = pm_parser_constant_id_location(parser, name.
start, parse_operator_symbol_name(&name));
19577 flush_block_exits(parser, previous_block_exits);
19578 pm_node_list_free(¤t_block_exits);
19580 return (
pm_node_t *) pm_def_node_create(
19596 case PM_TOKEN_KEYWORD_DEFINED: {
19597 parser_lex(parser);
19605 bool newline = accept1(parser, PM_TOKEN_NEWLINE);
19607 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19610 if (newline && accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19611 expression = (
pm_node_t *) pm_parentheses_node_create(parser, &lparen, NULL, &parser->
previous, 0);
19612 lparen = not_provided(parser);
19613 rparen = not_provided(parser);
19615 expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19618 rparen = not_provided(parser);
19620 accept1(parser, PM_TOKEN_NEWLINE);
19621 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19626 lparen = not_provided(parser);
19627 rparen = not_provided(parser);
19628 expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19631 context_pop(parser);
19632 return (
pm_node_t *) pm_defined_node_create(
19637 &PM_LOCATION_TOKEN_VALUE(&keyword)
19640 case PM_TOKEN_KEYWORD_END_UPCASE: {
19641 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19642 pm_parser_err_current(parser, PM_ERR_STATEMENT_POSTEXE_END);
19645 parser_lex(parser);
19648 if (context_def_p(parser)) {
19649 pm_parser_warn_token(parser, &keyword, PM_WARN_END_IN_METHOD);
19652 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_END_UPCASE_BRACE);
19656 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM);
19657 return (
pm_node_t *) pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous);
19659 case PM_TOKEN_KEYWORD_FALSE:
19660 parser_lex(parser);
19662 case PM_TOKEN_KEYWORD_FOR: {
19663 size_t opening_newline_index = token_newline_index(parser);
19664 parser_lex(parser);
19672 if (accept1(parser, PM_TOKEN_USTAR)) {
19676 if (token_begins_expression_p(parser->
current.type)) {
19677 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19680 index = (
pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
19681 }
else if (token_begins_expression_p(parser->
current.type)) {
19682 index = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
19684 pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX);
19685 index = (
pm_node_t *) pm_missing_node_create(parser, for_keyword.
start, for_keyword.
end);
19689 if (match1(parser, PM_TOKEN_COMMA)) {
19690 index = parse_targets(parser, index, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19692 index = parse_target(parser, index,
false,
false);
19695 context_pop(parser);
19696 pm_do_loop_stack_push(parser,
true);
19698 expect1(parser, PM_TOKEN_KEYWORD_IN, PM_ERR_FOR_IN);
19701 pm_node_t *collection = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_FOR_COLLECTION, (uint16_t) (depth + 1));
19702 pm_do_loop_stack_pop(parser);
19705 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19708 do_keyword = not_provided(parser);
19709 if (!match2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE)) {
19715 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19716 statements = parse_statements(parser,
PM_CONTEXT_FOR, (uint16_t) (depth + 1));
19719 parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword,
false,
false);
19720 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM);
19722 return (
pm_node_t *) pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, &do_keyword, &parser->
previous);
19724 case PM_TOKEN_KEYWORD_IF:
19725 if (parser_end_of_line_p(parser)) {
19726 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
19729 size_t opening_newline_index = token_newline_index(parser);
19730 bool if_after_else = parser->
previous.
type == PM_TOKEN_KEYWORD_ELSE;
19731 parser_lex(parser);
19733 return parse_conditional(parser,
PM_CONTEXT_IF, opening_newline_index, if_after_else, (uint16_t) (depth + 1));
19734 case PM_TOKEN_KEYWORD_UNDEF: {
19735 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19736 pm_parser_err_current(parser, PM_ERR_STATEMENT_UNDEF);
19739 parser_lex(parser);
19741 pm_node_t *name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19743 if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) {
19744 pm_node_destroy(parser, name);
19746 pm_undef_node_append(undef, name);
19748 while (match1(parser, PM_TOKEN_COMMA)) {
19749 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
19750 parser_lex(parser);
19751 name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19753 if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) {
19754 pm_node_destroy(parser, name);
19758 pm_undef_node_append(undef, name);
19764 case PM_TOKEN_KEYWORD_NOT: {
19765 parser_lex(parser);
19774 if (!accepts_command_call && !match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19775 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES)) {
19776 pm_parser_err(parser, parser->
previous.
end, parser->
previous.
end + 1, PM_ERR_EXPECT_LPAREN_AFTER_NOT_LPAREN);
19778 accept1(parser, PM_TOKEN_NEWLINE);
19779 pm_parser_err_current(parser, PM_ERR_EXPECT_LPAREN_AFTER_NOT_OTHER);
19785 accept1(parser, PM_TOKEN_NEWLINE);
19787 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19790 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19791 receiver = (
pm_node_t *) pm_parentheses_node_create(parser, &lparen, NULL, &parser->
previous, 0);
19793 arguments.
opening_loc = PM_LOCATION_TOKEN_VALUE(&lparen);
19794 receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19797 accept1(parser, PM_TOKEN_NEWLINE);
19798 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19803 receiver = parse_expression(parser, PM_BINDING_POWER_NOT,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19806 return (
pm_node_t *) pm_call_node_not_create(parser, receiver, &message, &arguments);
19808 case PM_TOKEN_KEYWORD_UNLESS: {
19809 size_t opening_newline_index = token_newline_index(parser);
19810 parser_lex(parser);
19812 return parse_conditional(parser,
PM_CONTEXT_UNLESS, opening_newline_index,
false, (uint16_t) (depth + 1));
19814 case PM_TOKEN_KEYWORD_MODULE: {
19816 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19818 size_t opening_newline_index = token_newline_index(parser);
19819 parser_lex(parser);
19822 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_MODULE_NAME, (uint16_t) (depth + 1));
19827 if (PM_NODE_TYPE_P(constant_path, PM_MISSING_NODE)) {
19828 pop_block_exits(parser, previous_block_exits);
19829 pm_node_list_free(¤t_block_exits);
19832 return (
pm_node_t *) pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing);
19835 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
19838 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
19839 constant_path = (
pm_node_t *) pm_constant_path_node_create(parser, constant_path, &double_colon, &parser->
previous);
19846 if (name.
type != PM_TOKEN_CONSTANT) {
19847 pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
19850 pm_parser_scope_push(parser,
true);
19851 accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE);
19854 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19855 pm_accepts_block_stack_push(parser,
true);
19857 pm_accepts_block_stack_pop(parser);
19860 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
19861 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
19862 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));
19864 parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword,
false,
false);
19870 pm_parser_scope_pop(parser);
19871 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM);
19873 if (context_def_p(parser)) {
19874 pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
19877 pop_block_exits(parser, previous_block_exits);
19878 pm_node_list_free(¤t_block_exits);
19880 return (
pm_node_t *) pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->
previous);
19882 case PM_TOKEN_KEYWORD_NIL:
19883 parser_lex(parser);
19885 case PM_TOKEN_KEYWORD_REDO: {
19886 parser_lex(parser);
19893 case PM_TOKEN_KEYWORD_RETRY: {
19894 parser_lex(parser);
19897 parse_retry(parser, node);
19901 case PM_TOKEN_KEYWORD_SELF:
19902 parser_lex(parser);
19904 case PM_TOKEN_KEYWORD_TRUE:
19905 parser_lex(parser);
19907 case PM_TOKEN_KEYWORD_UNTIL: {
19908 size_t opening_newline_index = token_newline_index(parser);
19911 pm_do_loop_stack_push(parser,
true);
19913 parser_lex(parser);
19915 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
19917 pm_do_loop_stack_pop(parser);
19918 context_pop(parser);
19921 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19924 do_keyword = not_provided(parser);
19925 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
19929 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19930 pm_accepts_block_stack_push(parser,
true);
19931 statements = parse_statements(parser,
PM_CONTEXT_UNTIL, (uint16_t) (depth + 1));
19932 pm_accepts_block_stack_pop(parser);
19933 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19936 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19937 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM);
19939 return (
pm_node_t *) pm_until_node_create(parser, &keyword, &do_keyword, &parser->
previous, predicate, statements, 0);
19941 case PM_TOKEN_KEYWORD_WHILE: {
19942 size_t opening_newline_index = token_newline_index(parser);
19945 pm_do_loop_stack_push(parser,
true);
19947 parser_lex(parser);
19949 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
19951 pm_do_loop_stack_pop(parser);
19952 context_pop(parser);
19955 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19958 do_keyword = not_provided(parser);
19959 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
19963 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19964 pm_accepts_block_stack_push(parser,
true);
19965 statements = parse_statements(parser,
PM_CONTEXT_WHILE, (uint16_t) (depth + 1));
19966 pm_accepts_block_stack_pop(parser);
19967 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19970 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19971 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM);
19973 return (
pm_node_t *) pm_while_node_create(parser, &keyword, &do_keyword, &parser->
previous, predicate, statements, 0);
19975 case PM_TOKEN_PERCENT_LOWER_I: {
19976 parser_lex(parser);
19980 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19981 accept1(parser, PM_TOKEN_WORDS_SEP);
19982 if (match1(parser, PM_TOKEN_STRING_END))
break;
19984 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19987 pm_array_node_elements_append(array, (
pm_node_t *) pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing));
19990 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_LOWER_ELEMENT);
19994 if (match1(parser, PM_TOKEN_EOF)) {
19995 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
19998 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_LOWER_TERM);
20000 pm_array_node_close_set(array, &closing);
20004 case PM_TOKEN_PERCENT_UPPER_I: {
20005 parser_lex(parser);
20013 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20014 switch (parser->
current.type) {
20015 case PM_TOKEN_WORDS_SEP: {
20016 if (current == NULL) {
20022 pm_array_node_elements_append(array, current);
20026 parser_lex(parser);
20029 case PM_TOKEN_STRING_CONTENT: {
20033 if (current == NULL) {
20037 current = (
pm_node_t *) pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing);
20038 parser_lex(parser);
20039 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
20044 parser_lex(parser);
20047 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20056 pm_node_t *second_string = (
pm_node_t *) pm_string_node_create_current_string(parser, &opening, &parser->
previous, &closing);
20057 parser_lex(parser);
20060 pm_interpolated_symbol_node_append(interpolated, first_string);
20061 pm_interpolated_symbol_node_append(interpolated, second_string);
20066 assert(
false &&
"unreachable");
20071 case PM_TOKEN_EMBVAR: {
20072 bool start_location_set =
false;
20073 if (current == NULL) {
20079 current = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
20080 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20089 pm_interpolated_symbol_node_append(interpolated, current);
20091 start_location_set =
true;
20098 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20100 if (!start_location_set) {
20105 case PM_TOKEN_EMBEXPR_BEGIN: {
20106 bool start_location_set =
false;
20107 if (current == NULL) {
20113 current = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
20114 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20124 pm_interpolated_symbol_node_append(interpolated, current);
20126 start_location_set =
true;
20128 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
20132 assert(
false &&
"unreachable");
20135 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20137 if (!start_location_set) {
20143 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_UPPER_ELEMENT);
20144 parser_lex(parser);
20151 pm_array_node_elements_append(array, current);
20155 if (match1(parser, PM_TOKEN_EOF)) {
20156 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_UPPER_TERM);
20159 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_UPPER_TERM);
20161 pm_array_node_close_set(array, &closing);
20165 case PM_TOKEN_PERCENT_LOWER_W: {
20166 parser_lex(parser);
20171 accept1(parser, PM_TOKEN_WORDS_SEP);
20173 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20174 accept1(parser, PM_TOKEN_WORDS_SEP);
20175 if (match1(parser, PM_TOKEN_STRING_END))
break;
20177 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20182 pm_array_node_elements_append(array,
string);
20185 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_LOWER_ELEMENT);
20189 if (match1(parser, PM_TOKEN_EOF)) {
20190 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_LOWER_TERM);
20193 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_LOWER_TERM);
20196 pm_array_node_close_set(array, &closing);
20199 case PM_TOKEN_PERCENT_UPPER_W: {
20200 parser_lex(parser);
20208 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20209 switch (parser->
current.type) {
20210 case PM_TOKEN_WORDS_SEP: {
20215 if (current == NULL) {
20222 pm_array_node_elements_append(array, current);
20226 parser_lex(parser);
20229 case PM_TOKEN_STRING_CONTENT: {
20234 pm_node_flag_set(
string, parse_unescaped_encoding(parser));
20235 parser_lex(parser);
20237 if (current == NULL) {
20243 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
20248 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20254 pm_interpolated_string_node_append(interpolated, current);
20255 pm_interpolated_string_node_append(interpolated,
string);
20258 assert(
false &&
"unreachable");
20263 case PM_TOKEN_EMBVAR: {
20264 if (current == NULL) {
20271 current = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
20272 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20280 pm_interpolated_string_node_append(interpolated, current);
20288 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20292 case PM_TOKEN_EMBEXPR_BEGIN: {
20293 if (current == NULL) {
20300 current = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
20301 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20309 pm_interpolated_string_node_append(interpolated, current);
20311 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
20316 assert(
false &&
"unreachable");
20319 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20324 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_UPPER_ELEMENT);
20325 parser_lex(parser);
20332 pm_array_node_elements_append(array, current);
20336 if (match1(parser, PM_TOKEN_EOF)) {
20337 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_UPPER_TERM);
20340 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_UPPER_TERM);
20343 pm_array_node_close_set(array, &closing);
20346 case PM_TOKEN_REGEXP_BEGIN: {
20348 parser_lex(parser);
20350 if (match1(parser, PM_TOKEN_REGEXP_END)) {
20355 .
type = PM_TOKEN_STRING_CONTENT,
20360 parser_lex(parser);
20363 pm_node_flag_set(node, PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING);
20370 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20378 parser_lex(parser);
20383 if (accept1(parser, PM_TOKEN_REGEXP_END)) {
20390 if (!match1(parser, PM_TOKEN_EQUAL_TILDE)) {
20391 parse_regular_expression_errors(parser, node);
20394 pm_node_flag_set((
pm_node_t *) node, parse_and_validate_regular_expression_encoding(parser, &unescaped, ascii_only, node->base.
flags));
20400 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20410 pm_node_flag_set(part, PM_STRING_FLAGS_FORCED_BINARY_ENCODING);
20413 pm_interpolated_regular_expression_node_append(interpolated, part);
20418 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20424 while (!match2(parser, PM_TOKEN_REGEXP_END, PM_TOKEN_EOF)) {
20425 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20426 pm_interpolated_regular_expression_node_append(interpolated, part);
20431 if (match1(parser, PM_TOKEN_EOF)) {
20432 pm_parser_err_token(parser, &opening, PM_ERR_REGEXP_TERM);
20435 expect1(parser, PM_TOKEN_REGEXP_END, PM_ERR_REGEXP_TERM);
20438 pm_interpolated_regular_expression_node_closing_set(parser, interpolated, &closing);
20441 case PM_TOKEN_BACKTICK:
20442 case PM_TOKEN_PERCENT_LOWER_X: {
20443 parser_lex(parser);
20450 if (match1(parser, PM_TOKEN_STRING_END)) {
20455 .
type = PM_TOKEN_STRING_CONTENT,
20460 parser_lex(parser);
20461 return (
pm_node_t *) pm_xstring_node_create(parser, &opening, &content, &parser->
previous);
20466 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20473 parser_lex(parser);
20475 if (match1(parser, PM_TOKEN_STRING_END)) {
20476 pm_node_t *node = (
pm_node_t *) pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
20477 pm_node_flag_set(node, parse_unescaped_encoding(parser));
20478 parser_lex(parser);
20484 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20490 pm_node_flag_set(part, parse_unescaped_encoding(parser));
20492 pm_interpolated_xstring_node_append(node, part);
20497 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20501 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20502 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20503 pm_interpolated_xstring_node_append(node, part);
20508 if (match1(parser, PM_TOKEN_EOF)) {
20509 pm_parser_err_token(parser, &opening, PM_ERR_XSTRING_TERM);
20512 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_XSTRING_TERM);
20514 pm_interpolated_xstring_node_closing_set(node, &closing);
20518 case PM_TOKEN_USTAR: {
20519 parser_lex(parser);
20524 if (binding_power != PM_BINDING_POWER_STATEMENT) {
20525 pm_parser_err_prefix(parser, diag_id);
20532 if (token_begins_expression_p(parser->
current.type)) {
20533 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
20538 if (match1(parser, PM_TOKEN_COMMA)) {
20539 return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
20541 return parse_target_validate(parser, splat,
true);
20544 case PM_TOKEN_BANG: {
20545 if (binding_power > PM_BINDING_POWER_UNARY) {
20546 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20549 parser_lex(parser);
20552 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));
20553 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"!");
20555 pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
20558 case PM_TOKEN_TILDE: {
20559 if (binding_power > PM_BINDING_POWER_UNARY) {
20560 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20562 parser_lex(parser);
20565 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20566 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"~");
20570 case PM_TOKEN_UMINUS: {
20571 if (binding_power > PM_BINDING_POWER_UNARY) {
20572 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20574 parser_lex(parser);
20577 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20578 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"-@");
20582 case PM_TOKEN_UMINUS_NUM: {
20583 parser_lex(parser);
20586 pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20588 if (accept1(parser, PM_TOKEN_STAR_STAR)) {
20590 pm_node_t *exponent = parse_expression(parser, pm_binding_powers[exponent_operator.
type].right,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
20591 node = (
pm_node_t *) pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0);
20592 node = (
pm_node_t *) pm_call_node_unary_create(parser, &
operator, node,
"-@");
20594 switch (PM_NODE_TYPE(node)) {
20595 case PM_INTEGER_NODE:
20596 case PM_FLOAT_NODE:
20597 case PM_RATIONAL_NODE:
20598 case PM_IMAGINARY_NODE:
20599 parse_negative_numeric(node);
20602 node = (
pm_node_t *) pm_call_node_unary_create(parser, &
operator, node,
"-@");
20609 case PM_TOKEN_MINUS_GREATER: {
20613 size_t opening_newline_index = token_newline_index(parser);
20614 pm_accepts_block_stack_push(parser,
true);
20615 parser_lex(parser);
20618 pm_parser_scope_push(parser,
false);
20622 switch (parser->
current.type) {
20623 case PM_TOKEN_PARENTHESIS_LEFT: {
20625 parser_lex(parser);
20627 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
20628 block_parameters = pm_block_parameters_node_create(parser, NULL, &opening);
20630 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
true, (uint16_t) (depth + 1));
20633 accept1(parser, PM_TOKEN_NEWLINE);
20634 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
20636 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
20639 case PM_CASE_PARAMETER: {
20640 pm_accepts_block_stack_push(parser,
false);
20642 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
false, (uint16_t) (depth + 1));
20643 pm_accepts_block_stack_pop(parser);
20647 block_parameters = NULL;
20656 if (accept1(parser, PM_TOKEN_LAMBDA_BEGIN)) {
20659 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
20663 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20664 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE);
20666 expect1(parser, PM_TOKEN_KEYWORD_DO, PM_ERR_LAMBDA_OPEN);
20669 if (!match3(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20670 pm_accepts_block_stack_push(parser,
true);
20672 pm_accepts_block_stack_pop(parser);
20675 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20676 assert(body == NULL || PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE));
20677 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));
20679 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20682 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END);
20686 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
20689 pm_parser_scope_pop(parser);
20690 pm_accepts_block_stack_pop(parser);
20692 return (
pm_node_t *) pm_lambda_node_create(parser, &locals, &
operator, &opening, &parser->
previous, parameters, body);
20694 case PM_TOKEN_UPLUS: {
20695 if (binding_power > PM_BINDING_POWER_UNARY) {
20696 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20698 parser_lex(parser);
20701 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20702 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"+@");
20706 case PM_TOKEN_STRING_BEGIN:
20707 return parse_strings(parser, NULL, accepts_label, (uint16_t) (depth + 1));
20708 case PM_TOKEN_SYMBOL_BEGIN: {
20710 parser_lex(parser);
20712 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_END, (uint16_t) (depth + 1));
20723 if (diag_id != PM_ERR_CANNOT_PARSE_EXPRESSION) {
20724 pm_parser_err_prefix(parser, diag_id);
20730 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT,
pm_token_type_human(parser->
current.type), context_human(recoverable));
20731 }
else if (diag_id == PM_ERR_CANNOT_PARSE_EXPRESSION) {
20737 pm_parser_err_prefix(parser, diag_id);
20755parse_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) {
20756 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));
20760 if (match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
20764 parser_lex(parser);
20766 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));
20767 context_pop(parser);
20769 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
20781 switch (PM_NODE_TYPE(node)) {
20782 case PM_BEGIN_NODE: {
20787 case PM_LOCAL_VARIABLE_WRITE_NODE: {
20789 pm_locals_read(&pm_parser_scope_find(parser, cast->
depth)->
locals, cast->
name);
20792 case PM_PARENTHESES_NODE: {
20794 if (cast->
body != NULL) parse_assignment_value_local(parser, cast->
body);
20797 case PM_STATEMENTS_NODE: {
20802 parse_assignment_value_local(parser, statement);
20824parse_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) {
20825 bool permitted =
true;
20826 if (previous_binding_power != PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_USTAR)) permitted =
false;
20828 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_MATCH, diag_id, (uint16_t) (depth + 1));
20829 if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE);
20831 parse_assignment_value_local(parser, value);
20832 bool single_value =
true;
20834 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && (PM_NODE_TYPE_P(value, PM_SPLAT_NODE) || match1(parser, PM_TOKEN_COMMA))) {
20835 single_value =
false;
20840 pm_array_node_elements_append(array, value);
20843 while (accept1(parser, PM_TOKEN_COMMA)) {
20844 pm_node_t *element = parse_starred_expression(parser, binding_power,
false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1));
20846 pm_array_node_elements_append(array, element);
20847 if (PM_NODE_TYPE_P(element, PM_MISSING_NODE))
break;
20849 parse_assignment_value_local(parser, element);
20855 if ((single_value || (binding_power == (PM_BINDING_POWER_MULTI_ASSIGNMENT + 1))) && match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
20859 parser_lex(parser);
20861 bool accepts_command_call_inner =
false;
20865 if (PM_NODE_TYPE_P(value, PM_CALL_NODE)) {
20868 accepts_command_call_inner =
true;
20872 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));
20873 context_pop(parser);
20875 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
20891 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_ARGUMENTS);
20896 if (call_node->
block != NULL) {
20897 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_BLOCK);
20899 call_node->
block = NULL;
20928static inline const uint8_t *
20929pm_named_capture_escape_hex(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
20932 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
20933 uint8_t value = escape_hexadecimal_digit(*cursor);
20936 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
20937 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(*cursor));
20941 pm_buffer_append_byte(unescaped, value);
20943 pm_buffer_append_string(unescaped,
"\\x", 2);
20949static inline const uint8_t *
20950pm_named_capture_escape_octal(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
20951 uint8_t value = (uint8_t) (*cursor -
'0');
20954 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
20955 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
20958 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
20959 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
20964 pm_buffer_append_byte(unescaped, value);
20968static inline const uint8_t *
20969pm_named_capture_escape_unicode(
pm_parser_t *parser,
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
20970 const uint8_t *start = cursor - 1;
20973 if (cursor >= end) {
20974 pm_buffer_append_string(unescaped,
"\\u", 2);
20978 if (*cursor !=
'{') {
20979 size_t length = pm_strspn_hexadecimal_digit(cursor, MIN(end - cursor, 4));
20980 uint32_t value = escape_unicode(parser, cursor, length);
20982 if (!pm_buffer_append_unicode_codepoint(unescaped, value)) {
20983 pm_buffer_append_string(unescaped, (
const char *) start, (
size_t) ((cursor + length) - start));
20986 return cursor + length;
20991 while (cursor < end && *cursor ==
' ') cursor++;
20993 if (cursor >= end)
break;
20994 if (*cursor ==
'}') {
20999 size_t length = pm_strspn_hexadecimal_digit(cursor, end - cursor);
21000 uint32_t value = escape_unicode(parser, cursor, length);
21002 (void) pm_buffer_append_unicode_codepoint(unescaped, value);
21010pm_named_capture_escape(
pm_parser_t *parser,
pm_buffer_t *unescaped,
const uint8_t *source,
const size_t length,
const uint8_t *cursor) {
21011 const uint8_t *end = source + length;
21012 pm_buffer_append_string(unescaped, (
const char *) source, (
size_t) (cursor - source));
21015 if (++cursor >= end) {
21016 pm_buffer_append_byte(unescaped,
'\\');
21022 cursor = pm_named_capture_escape_hex(unescaped, cursor, end);
21024 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
21025 cursor = pm_named_capture_escape_octal(unescaped, cursor, end);
21028 cursor = pm_named_capture_escape_unicode(parser, unescaped, cursor, end);
21031 pm_buffer_append_byte(unescaped,
'\\');
21035 const uint8_t *next_cursor = pm_memchr(cursor,
'\\', (
size_t) (end - cursor), parser->
encoding_changed, parser->
encoding);
21036 if (next_cursor == NULL)
break;
21038 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (next_cursor - cursor));
21039 cursor = next_cursor;
21042 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (end - cursor));
21050parse_regular_expression_named_capture(
const pm_string_t *capture,
void *data) {
21057 const uint8_t *source = pm_string_source(capture);
21058 size_t length = pm_string_length(capture);
21071 pm_named_capture_escape(parser, &unescaped, source, length, cursor);
21072 source = (
const uint8_t *) pm_buffer_value(&unescaped);
21073 length = pm_buffer_length(&unescaped);
21081 if (!pm_slice_is_valid_local(parser, source, source + length)) {
21082 pm_buffer_free(&unescaped);
21086 if (callback_data->
shared) {
21090 name = pm_parser_constant_id_location(parser, location.
start, location.
end);
21096 void *memory =
xmalloc(length);
21097 if (memory == NULL) abort();
21099 memcpy(memory, source, length);
21100 name = pm_parser_constant_id_owned(parser, (uint8_t *) memory, length);
21105 if (name != 0 && !pm_constant_id_list_includes(names, name)) {
21106 pm_constant_id_list_append(names, name);
21109 if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
21112 if (pm_local_is_keyword((
const char *) source, length)) {
21113 pm_buffer_free(&unescaped);
21119 pm_parser_local_add(parser, name, location.
start, location.
end, 0);
21124 if (callback_data->
match == NULL) {
21125 callback_data->
match = pm_match_write_node_create(parser, call);
21130 pm_node_t *target = (
pm_node_t *) pm_local_variable_target_node_create(parser, &location, name, depth == -1 ? 0 : (uint32_t) depth);
21131 pm_node_list_append(&callback_data->
match->
targets, target);
21134 pm_buffer_free(&unescaped);
21147 .shared = content->
type == PM_STRING_SHARED
21154 .shared = content->
type == PM_STRING_SHARED
21157 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);
21158 pm_constant_id_list_free(&callback_data.
names);
21160 if (callback_data.
match != NULL) {
21168parse_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) {
21171 switch (token.type) {
21172 case PM_TOKEN_EQUAL: {
21173 switch (PM_NODE_TYPE(node)) {
21174 case PM_CALL_NODE: {
21180 if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21185 case PM_CASE_WRITABLE: {
21189 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
21193 parser_lex(parser);
21194 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));
21196 if (PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) && previous_binding_power != PM_BINDING_POWER_STATEMENT) {
21197 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_MULTI_WRITE);
21200 return parse_write(parser, node, &token, value);
21202 case PM_SPLAT_NODE: {
21204 pm_multi_target_node_targets_append(parser, multi_target, node);
21206 parser_lex(parser);
21207 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));
21208 return parse_write(parser, (
pm_node_t *) multi_target, &token, value);
21210 case PM_SOURCE_ENCODING_NODE:
21211 case PM_FALSE_NODE:
21212 case PM_SOURCE_FILE_NODE:
21213 case PM_SOURCE_LINE_NODE:
21216 case PM_TRUE_NODE: {
21219 parser_lex(parser);
21220 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));
21221 return parse_unwriteable_write(parser, node, &token, value);
21227 parser_lex(parser);
21228 pm_parser_err_token(parser, &token, PM_ERR_EXPRESSION_NOT_WRITABLE);
21232 case PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL: {
21233 switch (PM_NODE_TYPE(node)) {
21234 case PM_BACK_REFERENCE_READ_NODE:
21235 case PM_NUMBERED_REFERENCE_READ_NODE:
21236 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21238 case PM_GLOBAL_VARIABLE_READ_NODE: {
21239 parser_lex(parser);
21241 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));
21242 pm_node_t *result = (
pm_node_t *) pm_global_variable_and_write_node_create(parser, node, &token, value);
21244 pm_node_destroy(parser, node);
21247 case PM_CLASS_VARIABLE_READ_NODE: {
21248 parser_lex(parser);
21250 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));
21253 pm_node_destroy(parser, node);
21256 case PM_CONSTANT_PATH_NODE: {
21257 parser_lex(parser);
21259 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));
21262 return parse_shareable_constant_write(parser, write);
21264 case PM_CONSTANT_READ_NODE: {
21265 parser_lex(parser);
21267 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));
21270 pm_node_destroy(parser, node);
21271 return parse_shareable_constant_write(parser, write);
21273 case PM_INSTANCE_VARIABLE_READ_NODE: {
21274 parser_lex(parser);
21276 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));
21279 pm_node_destroy(parser, node);
21282 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21284 parser_lex(parser);
21286 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));
21287 pm_node_t *result = (
pm_node_t *) pm_local_variable_and_write_node_create(parser, node, &token, value, name, 0);
21289 parse_target_implicit_parameter(parser, node);
21290 pm_node_destroy(parser, node);
21293 case PM_LOCAL_VARIABLE_READ_NODE: {
21296 parse_target_implicit_parameter(parser, node);
21300 parser_lex(parser);
21302 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));
21305 pm_node_destroy(parser, node);
21308 case PM_CALL_NODE: {
21314 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21316 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21319 parser_lex(parser);
21321 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));
21322 pm_node_t *result = (
pm_node_t *) pm_local_variable_and_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21324 pm_node_destroy(parser, (
pm_node_t *) cast);
21330 parser_lex(parser);
21335 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21336 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21337 return (
pm_node_t *) pm_index_and_write_node_create(parser, cast, &token, value);
21341 if (pm_call_node_writable_p(parser, cast)) {
21342 parse_write_name(parser, &cast->
name);
21344 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21347 parse_call_operator_write(parser, cast, &token);
21348 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));
21349 return (
pm_node_t *) pm_call_and_write_node_create(parser, cast, &token, value);
21351 case PM_MULTI_WRITE_NODE: {
21352 parser_lex(parser);
21353 pm_parser_err_token(parser, &token, PM_ERR_AMPAMPEQ_MULTI_ASSIGN);
21357 parser_lex(parser);
21362 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
21366 case PM_TOKEN_PIPE_PIPE_EQUAL: {
21367 switch (PM_NODE_TYPE(node)) {
21368 case PM_BACK_REFERENCE_READ_NODE:
21369 case PM_NUMBERED_REFERENCE_READ_NODE:
21370 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21372 case PM_GLOBAL_VARIABLE_READ_NODE: {
21373 parser_lex(parser);
21375 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21376 pm_node_t *result = (
pm_node_t *) pm_global_variable_or_write_node_create(parser, node, &token, value);
21378 pm_node_destroy(parser, node);
21381 case PM_CLASS_VARIABLE_READ_NODE: {
21382 parser_lex(parser);
21384 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21387 pm_node_destroy(parser, node);
21390 case PM_CONSTANT_PATH_NODE: {
21391 parser_lex(parser);
21393 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21396 return parse_shareable_constant_write(parser, write);
21398 case PM_CONSTANT_READ_NODE: {
21399 parser_lex(parser);
21401 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21404 pm_node_destroy(parser, node);
21405 return parse_shareable_constant_write(parser, write);
21407 case PM_INSTANCE_VARIABLE_READ_NODE: {
21408 parser_lex(parser);
21410 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21413 pm_node_destroy(parser, node);
21416 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21418 parser_lex(parser);
21420 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21421 pm_node_t *result = (
pm_node_t *) pm_local_variable_or_write_node_create(parser, node, &token, value, name, 0);
21423 parse_target_implicit_parameter(parser, node);
21424 pm_node_destroy(parser, node);
21427 case PM_LOCAL_VARIABLE_READ_NODE: {
21430 parse_target_implicit_parameter(parser, node);
21434 parser_lex(parser);
21436 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21439 pm_node_destroy(parser, node);
21442 case PM_CALL_NODE: {
21448 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21450 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21453 parser_lex(parser);
21455 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21456 pm_node_t *result = (
pm_node_t *) pm_local_variable_or_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21458 pm_node_destroy(parser, (
pm_node_t *) cast);
21464 parser_lex(parser);
21469 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21470 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21471 return (
pm_node_t *) pm_index_or_write_node_create(parser, cast, &token, value);
21475 if (pm_call_node_writable_p(parser, cast)) {
21476 parse_write_name(parser, &cast->
name);
21478 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21481 parse_call_operator_write(parser, cast, &token);
21482 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21483 return (
pm_node_t *) pm_call_or_write_node_create(parser, cast, &token, value);
21485 case PM_MULTI_WRITE_NODE: {
21486 parser_lex(parser);
21487 pm_parser_err_token(parser, &token, PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN);
21491 parser_lex(parser);
21496 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
21500 case PM_TOKEN_AMPERSAND_EQUAL:
21501 case PM_TOKEN_CARET_EQUAL:
21502 case PM_TOKEN_GREATER_GREATER_EQUAL:
21503 case PM_TOKEN_LESS_LESS_EQUAL:
21504 case PM_TOKEN_MINUS_EQUAL:
21505 case PM_TOKEN_PERCENT_EQUAL:
21506 case PM_TOKEN_PIPE_EQUAL:
21507 case PM_TOKEN_PLUS_EQUAL:
21508 case PM_TOKEN_SLASH_EQUAL:
21509 case PM_TOKEN_STAR_EQUAL:
21510 case PM_TOKEN_STAR_STAR_EQUAL: {
21511 switch (PM_NODE_TYPE(node)) {
21512 case PM_BACK_REFERENCE_READ_NODE:
21513 case PM_NUMBERED_REFERENCE_READ_NODE:
21514 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21516 case PM_GLOBAL_VARIABLE_READ_NODE: {
21517 parser_lex(parser);
21519 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));
21520 pm_node_t *result = (
pm_node_t *) pm_global_variable_operator_write_node_create(parser, node, &token, value);
21522 pm_node_destroy(parser, node);
21525 case PM_CLASS_VARIABLE_READ_NODE: {
21526 parser_lex(parser);
21528 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));
21531 pm_node_destroy(parser, node);
21534 case PM_CONSTANT_PATH_NODE: {
21535 parser_lex(parser);
21537 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));
21540 return parse_shareable_constant_write(parser, write);
21542 case PM_CONSTANT_READ_NODE: {
21543 parser_lex(parser);
21545 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));
21548 pm_node_destroy(parser, node);
21549 return parse_shareable_constant_write(parser, write);
21551 case PM_INSTANCE_VARIABLE_READ_NODE: {
21552 parser_lex(parser);
21554 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21557 pm_node_destroy(parser, node);
21560 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21562 parser_lex(parser);
21564 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));
21565 pm_node_t *result = (
pm_node_t *) pm_local_variable_operator_write_node_create(parser, node, &token, value, name, 0);
21567 parse_target_implicit_parameter(parser, node);
21568 pm_node_destroy(parser, node);
21571 case PM_LOCAL_VARIABLE_READ_NODE: {
21574 parse_target_implicit_parameter(parser, node);
21578 parser_lex(parser);
21580 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));
21581 pm_node_t *result = (
pm_node_t *) pm_local_variable_operator_write_node_create(parser, node, &token, value, cast->
name, cast->
depth);
21583 pm_node_destroy(parser, node);
21586 case PM_CALL_NODE: {
21587 parser_lex(parser);
21593 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21595 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21598 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));
21599 pm_node_t *result = (
pm_node_t *) pm_local_variable_operator_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21601 pm_node_destroy(parser, (
pm_node_t *) cast);
21608 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21609 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));
21610 return (
pm_node_t *) pm_index_operator_write_node_create(parser, cast, &token, value);
21614 if (pm_call_node_writable_p(parser, cast)) {
21615 parse_write_name(parser, &cast->
name);
21617 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21620 parse_call_operator_write(parser, cast, &token);
21621 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21622 return (
pm_node_t *) pm_call_operator_write_node_create(parser, cast, &token, value);
21624 case PM_MULTI_WRITE_NODE: {
21625 parser_lex(parser);
21626 pm_parser_err_token(parser, &token, PM_ERR_OPERATOR_MULTI_ASSIGN);
21630 parser_lex(parser);
21639 case PM_TOKEN_AMPERSAND_AMPERSAND:
21640 case PM_TOKEN_KEYWORD_AND: {
21641 parser_lex(parser);
21643 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));
21644 return (
pm_node_t *) pm_and_node_create(parser, node, &token, right);
21646 case PM_TOKEN_KEYWORD_OR:
21647 case PM_TOKEN_PIPE_PIPE: {
21648 parser_lex(parser);
21650 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));
21651 return (
pm_node_t *) pm_or_node_create(parser, node, &token, right);
21653 case PM_TOKEN_EQUAL_TILDE: {
21661 parser_lex(parser);
21662 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21665 pm_call_node_t *call = pm_call_node_binary_create(parser, node, &token, argument, 0);
21671 if (PM_NODE_TYPE_P(node, PM_INTERPOLATED_REGULAR_EXPRESSION_NODE)) {
21678 bool interpolated =
false;
21679 size_t total_length = 0;
21683 if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
21684 total_length += pm_string_length(&((
pm_string_node_t *) part)->unescaped);
21686 interpolated =
true;
21691 if (!interpolated && total_length > 0) {
21692 void *memory =
xmalloc(total_length);
21693 if (!memory) abort();
21695 uint8_t *cursor = memory;
21698 size_t length = pm_string_length(unescaped);
21700 memcpy(cursor, pm_string_source(unescaped), length);
21705 pm_string_owned_init(&owned, (uint8_t *) memory, total_length);
21707 result = parse_regular_expression_named_captures(parser, &owned, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
21708 pm_string_free(&owned);
21710 }
else if (PM_NODE_TYPE_P(node, PM_REGULAR_EXPRESSION_NODE)) {
21714 result = parse_regular_expression_named_captures(parser, content, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
21719 case PM_TOKEN_UAMPERSAND:
21720 case PM_TOKEN_USTAR:
21721 case PM_TOKEN_USTAR_STAR:
21724 case PM_TOKEN_BANG_EQUAL:
21725 case PM_TOKEN_BANG_TILDE:
21726 case PM_TOKEN_EQUAL_EQUAL:
21727 case PM_TOKEN_EQUAL_EQUAL_EQUAL:
21728 case PM_TOKEN_LESS_EQUAL_GREATER:
21729 case PM_TOKEN_CARET:
21730 case PM_TOKEN_PIPE:
21731 case PM_TOKEN_AMPERSAND:
21732 case PM_TOKEN_GREATER_GREATER:
21733 case PM_TOKEN_LESS_LESS:
21734 case PM_TOKEN_MINUS:
21735 case PM_TOKEN_PLUS:
21736 case PM_TOKEN_PERCENT:
21737 case PM_TOKEN_SLASH:
21738 case PM_TOKEN_STAR:
21739 case PM_TOKEN_STAR_STAR: {
21740 parser_lex(parser);
21742 switch (PM_NODE_TYPE(node)) {
21743 case PM_RESCUE_MODIFIER_NODE: {
21746 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21750 case PM_AND_NODE: {
21752 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21753 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21759 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21760 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21768 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21769 return (
pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument, 0);
21771 case PM_TOKEN_GREATER:
21772 case PM_TOKEN_GREATER_EQUAL:
21773 case PM_TOKEN_LESS:
21774 case PM_TOKEN_LESS_EQUAL: {
21775 if (PM_NODE_TYPE_P(node, PM_CALL_NODE) && PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_COMPARISON)) {
21776 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_COMPARISON_AFTER_COMPARISON);
21779 parser_lex(parser);
21780 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21781 return (
pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON);
21783 case PM_TOKEN_AMPERSAND_DOT:
21784 case PM_TOKEN_DOT: {
21785 parser_lex(parser);
21790 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
21791 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21792 return (
pm_node_t *) pm_call_node_shorthand_create(parser, node, &
operator, &arguments);
21795 switch (PM_NODE_TYPE(node)) {
21796 case PM_RESCUE_MODIFIER_NODE: {
21799 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21803 case PM_AND_NODE: {
21805 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21806 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21812 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21813 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21823 switch (parser->
current.type) {
21824 case PM_CASE_OPERATOR:
21825 case PM_CASE_KEYWORD:
21826 case PM_TOKEN_CONSTANT:
21827 case PM_TOKEN_IDENTIFIER:
21828 case PM_TOKEN_METHOD_NAME: {
21829 parser_lex(parser);
21839 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21840 pm_call_node_t *call = pm_call_node_call_create(parser, node, &
operator, &message, &arguments);
21843 (previous_binding_power == PM_BINDING_POWER_STATEMENT) &&
21846 match1(parser, PM_TOKEN_COMMA)
21848 return parse_targets_validate(parser, (
pm_node_t *) call, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21853 case PM_TOKEN_DOT_DOT:
21854 case PM_TOKEN_DOT_DOT_DOT: {
21855 parser_lex(parser);
21858 if (token_begins_expression_p(parser->
current.type)) {
21859 right = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21862 return (
pm_node_t *) pm_range_node_create(parser, node, &token, right);
21864 case PM_TOKEN_KEYWORD_IF_MODIFIER: {
21866 parser_lex(parser);
21868 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
21869 return (
pm_node_t *) pm_if_node_modifier_create(parser, node, &keyword, predicate);
21871 case PM_TOKEN_KEYWORD_UNLESS_MODIFIER: {
21873 parser_lex(parser);
21875 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
21876 return (
pm_node_t *) pm_unless_node_modifier_create(parser, node, &keyword, predicate);
21878 case PM_TOKEN_KEYWORD_UNTIL_MODIFIER: {
21879 parser_lex(parser);
21881 pm_statements_node_body_append(parser, statements, node,
true);
21883 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
21884 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);
21886 case PM_TOKEN_KEYWORD_WHILE_MODIFIER: {
21887 parser_lex(parser);
21889 pm_statements_node_body_append(parser, statements, node,
true);
21891 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
21892 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);
21894 case PM_TOKEN_QUESTION_MARK: {
21897 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
21900 parser_lex(parser);
21902 pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_TRUE, (uint16_t) (depth + 1));
21914 context_pop(parser);
21915 pop_block_exits(parser, previous_block_exits);
21916 pm_node_list_free(¤t_block_exits);
21918 return (
pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
21921 accept1(parser, PM_TOKEN_NEWLINE);
21922 expect1(parser, PM_TOKEN_COLON, PM_ERR_TERNARY_COLON);
21925 pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_FALSE, (uint16_t) (depth + 1));
21927 context_pop(parser);
21928 pop_block_exits(parser, previous_block_exits);
21929 pm_node_list_free(¤t_block_exits);
21931 return (
pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
21933 case PM_TOKEN_COLON_COLON: {
21934 parser_lex(parser);
21937 switch (parser->
current.type) {
21938 case PM_TOKEN_CONSTANT: {
21939 parser_lex(parser);
21943 (parser->
current.type == PM_TOKEN_PARENTHESIS_LEFT) ||
21944 (accepts_command_call && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)))
21955 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21956 path = (
pm_node_t *) pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
21959 path = (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
21963 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
21964 return parse_targets_validate(parser, path, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21969 case PM_CASE_OPERATOR:
21970 case PM_CASE_KEYWORD:
21971 case PM_TOKEN_IDENTIFIER:
21972 case PM_TOKEN_METHOD_NAME: {
21973 parser_lex(parser);
21979 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21980 pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
21983 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
21984 return parse_targets_validate(parser, (
pm_node_t *) call, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21989 case PM_TOKEN_PARENTHESIS_LEFT: {
21993 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21995 return (
pm_node_t *) pm_call_node_shorthand_create(parser, node, &delimiter, &arguments);
21998 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
21999 return (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
22003 case PM_TOKEN_KEYWORD_RESCUE_MODIFIER: {
22005 parser_lex(parser);
22006 accept1(parser, PM_TOKEN_NEWLINE);
22008 pm_node_t *value = parse_expression(parser, binding_power,
true,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
22009 context_pop(parser);
22011 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, node, &token, value);
22013 case PM_TOKEN_BRACKET_LEFT: {
22014 parser_lex(parser);
22019 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
22020 pm_accepts_block_stack_push(parser,
true);
22021 parse_arguments(parser, &arguments,
false, PM_TOKEN_BRACKET_RIGHT, (uint16_t) (depth + 1));
22022 pm_accepts_block_stack_pop(parser);
22023 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_EXPECT_RBRACKET);
22030 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
22031 pm_call_node_t *aref = pm_call_node_aref_create(parser, node, &arguments);
22032 return parse_targets_validate(parser, (
pm_node_t *) aref, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22039 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
22040 block = parse_block(parser, (uint16_t) (depth + 1));
22041 pm_arguments_validate_block(parser, &arguments, block);
22042 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
22043 block = parse_block(parser, (uint16_t) (depth + 1));
22046 if (block != NULL) {
22047 if (arguments.
block != NULL) {
22048 pm_parser_err_node(parser, (
pm_node_t *) block, PM_ERR_ARGUMENT_AFTER_BLOCK);
22050 arguments.
arguments = pm_arguments_node_create(parser);
22052 pm_arguments_node_arguments_append(arguments.
arguments, arguments.
block);
22058 return (
pm_node_t *) pm_call_node_aref_create(parser, node, &arguments);
22060 case PM_TOKEN_KEYWORD_IN: {
22066 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
22067 parser_lex(parser);
22070 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));
22073 pm_constant_id_list_free(&captures);
22075 return (
pm_node_t *) pm_match_predicate_node_create(parser, node, pattern, &
operator);
22077 case PM_TOKEN_EQUAL_GREATER: {
22083 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
22084 parser_lex(parser);
22087 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));
22090 pm_constant_id_list_free(&captures);
22092 return (
pm_node_t *) pm_match_required_node_create(parser, node, pattern, &
operator);
22095 assert(
false &&
"unreachable");
22100#undef PM_PARSE_PATTERN_SINGLE
22101#undef PM_PARSE_PATTERN_TOP
22102#undef PM_PARSE_PATTERN_MULTI
22112 (node->
block == NULL || PM_NODE_TYPE_P(node->
block, PM_BLOCK_ARGUMENT_NODE)) &&
22126parse_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) {
22128 pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
22132 pm_node_t *node = parse_expression_prefix(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
22134 switch (PM_NODE_TYPE(node)) {
22135 case PM_MISSING_NODE:
22139 case PM_PRE_EXECUTION_NODE:
22140 case PM_POST_EXECUTION_NODE:
22141 case PM_ALIAS_GLOBAL_VARIABLE_NODE:
22142 case PM_ALIAS_METHOD_NODE:
22143 case PM_MULTI_WRITE_NODE:
22144 case PM_UNDEF_NODE:
22147 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
22157 if ((pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_COMPOSITION) && pm_call_node_command_p((
pm_call_node_t *) node)) {
22161 case PM_SYMBOL_NODE:
22165 if (pm_symbol_node_label_p(node)) {
22176 pm_token_type_t current_token_type;
22179 current_token_type = parser->
current.type,
22180 current_binding_powers = pm_binding_powers[current_token_type],
22181 binding_power <= current_binding_powers.
left &&
22182 current_binding_powers.
binary
22184 node = parse_expression_infix(parser, node, binding_power, current_binding_powers.
right, accepts_command_call, (uint16_t) (depth + 1));
22192 switch (PM_NODE_TYPE(node)) {
22193 case PM_MULTI_WRITE_NODE:
22196 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
22200 case PM_CLASS_VARIABLE_WRITE_NODE:
22201 case PM_CONSTANT_PATH_WRITE_NODE:
22202 case PM_CONSTANT_WRITE_NODE:
22203 case PM_GLOBAL_VARIABLE_WRITE_NODE:
22204 case PM_INSTANCE_VARIABLE_WRITE_NODE:
22205 case PM_LOCAL_VARIABLE_WRITE_NODE:
22208 if (PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
22216 if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
22226 if (current_binding_powers.
nonassoc) {
22229 if (match1(parser, current_token_type)) {
22241 if (PM_NODE_TYPE_P(node, PM_RANGE_NODE) && ((
pm_range_node_t *) node)->right == NULL) {
22242 if (match4(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_DOT, PM_TOKEN_AMPERSAND_DOT)) {
22247 if (PM_BINDING_POWER_TERM <= pm_binding_powers[parser->
current.type].left) {
22250 }
else if (current_binding_powers.
left <= pm_binding_powers[parser->
current.type].left) {
22255 if (accepts_command_call) {
22264 switch (node->
type) {
22265 case PM_CALL_NODE: {
22279 cast->
block == NULL &&
22289 cast->
block != NULL && PM_NODE_TYPE_P(cast->
block, PM_BLOCK_NODE)
22292 accepts_command_call =
false;
22297 case PM_CONSTANT_PATH_NODE:
22300 accepts_command_call =
false;
22315 if (PM_PARSER_COMMAND_LINE_OPTION_P(parser)) {
22316 if (statements == NULL) {
22317 statements = pm_statements_node_create(parser);
22321 pm_arguments_node_arguments_append(
22323 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2))
22326 pm_statements_node_body_append(parser, statements, (
pm_node_t *) pm_call_node_fcall_synthesized_create(
22329 pm_parser_constant_id_constant(parser,
"print", 5)
22333 if (PM_PARSER_COMMAND_LINE_OPTION_N(parser)) {
22334 if (PM_PARSER_COMMAND_LINE_OPTION_A(parser)) {
22335 if (statements == NULL) {
22336 statements = pm_statements_node_create(parser);
22340 pm_arguments_node_arguments_append(
22342 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$;", 2))
22345 pm_global_variable_read_node_t *receiver = pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2));
22346 pm_call_node_t *call = pm_call_node_call_synthesized_create(parser, (
pm_node_t *) receiver,
"split", arguments);
22350 pm_parser_constant_id_constant(parser,
"$F", 2),
22354 pm_statements_node_body_prepend(statements, (
pm_node_t *) write);
22358 pm_arguments_node_arguments_append(
22360 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$/", 2))
22363 if (PM_PARSER_COMMAND_LINE_OPTION_L(parser)) {
22365 pm_keyword_hash_node_elements_append(keywords, (
pm_node_t *) pm_assoc_node_create(
22367 (
pm_node_t *) pm_symbol_node_synthesized_create(parser,
"chomp"),
22369 (
pm_node_t *) pm_true_node_synthesized_create(parser)
22372 pm_arguments_node_arguments_append(arguments, (
pm_node_t *) keywords);
22373 pm_node_flag_set((
pm_node_t *) arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS);
22377 pm_statements_node_body_append(parser, wrapped_statements, (
pm_node_t *) pm_while_node_synthesized_create(
22379 (
pm_node_t *) pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser,
"gets", 4)),
22383 statements = wrapped_statements;
22398 pm_parser_scope_push(parser,
true);
22402 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
22404 parser_lex(parser);
22411 assert(statements->
body.
size > 0);
22412 pm_void_statement_check(parser, statements->
body.
nodes[statements->
body.
size - 1]);
22417 pm_parser_scope_pop(parser);
22422 statements = wrap_statements(parser, statements);
22424 flush_block_exits(parser, previous_block_exits);
22425 pm_node_list_free(¤t_block_exits);
22431 if (statements == NULL) {
22432 statements = pm_statements_node_create(parser);
22433 pm_statements_node_location_set(statements, parser->
start, parser->
start);
22436 return (
pm_node_t *) pm_program_node_create(parser, &locals, statements);
22453pm_strnstr(
const char *big,
const char *little,
size_t big_length) {
22454 size_t little_length = strlen(little);
22456 for (
const char *big_end = big + big_length; big < big_end; big++) {
22457 if (*big == *little && memcmp(big, little, little_length) == 0)
return big;
22464#define pm_parser_warn_shebang_carriage_return(parser, start, length) ((void) 0)
22472pm_parser_warn_shebang_carriage_return(
pm_parser_t *parser,
const uint8_t *start,
size_t length) {
22473 if (length > 2 && start[length - 2] ==
'\r' && start[length - 1] ==
'\n') {
22474 pm_parser_warn(parser, start, start + length, PM_WARN_SHEBANG_CARRIAGE_RETURN);
22485 const char *switches = pm_strnstr(engine,
" -", length);
22486 if (switches == NULL)
return;
22491 (
const uint8_t *) (switches + 1),
22492 length - ((
size_t) (switches - engine)) - 1,
22496 size_t encoding_length;
22497 if ((encoding_length = pm_string_length(&next_options.
encoding)) > 0) {
22498 const uint8_t *encoding_source = pm_string_source(&next_options.
encoding);
22499 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22511 assert(source != NULL);
22515 .lex_state = PM_LEX_STATE_BEG,
22516 .enclosure_nesting = 0,
22517 .lambda_enclosure_nesting = -1,
22518 .brace_nesting = 0,
22519 .do_loop_stack = 0,
22520 .accepts_block_stack = 0,
22523 .stack = {{ .mode = PM_LEX_DEFAULT }},
22527 .end = source + size,
22528 .previous = { .type = PM_TOKEN_EOF, .start = source, .end = source },
22529 .current = { .type = PM_TOKEN_EOF, .start = source, .end = source },
22530 .next_start = NULL,
22531 .heredoc_end = NULL,
22532 .data_loc = { .start = NULL, .end = NULL },
22533 .comment_list = { 0 },
22534 .magic_comment_list = { 0 },
22535 .warning_list = { 0 },
22536 .error_list = { 0 },
22537 .current_scope = NULL,
22538 .current_context = NULL,
22540 .encoding_changed_callback = NULL,
22541 .encoding_comment_start = source,
22542 .lex_callback = NULL,
22544 .constant_pool = { 0 },
22545 .newline_list = { 0 },
22549 .explicit_encoding = NULL,
22551 .parsing_eval =
false,
22552 .partial_script =
false,
22553 .command_start =
true,
22554 .recovering =
false,
22555 .encoding_locked =
false,
22556 .encoding_changed =
false,
22557 .pattern_matching_newlines =
false,
22558 .in_keyword_arg =
false,
22559 .current_block_exits = NULL,
22560 .semantic_token_seen =
false,
22562 .current_regular_expression_ascii_only =
false,
22563 .warn_mismatched_indentation =
true
22580 uint32_t constant_size = ((uint32_t) size) / 95;
22581 pm_constant_pool_init(&parser->
constant_pool, constant_size < 4 ? 4 : constant_size);
22586 size_t newline_size = size / 22;
22587 pm_newline_list_init(&parser->
newline_list, source, newline_size < 4 ? 4 : newline_size);
22590 if (options != NULL) {
22598 size_t encoding_length = pm_string_length(&options->
encoding);
22599 if (encoding_length > 0) {
22600 const uint8_t *encoding_source = pm_string_source(&options->
encoding);
22601 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22623 for (
size_t scope_index = 0; scope_index < options->
scopes_count; scope_index++) {
22625 pm_parser_scope_push(parser, scope_index == 0);
22631 for (
size_t local_index = 0; local_index < scope->
locals_count; local_index++) {
22632 const pm_string_t *local = pm_options_scope_local_get(scope, local_index);
22634 const uint8_t *source = pm_string_source(local);
22635 size_t length = pm_string_length(local);
22637 void *allocated =
xmalloc(length);
22638 if (allocated == NULL)
continue;
22640 memcpy(allocated, source, length);
22641 pm_parser_local_add_owned(parser, (uint8_t *) allocated, length);
22652 pm_accepts_block_stack_push(parser,
true);
22655 if (size >= 3 && source[0] == 0xef && source[1] == 0xbb && source[2] == 0xbf) {
22668 bool search_shebang = PM_PARSER_COMMAND_LINE_OPTION_X(parser);
22685 const uint8_t *newline = next_newline(parser->
start, parser->
end - parser->
start);
22686 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - parser->
start);
22688 if (length > 2 && parser->
current.end[0] ==
'#' && parser->
current.end[1] ==
'!') {
22689 const char *engine;
22691 if ((engine = pm_strnstr((
const char *) parser->
start,
"ruby", length)) != NULL) {
22692 if (newline != NULL) {
22696 pm_parser_warn_shebang_carriage_return(parser, parser->
start, length + 1);
22701 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) parser->
start)));
22704 search_shebang =
false;
22706 search_shebang =
true;
22712 if (search_shebang) {
22715 bool found_shebang =
false;
22719 const uint8_t *cursor = parser->
start;
22723 const uint8_t *newline = next_newline(cursor, parser->
end - cursor);
22725 while (newline != NULL) {
22726 pm_newline_list_append(&parser->
newline_list, newline);
22728 cursor = newline + 1;
22729 newline = next_newline(cursor, parser->
end - cursor);
22731 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - cursor);
22732 if (length > 2 && cursor[0] ==
'#' && cursor[1] ==
'!') {
22733 const char *engine;
22734 if ((engine = pm_strnstr((
const char *) cursor,
"ruby", length)) != NULL) {
22735 found_shebang =
true;
22737 if (newline != NULL) {
22738 pm_parser_warn_shebang_carriage_return(parser, cursor, length + 1);
22743 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) cursor)));
22751 if (found_shebang) {
22753 parser->
current = (
pm_token_t) { .type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
22755 pm_parser_err(parser, parser->
start, parser->
start, PM_ERR_SCRIPT_NOT_FOUND);
22782 for (node = list->
head; node != NULL; node = next) {
22794pm_magic_comment_list_free(
pm_list_t *list) {
22797 for (node = list->
head; node != NULL; node = next) {
22810 pm_string_free(&parser->
filepath);
22811 pm_diagnostic_list_free(&parser->
error_list);
22823 pm_parser_scope_pop(parser);
22827 lex_mode_pop(parser);
22836 return parse_program(parser);
22846#define LINE_SIZE 4096
22847 char line[LINE_SIZE];
22849 while (memset(line,
'\n', LINE_SIZE), stream_fgets(line, LINE_SIZE, stream) != NULL) {
22850 size_t length = LINE_SIZE;
22851 while (length > 0 && line[length - 1] ==
'\n') length--;
22853 if (length == LINE_SIZE) {
22858 pm_buffer_append_string(buffer, line, length);
22864 pm_buffer_append_string(buffer, line, length);
22872 if (strncmp(line,
"__END__", 7) == 0)
return false;
22875 if (strncmp(line,
"__END__\n", 8) == 0)
return false;
22878 if (strncmp(line,
"__END__\r\n", 9) == 0)
return false;
22884 if (stream_feof(stream)) {
22903pm_parse_stream_unterminated_heredoc_p(
pm_parser_t *parser) {
22906 for (; diagnostic != NULL; diagnostic = (
pm_diagnostic_t *) diagnostic->node.next) {
22907 if (diagnostic->diag_id == PM_ERR_HEREDOC_TERM) {
22923 pm_buffer_init(buffer);
22925 bool eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof);
22927 pm_parser_init(parser, (
const uint8_t *) pm_buffer_value(buffer), pm_buffer_length(buffer), options);
22931 pm_node_destroy(parser, node);
22932 eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof);
22934 pm_parser_free(parser);
22935 pm_parser_init(parser, (
const uint8_t *) pm_buffer_value(buffer), pm_buffer_length(buffer), options);
22936 node = pm_parse(parser);
22946pm_parse_success_p(
const uint8_t *source,
size_t size,
const char *data) {
22948 pm_options_read(&options, data);
22951 pm_parser_init(&parser, source, size, &options);
22954 pm_node_destroy(&parser, node);
22957 pm_parser_free(&parser);
22958 pm_options_free(&options);
22963#undef PM_CASE_KEYWORD
22964#undef PM_CASE_OPERATOR
22965#undef PM_CASE_WRITABLE
22966#undef PM_STRING_EMPTY
22967#undef PM_LOCATION_NODE_BASE_VALUE
22968#undef PM_LOCATION_NODE_VALUE
22969#undef PM_LOCATION_NULL_VALUE
22970#undef PM_LOCATION_TOKEN_VALUE
22975#ifndef PRISM_EXCLUDE_SERIALIZATION
22979 pm_buffer_append_string(buffer,
"PRISM", 5);
22983 pm_buffer_append_byte(buffer, PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS ? 1 : 0);
22991 pm_serialize_header(buffer);
22993 pm_buffer_append_byte(buffer,
'\0');
23001pm_serialize_parse(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
23003 pm_options_read(&options, data);
23006 pm_parser_init(&parser, source, size, &options);
23010 pm_serialize_header(buffer);
23012 pm_buffer_append_byte(buffer,
'\0');
23014 pm_node_destroy(&parser, node);
23015 pm_parser_free(&parser);
23016 pm_options_free(&options);
23027 pm_options_read(&options, data);
23030 pm_node_t *node = pm_parse_stream(&parser, &parser_buffer, stream, stream_fgets, stream_feof, &options);
23031 pm_serialize_header(buffer);
23033 pm_buffer_append_byte(buffer,
'\0');
23035 pm_node_destroy(&parser, node);
23036 pm_buffer_free(&parser_buffer);
23037 pm_parser_free(&parser);
23038 pm_options_free(&options);
23045pm_serialize_parse_comments(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
23047 pm_options_read(&options, data);
23050 pm_parser_init(&parser, source, size, &options);
23053 pm_serialize_header(buffer);
23055 pm_buffer_append_varsint(buffer, parser.
start_line);
23058 pm_node_destroy(&parser, node);
23059 pm_parser_free(&parser);
23060 pm_options_free(&options);
23072 PM_SLICE_TYPE_ERROR = -1,
23075 PM_SLICE_TYPE_NONE,
23078 PM_SLICE_TYPE_LOCAL,
23081 PM_SLICE_TYPE_CONSTANT,
23084 PM_SLICE_TYPE_METHOD_NAME
23091pm_slice_type(
const uint8_t *source,
size_t length,
const char *encoding_name) {
23093 const pm_encoding_t *encoding = pm_encoding_find((
const uint8_t *) encoding_name, (
const uint8_t *) (encoding_name + strlen(encoding_name)));
23094 if (encoding == NULL)
return PM_SLICE_TYPE_ERROR;
23097 if (length == 0)
return PM_SLICE_TYPE_NONE;
23100 if ((width = encoding->
alpha_char(source, (ptrdiff_t) length)) != 0) {
23102 }
else if (*source ==
'_') {
23105 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, (ptrdiff_t) length)) > 0)) {
23109 return PM_SLICE_TYPE_NONE;
23113 const uint8_t *end = source + length;
23114 pm_slice_type_t result = encoding->
isupper_char(source, end - source) ? PM_SLICE_TYPE_CONSTANT : PM_SLICE_TYPE_LOCAL;
23120 while (source < end) {
23121 if ((width = encoding->
alnum_char(source, end - source)) != 0) {
23124 }
else if (*source ==
'_') {
23127 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, end - source)) > 0)) {
23137 if (*source ==
'!' || *source ==
'?' || *source ==
'=') {
23139 result = PM_SLICE_TYPE_METHOD_NAME;
23143 return source == end ? result : PM_SLICE_TYPE_NONE;
23150pm_string_query_local(
const uint8_t *source,
size_t length,
const char *encoding_name) {
23151 switch (pm_slice_type(source, length, encoding_name)) {
23152 case PM_SLICE_TYPE_ERROR:
23154 case PM_SLICE_TYPE_NONE:
23155 case PM_SLICE_TYPE_CONSTANT:
23156 case PM_SLICE_TYPE_METHOD_NAME:
23158 case PM_SLICE_TYPE_LOCAL:
23162 assert(
false &&
"unreachable");
23170pm_string_query_constant(
const uint8_t *source,
size_t length,
const char *encoding_name) {
23171 switch (pm_slice_type(source, length, encoding_name)) {
23172 case PM_SLICE_TYPE_ERROR:
23174 case PM_SLICE_TYPE_NONE:
23175 case PM_SLICE_TYPE_LOCAL:
23176 case PM_SLICE_TYPE_METHOD_NAME:
23178 case PM_SLICE_TYPE_CONSTANT:
23182 assert(
false &&
"unreachable");
23190pm_string_query_method_name(
const uint8_t *source,
size_t length,
const char *encoding_name) {
23191#define B(p) ((p) ? PM_STRING_QUERY_TRUE : PM_STRING_QUERY_FALSE)
23192#define C1(c) (*source == c)
23193#define C2(s) (memcmp(source, s, 2) == 0)
23194#define C3(s) (memcmp(source, s, 3) == 0)
23196 switch (pm_slice_type(source, length, encoding_name)) {
23197 case PM_SLICE_TYPE_ERROR:
23199 case PM_SLICE_TYPE_NONE:
23201 case PM_SLICE_TYPE_LOCAL:
23203 return B((length != 2) || (source[0] !=
'_') || (source[1] ==
'0') || !pm_char_is_decimal_digit(source[1]));
23204 case PM_SLICE_TYPE_CONSTANT:
23206 case PM_SLICE_TYPE_METHOD_NAME:
23213 return B(C1(
'&') || C1(
'`') || C1(
'!') || C1(
'^') || C1(
'>') || C1(
'<') || C1(
'-') || C1(
'%') || C1(
'|') || C1(
'+') || C1(
'/') || C1(
'*') || C1(
'~'));
23215 return B(C2(
"!=") || C2(
"!~") || C2(
"[]") || C2(
"==") || C2(
"=~") || C2(
">=") || C2(
">>") || C2(
"<=") || C2(
"<<") || C2(
"**"));
23217 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.
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_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.
#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.
#define PM_STRING_EMPTY
Defines an empty string.
#define PRISM_FALLTHROUGH
We use -Wimplicit-fallthrough to guard potentially unintended fall-through between cases of a switch.
#define PRISM_UNLIKELY(x)
The compiler should predicate that this branch will not be taken.
#define PRISM_ATTRIBUTE_UNUSED
GCC will warn if you specify a function or parameter that is unused at runtime.
#define PRISM_DEPTH_MAXIMUM
When we are parsing using recursive descent, we want to protect against malicious payloads that could...
#define PM_STATIC_ASSERT(line, condition, message)
We want to be able to use static assertions, but they weren't standardized until C11.
#define PRISM_EXPORTED_FUNCTION
By default, we compile with -fvisibility=hidden.
#define PM_ENCODING_US_ASCII_ENTRY
This is the US-ASCII encoding.
#define PM_ENCODING_UTF_8_ENTRY
This is the default UTF-8 encoding.
#define PRISM_ENCODING_ALPHABETIC_BIT
All of the lookup tables use the first bit of each embedded byte to indicate whether the codepoint is...
#define PRISM_ENCODING_ALPHANUMERIC_BIT
All of the lookup tables use the second bit of each embedded byte to indicate whether the codepoint i...
#define PM_NODE_LIST_FOREACH(list, index, node)
Loop through each node in the node list, writing each node to the given pm_node_t pointer.
#define PRISM_VERSION
The version of the Prism library as a constant string.
#define PRISM_VERSION_PATCH
The patch version of the Prism library as an int.
#define PRISM_VERSION_MINOR
The minor version of the Prism library as an int.
#define PRISM_VERSION_MAJOR
The major version of the Prism library as an int.
The main header file for the prism parser.
pm_string_query_t
Represents the results of a slice query.
@ PM_STRING_QUERY_TRUE
Returned if the result of the slice query is true.
@ PM_STRING_QUERY_ERROR
Returned if the encoding given to a slice query was invalid.
@ PM_STRING_QUERY_FALSE
Returned if the result of the slice query is false.
void pm_serialize_content(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer)
Serialize the encoding, metadata, nodes, and constant pool.
char *() pm_parse_stream_fgets_t(char *string, int size, void *stream)
This function is used in pm_parse_stream to retrieve a line of input from a stream.
void pm_serialize_encoding(const pm_encoding_t *encoding, pm_buffer_t *buffer)
Serialize the name of the encoding to the buffer.
int() pm_parse_stream_feof_t(void *stream)
This function is used in pm_parse_stream to check whether a stream is EOF.
void pm_serialize_comment_list(pm_parser_t *parser, pm_list_t *list, pm_buffer_t *buffer)
Serialize the given list of comments to the given buffer.
const char * pm_token_type_human(pm_token_type_t token_type)
Returns the human name of the given token type.
This struct is used to pass information between the regular expression parser and the error callback.
pm_parser_t * parser
The parser that we are parsing the regular expression for.
const uint8_t * start
The start of the regular expression.
bool shared
Whether or not the source of the regular expression is shared.
const uint8_t * end
The end of the regular expression.
This struct is used to pass information between the regular expression parser and the named capture c...
pm_constant_id_list_t names
The list of names that have been parsed.
pm_parser_t * parser
The parser that is parsing the regular expression.
pm_match_write_node_t * match
The match write node that is being created.
pm_call_node_t * call
The call node wrapping the regular expression node.
bool shared
Whether the content of the regular expression is shared.
struct pm_node * left
AndNode::left.
struct pm_node * right
AndNode::right.
pm_node_t base
The embedded base node.
struct pm_node_list arguments
ArgumentsNode::arguments.
This is a special out parameter to the parse_arguments_list function that includes opening and closin...
pm_node_t * block
The optional block attached to the call.
bool has_forwarding
The flag indicating whether this arguments list has forwarding argument.
pm_location_t opening_loc
The optional location of the opening parenthesis or bracket.
pm_arguments_node_t * arguments
The lazily-allocated optional arguments node.
pm_location_t closing_loc
The optional location of the closing parenthesis or bracket.
struct pm_node_list elements
ArrayNode::elements.
struct pm_node * constant
ArrayPatternNode::constant.
pm_location_t opening_loc
ArrayPatternNode::opening_loc.
pm_node_t base
The embedded base node.
pm_location_t closing_loc
ArrayPatternNode::closing_loc.
struct pm_node * value
AssocNode::value.
struct pm_node * key
AssocNode::key.
struct pm_ensure_node * ensure_clause
BeginNode::ensure_clause.
struct pm_rescue_node * rescue_clause
BeginNode::rescue_clause.
struct pm_statements_node * statements
BeginNode::statements.
pm_node_t base
The embedded base node.
struct pm_else_node * else_clause
BeginNode::else_clause.
This struct represents a set of binding powers used for a given token.
bool binary
Whether or not this token can be used as a binary operator.
pm_binding_power_t left
The left binding power.
bool nonassoc
Whether or not this token can be used as non-associative binary operator.
pm_binding_power_t right
The right binding power.
A pm_buffer_t is a simple memory buffer that stores data in a contiguous block of memory.
size_t length
The length of the buffer in bytes.
char * value
A pointer to the start of the buffer.
pm_location_t opening_loc
CallNode::opening_loc.
pm_location_t closing_loc
CallNode::closing_loc.
struct pm_node * receiver
CallNode::receiver.
pm_constant_id_t name
CallNode::name.
pm_node_t base
The embedded base node.
pm_location_t call_operator_loc
CallNode::call_operator_loc.
pm_location_t message_loc
CallNode::message_loc.
struct pm_arguments_node * arguments
CallNode::arguments.
struct pm_node * block
CallNode::block.
struct pm_node_list conditions
CaseMatchNode::conditions.
struct pm_node_list conditions
CaseNode::conditions.
A constant in the pool which effectively stores a string.
size_t length
The length of the string.
const uint8_t * start
A pointer to the start of the string.
This is a node in a linked list of contexts.
pm_context_t context
The context that this node represents.
struct pm_context_node * prev
A pointer to the previous context in the linked list.
This struct represents a diagnostic generated during parsing.
struct pm_statements_node * statements
ElseNode::statements.
This struct defines the functions necessary to implement the encoding interface so we can determine h...
size_t(* alpha_char)(const uint8_t *b, ptrdiff_t n)
Return the number of bytes that the next character takes if it is valid in the encoding and is alphab...
size_t(* char_width)(const uint8_t *b, ptrdiff_t n)
Return the number of bytes that the next character takes if it is valid in the encoding.
bool(* isupper_char)(const uint8_t *b, ptrdiff_t n)
Return true if the next character is valid in the encoding and is an uppercase character.
const char * name
The name of the encoding.
size_t(* alnum_char)(const uint8_t *b, ptrdiff_t n)
Return the number of bytes that the next character takes if it is valid in the encoding and is alphan...
struct pm_statements_node * statements
EnsureNode::statements.
struct pm_node * constant
FindPatternNode::constant.
pm_location_t opening_loc
FindPatternNode::opening_loc.
pm_node_t base
The embedded base node.
pm_location_t closing_loc
FindPatternNode::closing_loc.
double value
FloatNode::value.
pm_node_t base
The embedded base node.
GlobalVariableTargetNode.
struct pm_node_list elements
HashNode::elements.
pm_location_t opening_loc
HashPatternNode::opening_loc.
pm_node_t base
The embedded base node.
pm_location_t closing_loc
HashPatternNode::closing_loc.
struct pm_node * constant
HashPatternNode::constant.
All of the information necessary to store to lexing a heredoc.
size_t ident_length
The length of the heredoc identifier.
pm_heredoc_quote_t quote
The type of quote that the heredoc uses.
pm_heredoc_indent_t indent
The type of indentation that the heredoc uses.
const uint8_t * ident_start
A pointer to the start of the heredoc identifier.
struct pm_statements_node * statements
IfNode::statements.
struct pm_node * subsequent
IfNode::subsequent.
InstanceVariableReadNode.
InstanceVariableTargetNode.
InstanceVariableWriteNode.
pm_integer_t value
IntegerNode::value.
pm_node_t base
The embedded base node.
bool negative
Whether or not the integer is negative.
InterpolatedMatchLastLineNode.
InterpolatedRegularExpressionNode.
pm_node_t base
The embedded base node.
pm_location_t opening_loc
InterpolatedStringNode::opening_loc.
pm_node_t base
The embedded base node.
pm_location_t opening_loc
InterpolatedXStringNode::opening_loc.
pm_node_t base
The embedded base node.
struct pm_node_list parts
InterpolatedXStringNode::parts.
void(* callback)(void *data, pm_parser_t *parser, pm_token_t *token)
This is the callback that is called when a token is lexed.
void * data
This opaque pointer is used to provide whatever information the user deemed necessary to the callback...
When lexing Ruby source, the lexer has a small amount of state to tell which kind of token it is curr...
uint8_t terminator
This is the terminator of the list literal.
size_t nesting
This keeps track of the nesting level of the list.
bool interpolation
Whether or not interpolation is allowed in this list.
uint8_t incrementor
When lexing a list, it takes into account balancing the terminator if the terminator is one of (),...
enum pm_lex_mode::@95 mode
The type of this lex mode.
uint8_t breakpoints[11]
This is the character set that should be used to delimit the tokens within the list.
pm_heredoc_lex_mode_t base
All of the data necessary to lex a heredoc.
bool line_continuation
True if the previous token ended with a line continuation.
struct pm_lex_mode * prev
The previous lex state so that it knows how to pop.
bool label_allowed
Whether or not at the end of the string we should allow a :, which would indicate this was a dynamic ...
const uint8_t * next_start
This is the pointer to the character where lexing should resume once the heredoc has been completely ...
size_t * common_whitespace
This is used to track the amount of common whitespace on each line so that we know how much to dedent...
union pm_lex_mode::@96 as
The data associated with this type of lex mode.
int32_t line
The line number.
This struct represents an abstract linked list that provides common functionality.
struct pm_list_node * next
A pointer to the next node in the list.
This represents the overall linked list.
pm_list_node_t * head
A pointer to the head of the list.
size_t size
The size of the list.
This tracks an individual local variable in a certain lexical context, as well as the number of times...
pm_constant_id_t name
The name of the local variable.
pm_location_t location
The location of the local variable in the source.
uint32_t hash
The hash of the local variable.
uint32_t index
The index of the local variable in the local table.
uint32_t reads
The number of times the local variable is read.
uint32_t depth
LocalVariableReadNode::depth.
pm_constant_id_t name
LocalVariableReadNode::name.
uint32_t depth
LocalVariableWriteNode::depth.
pm_constant_id_t name
LocalVariableWriteNode::name.
This is a set of local variables in a certain lexical context (method, class, module,...
pm_local_t * locals
The nullable allocated memory for the local variables in the set.
uint32_t capacity
The capacity of the local variables set.
uint32_t size
The number of local variables in the set.
This represents a range of bytes in the source string to which a node or token corresponds.
const uint8_t * start
A pointer to the start location of the range in the source.
const uint8_t * end
A pointer to the end location of the range in the source.
struct pm_node_list targets
MatchWriteNode::targets.
pm_node_t base
The embedded base node.
pm_location_t lparen_loc
MultiTargetNode::lparen_loc.
struct pm_node_list lefts
MultiTargetNode::lefts.
pm_location_t rparen_loc
MultiTargetNode::rparen_loc.
size_t * offsets
The list of offsets.
size_t size
The number of offsets in the list.
A list of nodes in the source, most often used for lists of children.
size_t size
The number of nodes in the list.
struct pm_node ** nodes
The nodes in the list.
This is the base structure that represents a node in the syntax tree.
pm_node_type_t type
This represents the type of the node.
pm_node_flags_t flags
This represents any flags on the node.
pm_location_t location
This is the location of the node in the source.
A scope of locals surrounding the code that is being parsed.
size_t locals_count
The number of locals in the scope.
uint8_t forwarding
Flags for the set of forwarding parameters in this scope.
The options that can be passed to the parser.
uint8_t command_line
A bitset of the various options that were set on the command line.
void * shebang_callback_data
Any additional data that should be passed along to the shebang callback if one was set.
bool encoding_locked
Whether or not the encoding magic comments should be respected.
bool main_script
When the file being parsed is the main script, the shebang will be considered for command-line flags ...
pm_string_t encoding
The name of the encoding that the source file is in.
int32_t line
The line within the file that the parse starts on.
pm_options_shebang_callback_t shebang_callback
The callback to call when additional switches are found in a shebang comment.
int8_t frozen_string_literal
Whether or not the frozen string literal option has been set.
bool partial_script
When the file being parsed is considered a "partial" script, jumps will not be marked as errors if th...
size_t scopes_count
The number of scopes surrounding the code that is being parsed.
pm_string_t filepath
The name of the file that is currently being parsed.
pm_options_version_t version
The version of prism that we should be parsing with.
struct pm_node * left
OrNode::left.
struct pm_node * right
OrNode::right.
struct pm_node * rest
ParametersNode::rest.
struct pm_block_parameter_node * block
ParametersNode::block.
pm_node_t base
The embedded base node.
struct pm_node * keyword_rest
ParametersNode::keyword_rest.
struct pm_node * body
ParenthesesNode::body.
This struct represents the overall parser.
const pm_encoding_t * explicit_encoding
When a string-like expression is being lexed, any byte or escape sequence that resolves to a value wh...
pm_lex_state_t lex_state
The current state of the lexer.
uint8_t command_line
The command line flags given from the options.
const pm_encoding_t * encoding
The encoding functions for the current file is attached to the parser as it's parsing so that it can ...
bool partial_script
Whether or not we are parsing a "partial" script, which is a script that will be evaluated in the con...
bool pattern_matching_newlines
This flag indicates that we are currently parsing a pattern matching expression and impacts that calc...
struct pm_parser::@101 lex_modes
A stack of lex modes.
const uint8_t * end
The pointer to the end of the source.
bool recovering
Whether or not we're currently recovering from a syntax error.
pm_node_flags_t integer_base
We want to add a flag to integer nodes that indicates their base.
bool warn_mismatched_indentation
By default, Ruby always warns about mismatched indentation.
pm_constant_pool_t constant_pool
This constant pool keeps all of the constants defined throughout the file so that we can reference th...
bool in_keyword_arg
This flag indicates that we are currently parsing a keyword argument.
const uint8_t * next_start
This is a special field set on the parser when we need the parser to jump to a specific location when...
pm_static_literals_t * current_hash_keys
The hash keys for the hash that is currently being parsed.
pm_list_t magic_comment_list
The list of magic comments that have been found while parsing.
int lambda_enclosure_nesting
Used to temporarily track the nesting of enclosures to determine if a { is the beginning of a lambda ...
pm_lex_callback_t * lex_callback
This is an optional callback that can be attached to the parser that will be called whenever a new to...
pm_options_version_t version
The version of prism that we should use to parse.
pm_token_t previous
The previous token we were considering.
pm_string_t current_string
This string is used to pass information from the lexer to the parser.
bool parsing_eval
Whether or not we are parsing an eval string.
bool current_regular_expression_ascii_only
True if the current regular expression being lexed contains only ASCII characters.
bool encoding_changed
Whether or not the encoding has been changed by a magic comment.
pm_location_t data_loc
An optional location that represents the location of the END marker and the rest of the content of th...
pm_context_node_t * current_context
The current parsing context.
const uint8_t * start
The pointer to the start of the source.
int enclosure_nesting
Tracks the current nesting of (), [], and {}.
pm_list_t error_list
The list of errors that have been found while parsing.
int8_t frozen_string_literal
Whether or not we have found a frozen_string_literal magic comment with a true or false value.
pm_node_list_t * current_block_exits
When parsing block exits (e.g., break, next, redo), we need to validate that they are in correct cont...
const uint8_t * encoding_comment_start
This pointer indicates where a comment must start if it is to be considered an encoding comment.
pm_lex_mode_t stack[PM_LEX_STACK_SIZE]
The stack of lexer modes.
pm_list_t warning_list
The list of warnings that have been found while parsing.
const uint8_t * heredoc_end
This field indicates the end of a heredoc whose identifier was found on the current line.
int brace_nesting
Used to track the nesting of braces to ensure we get the correct value when we are interpolating bloc...
pm_encoding_changed_callback_t encoding_changed_callback
When the encoding that is being used to parse the source is changed by prism, we provide the ability ...
int32_t start_line
The line number at the start of the parse.
bool encoding_locked
This is very specialized behavior for when you want to parse in a context that does not respect encod...
pm_lex_mode_t * current
The current mode of the lexer.
pm_list_t comment_list
The list of comments that have been found while parsing.
size_t index
The current index into the lexer mode stack.
pm_string_t filepath
This is the path of the file being parsed.
pm_scope_t * current_scope
The current local scope.
bool command_start
Whether or not we're at the beginning of a command.
pm_newline_list_t newline_list
This is the list of newline offsets in the source file.
bool semantic_token_seen
Whether or not the parser has seen a token that has semantic meaning (i.e., a token that is not a com...
uint32_t node_id
The next node identifier that will be assigned.
struct pm_node * right
RangeNode::right.
struct pm_node * left
RangeNode::left.
pm_node_t base
The embedded base node.
pm_integer_t numerator
RationalNode::numerator.
In order to properly set a regular expression's encoding and to validate the byte sequence for the un...
pm_buffer_t regexp_buffer
The buffer holding the regexp source.
pm_token_buffer_t base
The embedded base buffer.
pm_node_t base
The embedded base node.
pm_string_t unescaped
RegularExpressionNode::unescaped.
struct pm_node * rescue_expression
RescueModifierNode::rescue_expression.
struct pm_rescue_node * subsequent
RescueNode::subsequent.
pm_location_t then_keyword_loc
RescueNode::then_keyword_loc.
pm_node_t base
The embedded base node.
This struct represents a node in a linked list of scopes.
struct pm_scope * previous
A pointer to the previous scope in the linked list.
pm_node_list_t implicit_parameters
This is a list of the implicit parameters contained within the block.
pm_shareable_constant_value_t shareable_constant
The current state of constant shareability for this scope.
pm_locals_t locals
The IDs of the locals in the given scope.
pm_scope_parameters_t parameters
This is a bitfield that indicates the parameters that are being used in this scope.
bool closed
A boolean indicating whether or not this scope can see into its parent.
struct pm_node * expression
SplatNode::expression.
struct pm_node_list body
StatementsNode::body.
Certain sets of nodes (hash keys and when clauses) check for duplicate nodes to alert the user of pot...
pm_node_t base
The embedded base node.
pm_string_t unescaped
StringNode::unescaped.
pm_location_t closing_loc
StringNode::closing_loc.
pm_location_t opening_loc
StringNode::opening_loc.
A generic string type that can have various ownership semantics.
const uint8_t * source
A pointer to the start of the string.
size_t length
The length of the string in bytes of memory.
enum pm_string_t::@102 type
The type of the string.
pm_location_t value_loc
SymbolNode::value_loc.
pm_string_t unescaped
SymbolNode::unescaped.
When we're lexing certain types (strings, symbols, lists, etc.) we have string content associated wit...
pm_buffer_t buffer
The buffer that we're using to keep track of the string content.
const uint8_t * cursor
The cursor into the source string that points to how far we have currently copied into the buffer.
This struct represents a token in the Ruby source.
const uint8_t * end
A pointer to the end location of the token in the source.
const uint8_t * start
A pointer to the start location of the token in the source.
pm_token_type_t type
The type of the token.
struct pm_statements_node * statements
UnlessNode::statements.
struct pm_else_node * else_clause
UnlessNode::else_clause.