15#define PM_TAB_WHITESPACE_SIZE 8
18#define MIN(a,b) (((a)<(b))?(a):(b))
19#define MAX(a,b) (((a)>(b))?(a):(b))
25#define FL PM_NODE_FLAGS
26#define UP PM_NODE_UPCAST
28#define PM_TOKEN_START(token_) ((token_)->start)
29#define PM_TOKEN_END(token_) ((token_)->end)
31#define PM_NODE_START(node_) (UP(node_)->location.start)
32#define PM_NODE_END(node_) (UP(node_)->location.end)
34#define PM_LOCATION_NULL_VALUE(parser_) ((pm_location_t) { .start = (parser_)->start, .end = (parser_)->start })
35#define PM_LOCATION_TOKEN_VALUE(token_) ((pm_location_t) { .start = PM_TOKEN_START(token_), .end = PM_TOKEN_END(token_) })
36#define PM_LOCATION_NODE_VALUE(node_) ((pm_location_t) { .start = PM_NODE_START(node_), .end = PM_NODE_END(node_) })
37#define PM_OPTIONAL_LOCATION_TOKEN_VALUE(token) ((token)->type == PM_TOKEN_NOT_PROVIDED ? ((pm_location_t) { 0 }) : PM_LOCATION_TOKEN_VALUE(token))
48lex_mode_incrementor(
const uint8_t start) {
65lex_mode_terminator(
const uint8_t start) {
107lex_mode_push_list(
pm_parser_t *parser,
bool interpolation, uint8_t delimiter) {
108 uint8_t incrementor = lex_mode_incrementor(delimiter);
109 uint8_t terminator = lex_mode_terminator(delimiter);
115 .interpolation = interpolation,
116 .incrementor = incrementor,
117 .terminator = terminator
124 memcpy(breakpoints,
"\\ \t\f\r\v\n\0\0\0",
sizeof(lex_mode.
as.list.
breakpoints));
129 if (terminator !=
'\0') {
130 breakpoints[index++] = terminator;
136 breakpoints[index++] =
'#';
140 if (incrementor !=
'\0') {
141 breakpoints[index++] = incrementor;
145 return lex_mode_push(parser, lex_mode);
155 return lex_mode_push_list(parser,
false,
'\0');
162lex_mode_push_regexp(
pm_parser_t *parser, uint8_t incrementor, uint8_t terminator) {
164 .
mode = PM_LEX_REGEXP,
167 .incrementor = incrementor,
168 .terminator = terminator
176 memcpy(breakpoints,
"\r\n\\#\0\0",
sizeof(lex_mode.
as.regexp.
breakpoints));
180 if (terminator !=
'\0') {
181 breakpoints[index++] = terminator;
185 if (incrementor !=
'\0') {
186 breakpoints[index++] = incrementor;
190 return lex_mode_push(parser, lex_mode);
197lex_mode_push_string(
pm_parser_t *parser,
bool interpolation,
bool label_allowed, uint8_t incrementor, uint8_t terminator) {
199 .
mode = PM_LEX_STRING,
202 .interpolation = interpolation,
203 .label_allowed = label_allowed,
204 .incrementor = incrementor,
205 .terminator = terminator
212 memcpy(breakpoints,
"\r\n\\\0\0\0",
sizeof(lex_mode.
as.string.
breakpoints));
217 if (terminator !=
'\0') {
218 breakpoints[index++] = terminator;
224 breakpoints[index++] =
'#';
229 if (incrementor !=
'\0') {
230 breakpoints[index++] = incrementor;
234 return lex_mode_push(parser, lex_mode);
244 return lex_mode_push_string(parser,
false,
false,
'\0',
'\0');
276 PM_IGNORED_NEWLINE_NONE = 0,
277 PM_IGNORED_NEWLINE_ALL,
278 PM_IGNORED_NEWLINE_PATTERN
279} pm_ignored_newline_type_t;
281static inline pm_ignored_newline_type_t
283 bool ignored = lex_state_p(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_CLASS | PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT) && !lex_state_p(parser, PM_LEX_STATE_LABELED);
286 return PM_IGNORED_NEWLINE_ALL;
287 }
else if ((parser->
lex_state & ~((
unsigned int) PM_LEX_STATE_LABEL)) == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)) {
288 return PM_IGNORED_NEWLINE_PATTERN;
290 return PM_IGNORED_NEWLINE_NONE;
296 return lex_state_p(parser, PM_LEX_STATE_BEG_ANY) || ((parser->
lex_state & (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)) == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED));
301 return lex_state_p(parser, PM_LEX_STATE_ARG_ANY);
305lex_state_spcarg_p(
pm_parser_t *parser,
bool space_seen) {
309 return lex_state_arg_p(parser) && space_seen && !pm_char_is_whitespace(*parser->
current.end);
314 return lex_state_p(parser, PM_LEX_STATE_END_ANY);
322 return lex_state_p(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT);
334#ifndef PM_DEBUG_LOGGING
339#define PM_DEBUG_LOGGING 0
345 fprintf(stderr,
"STATE: ");
348 if (parser->
lex_state == PM_LEX_STATE_NONE) {
349 fprintf(stderr,
"NONE\n");
353#define CHECK_STATE(state) \
354 if (parser->lex_state & state) { \
355 if (!first) fprintf(stderr, "|"); \
356 fprintf(stderr, "%s", #state); \
360 CHECK_STATE(PM_LEX_STATE_BEG)
361 CHECK_STATE(PM_LEX_STATE_END)
362 CHECK_STATE(PM_LEX_STATE_ENDARG)
363 CHECK_STATE(PM_LEX_STATE_ENDFN)
364 CHECK_STATE(PM_LEX_STATE_ARG)
365 CHECK_STATE(PM_LEX_STATE_CMDARG)
366 CHECK_STATE(PM_LEX_STATE_MID)
367 CHECK_STATE(PM_LEX_STATE_FNAME)
368 CHECK_STATE(PM_LEX_STATE_DOT)
369 CHECK_STATE(PM_LEX_STATE_CLASS)
370 CHECK_STATE(PM_LEX_STATE_LABEL)
371 CHECK_STATE(PM_LEX_STATE_LABELED)
372 CHECK_STATE(PM_LEX_STATE_FITEM)
376 fprintf(stderr,
"\n");
381 fprintf(stderr,
"Caller: %s:%d\nPrevious: ", caller_name, line_number);
383 lex_state_set(parser, state);
384 fprintf(stderr,
"Now: ");
386 fprintf(stderr,
"\n");
389#define lex_state_set(parser, state) debug_lex_state_set(parser, state, __func__, __LINE__)
397#define PM_PARSER_COMMAND_LINE_OPTION(parser, option) ((parser)->command_line & (option))
400#define PM_PARSER_COMMAND_LINE_OPTION_A(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_A)
403#define PM_PARSER_COMMAND_LINE_OPTION_E(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_E)
406#define PM_PARSER_COMMAND_LINE_OPTION_L(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_L)
409#define PM_PARSER_COMMAND_LINE_OPTION_N(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_N)
412#define PM_PARSER_COMMAND_LINE_OPTION_P(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_P)
415#define PM_PARSER_COMMAND_LINE_OPTION_X(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_X)
426 pm_diagnostic_list_append(&parser->
error_list, start, end, diag_id);
432#define PM_PARSER_ERR_FORMAT(parser, start, end, diag_id, ...) \
433 pm_diagnostic_list_append_format(&parser->error_list, start, end, diag_id, __VA_ARGS__)
441 pm_parser_err(parser, parser->
current.start, parser->
current.end, diag_id);
448#define PM_PARSER_ERR_LOCATION_FORMAT(parser, location, diag_id, ...) \
449 PM_PARSER_ERR_FORMAT(parser, (location)->start, (location)->end, diag_id, __VA_ARGS__)
464#define PM_PARSER_ERR_NODE_FORMAT(parser, node, diag_id, ...) \
465 PM_PARSER_ERR_FORMAT(parser, (node)->location.start, (node)->location.end, diag_id, __VA_ARGS__)
471#define PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, diag_id) \
472 PM_PARSER_ERR_NODE_FORMAT(parser, node, diag_id, (int) ((node)->location.end - (node)->location.start), (const char *) (node)->location.start)
489 pm_parser_err(parser, token->start, token->end, diag_id);
496#define PM_PARSER_ERR_TOKEN_FORMAT(parser, token, diag_id, ...) \
497 PM_PARSER_ERR_FORMAT(parser, (token).start, (token).end, diag_id, __VA_ARGS__)
503#define PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, token, diag_id) \
504 PM_PARSER_ERR_TOKEN_FORMAT(parser, token, diag_id, (int) ((token).end - (token).start), (const char *) (token).start)
511 pm_diagnostic_list_append(&parser->
warning_list, start, end, diag_id);
520 pm_parser_warn(parser, token->start, token->end, diag_id);
535#define PM_PARSER_WARN_FORMAT(parser, start, end, diag_id, ...) \
536 pm_diagnostic_list_append_format(&parser->warning_list, start, end, diag_id, __VA_ARGS__)
542#define PM_PARSER_WARN_TOKEN_FORMAT(parser, token, diag_id, ...) \
543 PM_PARSER_WARN_FORMAT(parser, (token).start, (token).end, diag_id, __VA_ARGS__)
549#define PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, token, diag_id) \
550 PM_PARSER_WARN_TOKEN_FORMAT(parser, token, diag_id, (int) ((token).end - (token).start), (const char *) (token).start)
556#define PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, ...) \
557 PM_PARSER_WARN_FORMAT(parser, (node)->location.start, (node)->location.end, diag_id, __VA_ARGS__)
565pm_parser_err_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
566 PM_PARSER_ERR_FORMAT(
569 ident_start + ident_length,
572 (
const char *) ident_start
584pm_parser_scope_push(
pm_parser_t *parser,
bool closed) {
586 if (scope == NULL)
return false;
591 .parameters = PM_SCOPE_PARAMETERS_NONE,
592 .implicit_parameters = { 0 },
610 if (scope->
previous == NULL)
return true;
611 if (scope->
closed)
return false;
612 }
while ((scope = scope->
previous) != NULL);
614 assert(
false &&
"unreachable");
622pm_parser_scope_find(
pm_parser_t *parser, uint32_t depth) {
625 while (depth-- > 0) {
626 assert(scope != NULL);
634 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS,
635 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT,
636 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL
637} pm_scope_forwarding_param_check_result_t;
639static pm_scope_forwarding_param_check_result_t
640pm_parser_scope_forwarding_param_check(
pm_parser_t *parser,
const uint8_t mask) {
642 bool conflict =
false;
644 while (scope != NULL) {
648 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT;
650 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS;
661 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL;
666 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_BLOCK)) {
667 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
670 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
671 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_AMPERSAND);
673 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
674 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_AMPERSAND);
681 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS)) {
682 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
685 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
686 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR);
688 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
689 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR);
696 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_ALL)) {
697 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
700 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
705 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
706 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
713 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS)) {
714 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
717 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
718 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR_STAR);
720 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
721 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR_STAR);
730pm_parser_scope_shareable_constant_get(
pm_parser_t *parser) {
754#define PM_LOCALS_HASH_THRESHOLD 9
769 name = ((name >> 16) ^ name) * 0x45d9f3b;
770 name = ((name >> 16) ^ name) * 0x45d9f3b;
771 name = (name >> 16) ^ name;
781 uint32_t next_capacity = locals->
capacity == 0 ? 4 : (locals->
capacity * 2);
782 assert(next_capacity > locals->
capacity);
785 if (next_locals == NULL) abort();
787 if (next_capacity < PM_LOCALS_HASH_THRESHOLD) {
788 if (locals->
size > 0) {
794 bool hash_needed = (locals->
capacity <= PM_LOCALS_HASH_THRESHOLD);
795 uint32_t mask = next_capacity - 1;
797 for (uint32_t index = 0; index < locals->
capacity; index++) {
801 if (hash_needed) local->
hash = pm_locals_hash(local->
name);
803 uint32_t hash = local->
hash;
805 next_locals[hash & mask] = *local;
810 pm_locals_free(locals);
811 locals->
locals = next_locals;
833 pm_locals_resize(locals);
836 if (locals->
capacity < PM_LOCALS_HASH_THRESHOLD) {
837 for (uint32_t index = 0; index < locals->
capacity; index++) {
843 .location = { .start = start, .end = end },
844 .index = locals->
size++,
849 }
else if (local->
name == name) {
854 uint32_t mask = locals->
capacity - 1;
855 uint32_t hash = pm_locals_hash(name);
856 uint32_t initial_hash = hash;
864 .location = { .start = start, .end = end },
865 .index = locals->
size++,
870 }
else if (local->
name == name) {
875 }
while ((hash & mask) != initial_hash);
878 assert(
false &&
"unreachable");
888 if (locals->
capacity < PM_LOCALS_HASH_THRESHOLD) {
889 for (uint32_t index = 0; index < locals->
size; index++) {
891 if (local->
name == name)
return index;
894 uint32_t mask = locals->
capacity - 1;
895 uint32_t hash = pm_locals_hash(name);
896 uint32_t initial_hash = hash & mask;
903 }
else if (local->
name == name) {
908 }
while ((hash & mask) != initial_hash);
920 uint32_t index = pm_locals_find(locals, name);
921 assert(index != UINT32_MAX);
924 assert(local->
reads < UINT32_MAX);
935 uint32_t index = pm_locals_find(locals, name);
936 assert(index != UINT32_MAX);
939 assert(local->
reads > 0);
949 uint32_t index = pm_locals_find(locals, name);
950 assert(index != UINT32_MAX);
965 pm_constant_id_list_init_capacity(list, locals->
size);
970 uint32_t capacity = locals->
capacity < PM_LOCALS_HASH_THRESHOLD ? locals->
size : locals->
capacity;
974 bool warn_unused = !toplevel || (!parser->parsing_eval && !PM_PARSER_COMMAND_LINE_OPTION_E(parser));
976 for (uint32_t index = 0; index < capacity; index++) {
980 pm_constant_id_list_insert(list, (
size_t) local->
index, local->
name);
982 if (warn_unused && local->
reads == 0 && ((parser->start_line >= 0) || (pm_newline_list_line(&parser->newline_list, local->
location.
start, parser->start_line) >= 0))) {
983 pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, local->
name);
985 if (constant->
length >= 1 && *constant->
start !=
'_') {
986 PM_PARSER_WARN_FORMAT(
990 PM_WARN_UNUSED_LOCAL_VARIABLE,
992 (
const char *) constant->
start
1008pm_parser_constant_id_location(
pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
1009 return pm_constant_pool_insert_shared(&parser->
constant_pool, start, (
size_t) (end - start));
1016pm_parser_constant_id_owned(
pm_parser_t *parser, uint8_t *start,
size_t length) {
1017 return pm_constant_pool_insert_owned(&parser->
constant_pool, start, length);
1024pm_parser_constant_id_constant(
pm_parser_t *parser,
const char *start,
size_t length) {
1025 return pm_constant_pool_insert_constant(&parser->
constant_pool, (
const uint8_t *) start, length);
1033 return pm_parser_constant_id_location(parser, token->start, token->end);
1042 return token->type == PM_TOKEN_NOT_PROVIDED ? 0 : pm_parser_constant_id_token(parser, token);
1054 while (node != NULL) {
1055 switch (PM_NODE_TYPE(node)) {
1056 case PM_RETURN_NODE:
1061 case PM_MATCH_REQUIRED_NODE:
1062 return void_node != NULL ? void_node : node;
1063 case PM_MATCH_PREDICATE_NODE:
1065 case PM_BEGIN_NODE: {
1071 if (vn != NULL)
return vn;
1076 if (vn != NULL)
return vn;
1084 if (vn == NULL)
return NULL;
1085 if (void_node == NULL) void_node = vn;
1088 pm_node_t *vn = pm_check_value_expression(parser, UP(rescue_clause->statements));
1093 if (void_node == NULL) {
1109 case PM_ENSURE_NODE: {
1114 case PM_PARENTHESES_NODE: {
1116 node = UP(cast->
body);
1119 case PM_STATEMENTS_NODE: {
1133 if (void_node == NULL) {
1139 case PM_UNLESS_NODE: {
1148 if (void_node == NULL) {
1154 case PM_ELSE_NODE: {
1169 case PM_LOCAL_VARIABLE_WRITE_NODE: {
1173 for (uint32_t depth = 0; depth < cast->
depth; depth++) scope = scope->
previous;
1188 pm_node_t *void_node = pm_check_value_expression(parser, node);
1189 if (void_node != NULL) {
1190 pm_parser_err_node(parser, void_node, PM_ERR_VOID_EXPRESSION);
1199 const char *
type = NULL;
1202 switch (PM_NODE_TYPE(node)) {
1203 case PM_BACK_REFERENCE_READ_NODE:
1204 case PM_CLASS_VARIABLE_READ_NODE:
1205 case PM_GLOBAL_VARIABLE_READ_NODE:
1206 case PM_INSTANCE_VARIABLE_READ_NODE:
1207 case PM_LOCAL_VARIABLE_READ_NODE:
1208 case PM_NUMBERED_REFERENCE_READ_NODE:
1209 type =
"a variable";
1212 case PM_CALL_NODE: {
1217 switch (message->
length) {
1219 switch (message->
start[0]) {
1236 switch (message->
start[1]) {
1238 if (message->
start[0] ==
'<' || message->
start[0] ==
'>' || message->
start[0] ==
'!' || message->
start[0] ==
'=') {
1244 if (message->
start[0] ==
'+' || message->
start[0] ==
'-') {
1250 if (message->
start[0] ==
'*') {
1258 if (memcmp(message->
start,
"<=>", 3) == 0) {
1267 case PM_CONSTANT_PATH_NODE:
1271 case PM_CONSTANT_READ_NODE:
1272 type =
"a constant";
1275 case PM_DEFINED_NODE:
1284 case PM_IMAGINARY_NODE:
1285 case PM_INTEGER_NODE:
1286 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
1287 case PM_INTERPOLATED_STRING_NODE:
1288 case PM_RATIONAL_NODE:
1289 case PM_REGULAR_EXPRESSION_NODE:
1290 case PM_SOURCE_ENCODING_NODE:
1291 case PM_SOURCE_FILE_NODE:
1292 case PM_SOURCE_LINE_NODE:
1293 case PM_STRING_NODE:
1294 case PM_SYMBOL_NODE:
1302 case PM_RANGE_NODE: {
1305 if (PM_NODE_FLAG_P(cast, PM_RANGE_FLAGS_EXCLUDE_END)) {
1328 PM_PARSER_WARN_NODE_FORMAT(parser, node, PM_WARN_VOID_STATEMENT, length,
type);
1339 const size_t size = node->
body.
size - (last_value ? 1 : 0);
1340 for (
size_t index = 0; index < size; index++) {
1341 pm_void_statement_check(parser, node->
body.
nodes[index]);
1351 PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL,
1352 PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP,
1353 PM_CONDITIONAL_PREDICATE_TYPE_NOT
1354} pm_conditional_predicate_type_t;
1362 case PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL:
1363 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"condition");
1365 case PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP:
1366 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"flip-flop");
1368 case PM_CONDITIONAL_PREDICATE_TYPE_NOT:
1378pm_conditional_predicate_warn_write_literal_p(
const pm_node_t *node) {
1379 switch (PM_NODE_TYPE(node)) {
1380 case PM_ARRAY_NODE: {
1381 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1384 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1385 if (!pm_conditional_predicate_warn_write_literal_p(cast->
elements.
nodes[index]))
return false;
1390 case PM_HASH_NODE: {
1391 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1394 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1396 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE))
return false;
1399 if (!pm_conditional_predicate_warn_write_literal_p(assoc->
key) || !pm_conditional_predicate_warn_write_literal_p(assoc->
value))
return false;
1406 case PM_IMAGINARY_NODE:
1407 case PM_INTEGER_NODE:
1409 case PM_RATIONAL_NODE:
1410 case PM_REGULAR_EXPRESSION_NODE:
1411 case PM_SOURCE_ENCODING_NODE:
1412 case PM_SOURCE_FILE_NODE:
1413 case PM_SOURCE_LINE_NODE:
1414 case PM_STRING_NODE:
1415 case PM_SYMBOL_NODE:
1429 if (pm_conditional_predicate_warn_write_literal_p(node)) {
1448 switch (PM_NODE_TYPE(node)) {
1451 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1452 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1457 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1458 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1461 case PM_PARENTHESES_NODE: {
1464 if ((cast->
body != NULL) && PM_NODE_TYPE_P(cast->
body, PM_STATEMENTS_NODE)) {
1466 if (statements->body.size == 1) pm_conditional_predicate(parser, statements->body.nodes[0],
type);
1471 case PM_BEGIN_NODE: {
1479 case PM_RANGE_NODE: {
1482 if (cast->
left != NULL) pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1483 if (cast->
right != NULL) pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1491 node->
type = PM_FLIP_FLOP_NODE;
1495 case PM_REGULAR_EXPRESSION_NODE:
1500 node->
type = PM_MATCH_LAST_LINE_NODE;
1502 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1503 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"regex ");
1507 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
1512 node->
type = PM_INTERPOLATED_MATCH_LAST_LINE_NODE;
1514 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1515 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"regex ");
1519 case PM_INTEGER_NODE:
1520 if (
type == PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP) {
1521 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1522 pm_parser_warn_node(parser, node, PM_WARN_INTEGER_IN_FLIP_FLOP);
1525 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1528 case PM_STRING_NODE:
1529 case PM_SOURCE_FILE_NODE:
1530 case PM_INTERPOLATED_STRING_NODE:
1531 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"string ");
1533 case PM_SYMBOL_NODE:
1534 case PM_INTERPOLATED_SYMBOL_NODE:
1535 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"symbol ");
1537 case PM_SOURCE_LINE_NODE:
1538 case PM_SOURCE_ENCODING_NODE:
1540 case PM_RATIONAL_NODE:
1541 case PM_IMAGINARY_NODE:
1542 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1544 case PM_CLASS_VARIABLE_WRITE_NODE:
1547 case PM_CONSTANT_WRITE_NODE:
1550 case PM_GLOBAL_VARIABLE_WRITE_NODE:
1553 case PM_INSTANCE_VARIABLE_WRITE_NODE:
1556 case PM_LOCAL_VARIABLE_WRITE_NODE:
1559 case PM_MULTI_WRITE_NODE:
1606static inline const uint8_t *
1608 if (arguments->
block != NULL) {
1649 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_UNEXPECTED_BLOCK);
1663char_is_identifier_start(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
1664 if (n <= 0)
return 0;
1671 }
else if (*b ==
'_') {
1673 }
else if (*b >= 0x80) {
1678 }
else if (*b < 0x80) {
1681 return pm_encoding_utf_8_char_width(b, n);
1690char_is_identifier_utf8(
const uint8_t *b, ptrdiff_t n) {
1693 }
else if (*b < 0x80) {
1696 return pm_encoding_utf_8_char_width(b, n);
1706char_is_identifier(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
1714 }
else if (*b ==
'_') {
1716 }
else if (*b >= 0x80) {
1722 return char_is_identifier_utf8(b, n);
1729#define BIT(c, idx) (((c) / 32 - 1 == idx) ? (1U << ((c) % 32)) : 0)
1730#define PUNCT(idx) ( \
1731 BIT('~', idx) | BIT('*', idx) | BIT('$', idx) | BIT('?', idx) | \
1732 BIT('!', idx) | BIT('@', idx) | BIT('/', idx) | BIT('\\', idx) | \
1733 BIT(';', idx) | BIT(',', idx) | BIT('.', idx) | BIT('=', idx) | \
1734 BIT(':', idx) | BIT('<', idx) | BIT('>', idx) | BIT('\"', idx) | \
1735 BIT('&', idx) | BIT('`', idx) | BIT('\'', idx) | BIT('+', idx) | \
1738const unsigned int pm_global_name_punctuation_hash[(0x7e - 0x20 + 31) / 32] = { PUNCT(0), PUNCT(1), PUNCT(2) };
1744char_is_global_name_punctuation(const uint8_t b) {
1745 const unsigned int i = (const unsigned int) b;
1746 if (i <= 0x20 || 0x7e < i) return false;
1748 return (pm_global_name_punctuation_hash[(i - 0x20) / 32] >> (i % 32)) & 1;
1752token_is_setter_name(pm_token_t *token) {
1754 (token->type == PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL) ||
1755 ((token->type == PM_TOKEN_IDENTIFIER) &&
1756 (token->end - token->start >= 2) &&
1757 (token->end[-1] == '='))
1765pm_local_is_keyword(const char *source, size_t length) {
1766#define KEYWORD(name) if (memcmp(source, name, length) == 0) return true
1770 switch (source[0]) {
1771 case 'd': KEYWORD("do"); return false;
1772 case 'i': KEYWORD("if"); KEYWORD("in"); return false;
1773 case 'o': KEYWORD("or"); return false;
1774 default: return false;
1777 switch (source[0]) {
1778 case 'a': KEYWORD("and"); return false;
1779 case 'd': KEYWORD("def"); return false;
1780 case 'e': KEYWORD("end"); return false;
1781 case 'f': KEYWORD("for"); return false;
1782 case 'n': KEYWORD("nil"); KEYWORD("not"); return false;
1783 default: return false;
1786 switch (source[0]) {
1787 case 'c': KEYWORD("case"); return false;
1788 case 'e': KEYWORD("else"); return false;
1789 case 'n': KEYWORD("next"); return false;
1790 case 'r': KEYWORD("redo"); return false;
1791 case 's': KEYWORD("self"); return false;
1792 case 't': KEYWORD("then"); KEYWORD("true"); return false;
1793 case 'w': KEYWORD("when"); return false;
1794 default: return false;
1797 switch (source[0]) {
1798 case 'a': KEYWORD("alias"); return false;
1799 case 'b': KEYWORD("begin"); KEYWORD("break"); return false;
1800 case 'c': KEYWORD("class"); return false;
1801 case 'e': KEYWORD("elsif"); return false;
1802 case 'f': KEYWORD("false"); return false;
1803 case 'r': KEYWORD("retry"); return false;
1804 case 's': KEYWORD("super"); return false;
1805 case 'u': KEYWORD("undef"); KEYWORD("until"); return false;
1806 case 'w': KEYWORD("while"); return false;
1807 case 'y': KEYWORD("yield"); return false;
1808 default: return false;
1811 switch (source[0]) {
1812 case 'e': KEYWORD("ensure"); return false;
1813 case 'm': KEYWORD("module"); return false;
1814 case 'r': KEYWORD("rescue"); KEYWORD("return"); return false;
1815 case 'u': KEYWORD("unless"); return false;
1816 default: return false;
1819 KEYWORD("__LINE__");
1820 KEYWORD("__FILE__");
1823 KEYWORD("__ENCODING__");
1832/******************************************************************************/
1833/* Node flag handling functions */
1834/******************************************************************************/
1840pm_node_flag_set(pm_node_t *node, pm_node_flags_t flag) {
1841 node->flags |= flag;
1848pm_node_flag_unset(pm_node_t *node, pm_node_flags_t flag) {
1849 node->flags &= (pm_node_flags_t) ~flag;
1856pm_node_flag_set_repeated_parameter(pm_node_t *node) {
1857 assert(PM_NODE_TYPE(node) == PM_BLOCK_LOCAL_VARIABLE_NODE ||
1858 PM_NODE_TYPE(node) == PM_BLOCK_PARAMETER_NODE ||
1859 PM_NODE_TYPE(node) == PM_KEYWORD_REST_PARAMETER_NODE ||
1860 PM_NODE_TYPE(node) == PM_OPTIONAL_KEYWORD_PARAMETER_NODE ||
1861 PM_NODE_TYPE(node) == PM_OPTIONAL_PARAMETER_NODE ||
1862 PM_NODE_TYPE(node) == PM_REQUIRED_KEYWORD_PARAMETER_NODE ||
1863 PM_NODE_TYPE(node) == PM_REQUIRED_PARAMETER_NODE ||
1864 PM_NODE_TYPE(node) == PM_REST_PARAMETER_NODE);
1866 pm_node_flag_set(node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER);
1869/******************************************************************************/
1870/* Node creation functions */
1871/******************************************************************************/
1878#define PM_REGULAR_EXPRESSION_ENCODING_MASK ~(PM_REGULAR_EXPRESSION_FLAGS_EUC_JP | PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J | PM_REGULAR_EXPRESSION_FLAGS_UTF_8)
1883static inline pm_node_flags_t
1884pm_regular_expression_flags_create(pm_parser_t *parser, const pm_token_t *closing) {
1885 pm_node_flags_t flags = 0;
1887 if (closing->type == PM_TOKEN_REGEXP_END) {
1888 pm_buffer_t unknown_flags = { 0 };
1890 for (const uint8_t *flag = closing->start + 1; flag < closing->end; flag++) {
1892 case 'i': flags |= PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE; break;
1893 case 'm': flags |= PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE; break;
1894 case 'x': flags |= PM_REGULAR_EXPRESSION_FLAGS_EXTENDED; break;
1895 case 'o': flags |= PM_REGULAR_EXPRESSION_FLAGS_ONCE; break;
1897 case 'e': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_EUC_JP); break;
1898 case 'n': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT); break;
1899 case 's': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J); break;
1900 case 'u': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_UTF_8); break;
1902 default: pm_buffer_append_byte(&unknown_flags, *flag);
1906 size_t unknown_flags_length = pm_buffer_length(&unknown_flags);
1907 if (unknown_flags_length != 0) {
1908 const char *word = unknown_flags_length >= 2 ? "options" : "option";
1909 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, PM_ERR_REGEXP_UNKNOWN_OPTIONS, word, unknown_flags_length, pm_buffer_value(&unknown_flags));
1911 pm_buffer_free(&unknown_flags);
1917#undef PM_REGULAR_EXPRESSION_ENCODING_MASK
1919static pm_statements_node_t *
1920pm_statements_node_create(pm_parser_t *parser);
1923pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline);
1926pm_statements_node_body_length(pm_statements_node_t *node);
1933pm_node_alloc(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, size_t size) {
1934 void *memory = xcalloc(1, size);
1935 if (memory == NULL) {
1936 fprintf(stderr, "Failed to allocate %d bytes\n", (int) size);
1942#define PM_NODE_ALLOC(parser_, type_) (type_ *) pm_node_alloc(parser_, sizeof(type_))
1943#define PM_NODE_INIT(parser_, type_, flags_, start_, end_) (pm_node_t) { \
1945 .flags = (flags_), \
1946 .node_id = ++(parser_)->node_id, \
1947 .location = { .start = (start_), .end = (end_) } \
1950#define PM_NODE_INIT_UNSET(parser_, type_, flags_) PM_NODE_INIT(parser_, type_, flags_, NULL, NULL)
1951#define PM_NODE_INIT_BASE(parser_, type_, flags_) PM_NODE_INIT(parser_, type_, flags_, (parser_)->start, (parser_)->start)
1952#define PM_NODE_INIT_TOKEN(parser_, type_, flags_, token_) PM_NODE_INIT(parser_, type_, flags_, PM_TOKEN_START(token_), PM_TOKEN_END(token_))
1953#define PM_NODE_INIT_NODE(parser_, type_, flags_, node_) PM_NODE_INIT(parser_, type_, flags_, PM_NODE_START(node_), PM_NODE_END(node_))
1955#define PM_NODE_INIT_TOKENS(parser_, type_, flags_, left_, right_) PM_NODE_INIT(parser_, type_, flags_, PM_TOKEN_START(left_), PM_TOKEN_END(right_))
1956#define PM_NODE_INIT_NODES(parser_, type_, flags_, left_, right_) PM_NODE_INIT(parser_, type_, flags_, PM_NODE_START(left_), PM_NODE_END(right_))
1957#define PM_NODE_INIT_TOKEN_NODE(parser_, type_, flags_, token_, node_) PM_NODE_INIT(parser_, type_, flags_, PM_TOKEN_START(token_), PM_NODE_END(node_))
1958#define PM_NODE_INIT_NODE_TOKEN(parser_, type_, flags_, node_, token_) PM_NODE_INIT(parser_, type_, flags_, PM_NODE_START(node_), PM_TOKEN_END(token_))
1963static pm_missing_node_t *
1964pm_missing_node_create(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
1965 pm_missing_node_t *node = PM_NODE_ALLOC(parser, pm_missing_node_t);
1967 *node = (pm_missing_node_t) {
1968 .base = PM_NODE_INIT(parser, PM_MISSING_NODE, 0, start, end)
1977static pm_alias_global_variable_node_t *
1978pm_alias_global_variable_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
1979 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
1980 pm_alias_global_variable_node_t *node = PM_NODE_ALLOC(parser, pm_alias_global_variable_node_t);
1982 *node = (pm_alias_global_variable_node_t) {
1983 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_ALIAS_GLOBAL_VARIABLE_NODE, 0, keyword, old_name),
1984 .new_name = new_name,
1985 .old_name = old_name,
1986 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
1995static pm_alias_method_node_t *
1996pm_alias_method_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
1997 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
1998 pm_alias_method_node_t *node = PM_NODE_ALLOC(parser, pm_alias_method_node_t);
2000 *node = (pm_alias_method_node_t) {
2001 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_ALIAS_METHOD_NODE, 0, keyword, old_name),
2002 .new_name = new_name,
2003 .old_name = old_name,
2004 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
2013static pm_alternation_pattern_node_t *
2014pm_alternation_pattern_node_create(pm_parser_t *parser, pm_node_t *left, pm_node_t *right, const pm_token_t *operator) {
2015 pm_alternation_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_alternation_pattern_node_t);
2017 *node = (pm_alternation_pattern_node_t) {
2018 .base = PM_NODE_INIT_NODES(parser, PM_ALTERNATION_PATTERN_NODE, 0, left, right),
2021 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2030static pm_and_node_t *
2031pm_and_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
2032 pm_assert_value_expression(parser, left);
2034 pm_and_node_t *node = PM_NODE_ALLOC(parser, pm_and_node_t);
2036 *node = (pm_and_node_t) {
2037 .base = PM_NODE_INIT_NODES(parser, PM_AND_NODE, 0, left, right),
2039 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2049static pm_arguments_node_t *
2050pm_arguments_node_create(pm_parser_t *parser) {
2051 pm_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_arguments_node_t);
2053 *node = (pm_arguments_node_t) {
2054 .base = PM_NODE_INIT_BASE(parser, PM_ARGUMENTS_NODE, 0),
2065pm_arguments_node_size(pm_arguments_node_t *node) {
2066 return node->arguments.size;
2073pm_arguments_node_arguments_append(pm_arguments_node_t *node, pm_node_t *argument) {
2074 if (pm_arguments_node_size(node) == 0) {
2075 node->base.location.start = argument->location.start;
2078 node->base.location.end = argument->location.end;
2079 pm_node_list_append(&node->arguments, argument);
2081 if (PM_NODE_TYPE_P(argument, PM_SPLAT_NODE)) {
2082 if (PM_NODE_FLAG_P(node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
2083 pm_node_flag_set(UP(node), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS);
2085 pm_node_flag_set(UP(node), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT);
2093static pm_array_node_t *
2094pm_array_node_create(pm_parser_t *parser, const pm_token_t *opening) {
2095 pm_array_node_t *node = PM_NODE_ALLOC(parser, pm_array_node_t);
2097 *node = (pm_array_node_t) {
2098 .base = PM_NODE_INIT_TOKEN(parser, PM_ARRAY_NODE, PM_NODE_FLAG_STATIC_LITERAL, opening),
2099 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2100 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2111pm_array_node_elements_append(pm_array_node_t *node, pm_node_t *element) {
2112 if (!node->elements.size && !node->opening_loc.start) {
2113 node->base.location.start = element->location.start;
2116 pm_node_list_append(&node->elements, element);
2117 node->base.location.end = element->location.end;
2119 // If the element is not a static literal, then the array is not a static
2120 // literal. Turn that flag off.
2121 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)) {
2122 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
2125 if (PM_NODE_TYPE_P(element, PM_SPLAT_NODE)) {
2126 pm_node_flag_set(UP(node), PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT);
2134pm_array_node_close_set(pm_array_node_t *node, const pm_token_t *closing) {
2135 assert(closing->type == PM_TOKEN_BRACKET_RIGHT || closing->type == PM_TOKEN_STRING_END || closing->type == PM_TOKEN_MISSING || closing->type == PM_TOKEN_NOT_PROVIDED);
2136 node->base.location.end = closing->end;
2137 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
2144static pm_array_pattern_node_t *
2145pm_array_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *nodes) {
2146 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2148 *node = (pm_array_pattern_node_t) {
2149 .base = PM_NODE_INIT_NODES(parser, PM_ARRAY_PATTERN_NODE, 0, nodes->nodes[0], nodes->nodes[nodes->size - 1]),
2154 .opening_loc = { 0 },
2155 .closing_loc = { 0 }
2158 // For now we're going to just copy over each pointer manually. This could be
2159 // much more efficient, as we could instead resize the node list.
2160 bool found_rest = false;
2163 PM_NODE_LIST_FOREACH(nodes, index, child) {
2164 if (!found_rest && (PM_NODE_TYPE_P(child, PM_SPLAT_NODE) || PM_NODE_TYPE_P(child, PM_IMPLICIT_REST_NODE))) {
2167 } else if (found_rest) {
2168 pm_node_list_append(&node->posts, child);
2170 pm_node_list_append(&node->requireds, child);
2180static pm_array_pattern_node_t *
2181pm_array_pattern_node_rest_create(pm_parser_t *parser, pm_node_t *rest) {
2182 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2184 *node = (pm_array_pattern_node_t) {
2185 .base = PM_NODE_INIT_NODE(parser, PM_ARRAY_PATTERN_NODE, 0, rest),
2190 .opening_loc = { 0 },
2191 .closing_loc = { 0 }
2201static pm_array_pattern_node_t *
2202pm_array_pattern_node_constant_create(pm_parser_t *parser, pm_node_t *constant, const pm_token_t *opening, const pm_token_t *closing) {
2203 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2205 *node = (pm_array_pattern_node_t) {
2206 .base = PM_NODE_INIT_NODE_TOKEN(parser, PM_ARRAY_PATTERN_NODE, 0, constant, closing),
2207 .constant = constant,
2209 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2210 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
2222static pm_array_pattern_node_t *
2223pm_array_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
2224 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2226 *node = (pm_array_pattern_node_t) {
2227 .base = PM_NODE_INIT_TOKENS(parser, PM_ARRAY_PATTERN_NODE, 0, opening, closing),
2230 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2231 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
2240pm_array_pattern_node_requireds_append(pm_array_pattern_node_t *node, pm_node_t *inner) {
2241 pm_node_list_append(&node->requireds, inner);
2247static pm_assoc_node_t *
2248pm_assoc_node_create(pm_parser_t *parser, pm_node_t *key, const pm_token_t *operator, pm_node_t *value) {
2249 pm_assoc_node_t *node = PM_NODE_ALLOC(parser, pm_assoc_node_t);
2252 if (value != NULL && value->location.end > key->location.end) {
2253 end = value->location.end;
2254 } else if (operator->type != PM_TOKEN_NOT_PROVIDED) {
2255 end = operator->end;
2257 end = key->location.end;
2260 // Hash string keys will be frozen, so we can mark them as frozen here so
2261 // that the compiler picks them up and also when we check for static literal
2262 // on the keys it gets factored in.
2263 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
2264 key->flags |= PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL;
2267 // If the key and value of this assoc node are both static literals, then
2268 // we can mark this node as a static literal.
2269 pm_node_flags_t flags = 0;
2271 !PM_NODE_TYPE_P(key, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(key, PM_HASH_NODE) && !PM_NODE_TYPE_P(key, PM_RANGE_NODE) &&
2272 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)
2274 flags = key->flags & value->flags & PM_NODE_FLAG_STATIC_LITERAL;
2277 *node = (pm_assoc_node_t) {
2278 .base = PM_NODE_INIT(parser, PM_ASSOC_NODE, flags, key->location.start, end),
2280 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
2290static pm_assoc_splat_node_t *
2291pm_assoc_splat_node_create(pm_parser_t *parser, pm_node_t *value, const pm_token_t *operator) {
2292 assert(operator->type == PM_TOKEN_USTAR_STAR);
2293 pm_assoc_splat_node_t *node = PM_NODE_ALLOC(parser, pm_assoc_splat_node_t);
2295 *node = (pm_assoc_splat_node_t) {
2298 ? PM_NODE_INIT_TOKEN(parser, PM_ASSOC_SPLAT_NODE, 0, operator)
2299 : PM_NODE_INIT_TOKEN_NODE(parser, PM_ASSOC_SPLAT_NODE, 0, operator, value)
2302 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2311static pm_back_reference_read_node_t *
2312pm_back_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
2313 assert(name->type == PM_TOKEN_BACK_REFERENCE);
2314 pm_back_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_back_reference_read_node_t);
2316 *node = (pm_back_reference_read_node_t) {
2317 .base = PM_NODE_INIT_TOKEN(parser, PM_BACK_REFERENCE_READ_NODE, 0, name),
2318 .name = pm_parser_constant_id_token(parser, name)
2327static pm_begin_node_t *
2328pm_begin_node_create(pm_parser_t *parser, const pm_token_t *begin_keyword, pm_statements_node_t *statements) {
2329 pm_begin_node_t *node = PM_NODE_ALLOC(parser, pm_begin_node_t);
2331 *node = (pm_begin_node_t) {
2333 (statements == NULL)
2334 ? PM_NODE_INIT_TOKEN(parser, PM_BEGIN_NODE, 0, begin_keyword)
2335 : PM_NODE_INIT_TOKEN_NODE(parser, PM_BEGIN_NODE, 0, begin_keyword, statements)
2337 .begin_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(begin_keyword),
2338 .statements = statements,
2339 .end_keyword_loc = { 0 }
2349pm_begin_node_rescue_clause_set(pm_begin_node_t *node, pm_rescue_node_t *rescue_clause) {
2350 // If the begin keyword doesn't exist, we set the start on the begin_node
2351 if (!node->begin_keyword_loc.start) {
2352 node->base.location.start = rescue_clause->base.location.start;
2354 node->base.location.end = rescue_clause->base.location.end;
2355 node->rescue_clause = rescue_clause;
2362pm_begin_node_else_clause_set(pm_begin_node_t *node, pm_else_node_t *else_clause) {
2363 node->base.location.end = else_clause->base.location.end;
2364 node->else_clause = else_clause;
2371pm_begin_node_ensure_clause_set(pm_begin_node_t *node, pm_ensure_node_t *ensure_clause) {
2372 node->base.location.end = ensure_clause->base.location.end;
2373 node->ensure_clause = ensure_clause;
2380pm_begin_node_end_keyword_set(pm_begin_node_t *node, const pm_token_t *end_keyword) {
2381 assert(end_keyword->type == PM_TOKEN_KEYWORD_END || end_keyword->type == PM_TOKEN_MISSING);
2383 node->base.location.end = end_keyword->end;
2384 node->end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword);
2390static pm_block_argument_node_t *
2391pm_block_argument_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
2392 pm_block_argument_node_t *node = PM_NODE_ALLOC(parser, pm_block_argument_node_t);
2394 *node = (pm_block_argument_node_t) {
2396 (expression == NULL)
2397 ? PM_NODE_INIT_TOKEN(parser, PM_BLOCK_ARGUMENT_NODE, 0, operator)
2398 : PM_NODE_INIT_TOKEN_NODE(parser, PM_BLOCK_ARGUMENT_NODE, 0, operator, expression)
2400 .expression = expression,
2401 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2410static pm_block_node_t *
2411pm_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) {
2412 pm_block_node_t *node = PM_NODE_ALLOC(parser, pm_block_node_t);
2414 *node = (pm_block_node_t) {
2415 .base = PM_NODE_INIT_TOKENS(parser, PM_BLOCK_NODE, 0, opening, closing),
2417 .parameters = parameters,
2419 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2420 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
2429static pm_block_parameter_node_t *
2430pm_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator) {
2431 assert(operator->type == PM_TOKEN_NOT_PROVIDED || operator->type == PM_TOKEN_UAMPERSAND || operator->type == PM_TOKEN_AMPERSAND);
2432 pm_block_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_block_parameter_node_t);
2434 *node = (pm_block_parameter_node_t) {
2436 (name->type == PM_TOKEN_NOT_PROVIDED)
2437 ? PM_NODE_INIT_TOKEN(parser, PM_BLOCK_PARAMETER_NODE, 0, operator)
2438 : PM_NODE_INIT_TOKENS(parser, PM_BLOCK_PARAMETER_NODE, 0, operator, name)
2440 .name = pm_parser_optional_constant_id_token(parser, name),
2441 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
2442 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2451static pm_block_parameters_node_t *
2452pm_block_parameters_node_create(pm_parser_t *parser, pm_parameters_node_t *parameters, const pm_token_t *opening) {
2453 pm_block_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_block_parameters_node_t);
2455 const uint8_t *start;
2456 if (opening->type != PM_TOKEN_NOT_PROVIDED) {
2457 start = opening->start;
2458 } else if (parameters != NULL) {
2459 start = parameters->base.location.start;
2465 if (parameters != NULL) {
2466 end = parameters->base.location.end;
2467 } else if (opening->type != PM_TOKEN_NOT_PROVIDED) {
2473 *node = (pm_block_parameters_node_t) {
2474 .base = PM_NODE_INIT(parser, PM_BLOCK_PARAMETERS_NODE, 0, start, end),
2475 .parameters = parameters,
2476 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2477 .closing_loc = { 0 },
2488pm_block_parameters_node_closing_set(pm_block_parameters_node_t *node, const pm_token_t *closing) {
2489 assert(closing->type == PM_TOKEN_PIPE || closing->type == PM_TOKEN_PARENTHESIS_RIGHT || closing->type == PM_TOKEN_MISSING);
2491 node->base.location.end = closing->end;
2492 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
2498static pm_block_local_variable_node_t *
2499pm_block_local_variable_node_create(pm_parser_t *parser, const pm_token_t *name) {
2500 pm_block_local_variable_node_t *node = PM_NODE_ALLOC(parser, pm_block_local_variable_node_t);
2502 *node = (pm_block_local_variable_node_t) {
2503 .base = PM_NODE_INIT_TOKEN(parser, PM_BLOCK_LOCAL_VARIABLE_NODE, 0, name),
2504 .name = pm_parser_constant_id_token(parser, name)
2514pm_block_parameters_node_append_local(pm_block_parameters_node_t *node, const pm_block_local_variable_node_t *local) {
2515 pm_node_list_append(&node->locals, UP(local));
2517 if (node->base.location.start == NULL) node->base.location.start = local->base.location.start;
2518 node->base.location.end = local->base.location.end;
2524static pm_break_node_t *
2525pm_break_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
2526 assert(keyword->type == PM_TOKEN_KEYWORD_BREAK);
2527 pm_break_node_t *node = PM_NODE_ALLOC(parser, pm_break_node_t);
2529 *node = (pm_break_node_t) {
2532 ? PM_NODE_INIT_TOKEN(parser, PM_BREAK_NODE, 0, keyword)
2533 : PM_NODE_INIT_TOKEN_NODE(parser, PM_BREAK_NODE, 0, keyword, arguments)
2535 .arguments = arguments,
2536 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
2542// There are certain flags that we want to use internally but don't want to
2543// expose because they are not relevant beyond parsing. Therefore we'll define
2544// them here and not define them in config.yml/a header file.
2545static const pm_node_flags_t PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY = (1 << 2);
2547static const pm_node_flags_t PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY = ((PM_CALL_NODE_FLAGS_LAST - 1) << 1);
2548static const pm_node_flags_t PM_CALL_NODE_FLAGS_COMPARISON = ((PM_CALL_NODE_FLAGS_LAST - 1) << 2);
2549static const pm_node_flags_t PM_CALL_NODE_FLAGS_INDEX = ((PM_CALL_NODE_FLAGS_LAST - 1) << 3);
2556static pm_call_node_t *
2557pm_call_node_create(pm_parser_t *parser, pm_node_flags_t flags) {
2558 pm_call_node_t *node = PM_NODE_ALLOC(parser, pm_call_node_t);
2560 *node = (pm_call_node_t) {
2561 .base = PM_NODE_INIT_BASE(parser, PM_CALL_NODE, flags),
2563 .call_operator_loc = { 0 },
2564 .message_loc = { 0 },
2565 .opening_loc = { 0 },
2567 .closing_loc = { 0 },
2580static inline pm_node_flags_t
2581pm_call_node_ignore_visibility_flag(const pm_node_t *receiver) {
2582 return PM_NODE_TYPE_P(receiver, PM_SELF_NODE) ? PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY : 0;
2589static pm_call_node_t *
2590pm_call_node_aref_create(pm_parser_t *parser, pm_node_t *receiver, pm_arguments_t *arguments) {
2591 pm_assert_value_expression(parser, receiver);
2593 pm_node_flags_t flags = pm_call_node_ignore_visibility_flag(receiver);
2594 if (arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_ARGUMENT_NODE)) {
2595 flags |= PM_CALL_NODE_FLAGS_INDEX;
2598 pm_call_node_t *node = pm_call_node_create(parser, flags);
2600 node->base.location.start = receiver->location.start;
2601 node->base.location.end = pm_arguments_end(arguments);
2603 node->receiver = receiver;
2604 node->message_loc.start = arguments->opening_loc.start;
2605 node->message_loc.end = arguments->closing_loc.end;
2607 node->opening_loc = arguments->opening_loc;
2608 node->arguments = arguments->arguments;
2609 node->closing_loc = arguments->closing_loc;
2610 node->block = arguments->block;
2612 node->name = pm_parser_constant_id_constant(parser, "[]", 2);
2619static pm_call_node_t *
2620pm_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) {
2621 pm_assert_value_expression(parser, receiver);
2622 pm_assert_value_expression(parser, argument);
2624 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver) | flags);
2626 node->base.location.start = MIN(receiver->location.start, argument->location.start);
2627 node->base.location.end = MAX(receiver->location.end, argument->location.end);
2629 node->receiver = receiver;
2630 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2632 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
2633 pm_arguments_node_arguments_append(arguments, argument);
2634 node->arguments = arguments;
2636 node->name = pm_parser_constant_id_token(parser, operator);
2640static const uint8_t * parse_operator_symbol_name(const pm_token_t *);
2645static pm_call_node_t *
2646pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_token_t *message, pm_arguments_t *arguments) {
2647 pm_assert_value_expression(parser, receiver);
2649 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2651 node->base.location.start = receiver->location.start;
2652 const uint8_t *end = pm_arguments_end(arguments);
2656 node->base.location.end = end;
2658 node->receiver = receiver;
2659 node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2660 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2661 node->opening_loc = arguments->opening_loc;
2662 node->arguments = arguments->arguments;
2663 node->closing_loc = arguments->closing_loc;
2664 node->block = arguments->block;
2666 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2667 pm_node_flag_set(UP(node), PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2674 node->name = pm_parser_constant_id_location(parser, message->start, parse_operator_symbol_name(message));
2681static pm_call_node_t *
2682pm_call_node_call_synthesized_create(pm_parser_t *parser, pm_node_t *receiver, const char *message, pm_arguments_node_t *arguments) {
2683 pm_call_node_t *node = pm_call_node_create(parser, 0);
2684 node->base.location.start = parser->start;
2685 node->base.location.end = parser->end;
2687 node->receiver = receiver;
2688 node->call_operator_loc = (pm_location_t) { .start = NULL, .end = NULL };
2689 node->message_loc = (pm_location_t) { .start = NULL, .end = NULL };
2690 node->arguments = arguments;
2692 node->name = pm_parser_constant_id_constant(parser, message, strlen(message));
2700static pm_call_node_t *
2701pm_call_node_fcall_create(pm_parser_t *parser, pm_token_t *message, pm_arguments_t *arguments) {
2702 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2704 node->base.location.start = message->start;
2705 node->base.location.end = pm_arguments_end(arguments);
2707 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2708 node->opening_loc = arguments->opening_loc;
2709 node->arguments = arguments->arguments;
2710 node->closing_loc = arguments->closing_loc;
2711 node->block = arguments->block;
2713 node->name = pm_parser_constant_id_token(parser, message);
2721static pm_call_node_t *
2722pm_call_node_fcall_synthesized_create(pm_parser_t *parser, pm_arguments_node_t *arguments, pm_constant_id_t name) {
2723 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2725 node->base.location = PM_LOCATION_NULL_VALUE(parser);
2726 node->arguments = arguments;
2735static pm_call_node_t *
2736pm_call_node_not_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *message, pm_arguments_t *arguments) {
2737 pm_assert_value_expression(parser, receiver);
2738 if (receiver != NULL) pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
2740 pm_call_node_t *node = pm_call_node_create(parser, receiver == NULL ? 0 : pm_call_node_ignore_visibility_flag(receiver));
2742 node->base.location.start = message->start;
2743 if (arguments->closing_loc.start != NULL) {
2744 node->base.location.end = arguments->closing_loc.end;
2746 assert(receiver != NULL);
2747 node->base.location.end = receiver->location.end;
2750 node->receiver = receiver;
2751 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2752 node->opening_loc = arguments->opening_loc;
2753 node->arguments = arguments->arguments;
2754 node->closing_loc = arguments->closing_loc;
2756 node->name = pm_parser_constant_id_constant(parser, "!", 1);
2763static pm_call_node_t *
2764pm_call_node_shorthand_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_arguments_t *arguments) {
2765 pm_assert_value_expression(parser, receiver);
2767 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2769 node->base.location.start = receiver->location.start;
2770 node->base.location.end = pm_arguments_end(arguments);
2772 node->receiver = receiver;
2773 node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2774 node->opening_loc = arguments->opening_loc;
2775 node->arguments = arguments->arguments;
2776 node->closing_loc = arguments->closing_loc;
2777 node->block = arguments->block;
2779 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2780 pm_node_flag_set(UP(node), PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2783 node->name = pm_parser_constant_id_constant(parser, "call", 4);
2790static pm_call_node_t *
2791pm_call_node_unary_create(pm_parser_t *parser, pm_token_t *operator, pm_node_t *receiver, const char *name) {
2792 pm_assert_value_expression(parser, receiver);
2794 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2796 node->base.location.start = operator->start;
2797 node->base.location.end = receiver->location.end;
2799 node->receiver = receiver;
2800 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2802 node->name = pm_parser_constant_id_constant(parser, name, strlen(name));
2810static pm_call_node_t *
2811pm_call_node_variable_call_create(pm_parser_t *parser, pm_token_t *message) {
2812 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2814 node->base.location = PM_LOCATION_TOKEN_VALUE(message);
2815 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2817 node->name = pm_parser_constant_id_token(parser, message);
2826pm_call_node_writable_p(const pm_parser_t *parser, const pm_call_node_t *node) {
2828 (node->message_loc.start != NULL) &&
2829 (node->message_loc.end[-1] != '!') &&
2830 (node->message_loc.end[-1] != '?') &&
2831 char_is_identifier_start(parser, node->message_loc.start, parser->end - node->message_loc.start) &&
2832 (node->opening_loc.start == NULL) &&
2833 (node->arguments == NULL) &&
2834 (node->block == NULL)
2842pm_call_write_read_name_init(pm_parser_t *parser, pm_constant_id_t *read_name, pm_constant_id_t *write_name) {
2843 pm_constant_t *write_constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *write_name);
2845 if (write_constant->length > 0) {
2846 size_t length = write_constant->length - 1;
2848 void *memory = xmalloc(length);
2849 memcpy(memory, write_constant->start, length);
2851 *read_name = pm_constant_pool_insert_owned(&parser->constant_pool, (uint8_t *) memory, length);
2853 // We can get here if the message was missing because of a syntax error.
2854 *read_name = pm_parser_constant_id_constant(parser, "", 0);
2861static pm_call_and_write_node_t *
2862pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2863 assert(target->block == NULL);
2864 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
2865 pm_call_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_and_write_node_t);
2867 *node = (pm_call_and_write_node_t) {
2868 .base = PM_NODE_INIT_NODES(parser, PM_CALL_AND_WRITE_NODE, FL(target), target, value),
2869 .receiver = target->receiver,
2870 .call_operator_loc = target->call_operator_loc,
2871 .message_loc = target->message_loc,
2873 .write_name = target->name,
2874 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2878 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
2880 // Here we're going to free the target, since it is no longer necessary.
2881 // However, we don't want to call `pm_node_destroy` because we want to keep
2882 // around all of its children since we just reused them.
2893pm_index_arguments_check(pm_parser_t *parser, const pm_arguments_node_t *arguments, const pm_node_t *block) {
2894 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) {
2895 if (arguments != NULL && PM_NODE_FLAG_P(arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) {
2897 PM_NODE_LIST_FOREACH(&arguments->arguments, index, node) {
2898 if (PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE)) {
2899 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_INDEX_KEYWORDS);
2905 if (block != NULL) {
2906 pm_parser_err_node(parser, block, PM_ERR_UNEXPECTED_INDEX_BLOCK);
2914static pm_index_and_write_node_t *
2915pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2916 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
2917 pm_index_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_and_write_node_t);
2919 pm_index_arguments_check(parser, target->arguments, target->block);
2921 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
2922 *node = (pm_index_and_write_node_t) {
2923 .base = PM_NODE_INIT_NODES(parser, PM_INDEX_AND_WRITE_NODE, FL(target), target, value),
2924 .receiver = target->receiver,
2925 .call_operator_loc = target->call_operator_loc,
2926 .opening_loc = target->opening_loc,
2927 .arguments = target->arguments,
2928 .closing_loc = target->closing_loc,
2929 .block = (pm_block_argument_node_t *) target->block,
2930 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2934 // Here we're going to free the target, since it is no longer necessary.
2935 // However, we don't want to call `pm_node_destroy` because we want to keep
2936 // around all of its children since we just reused them.
2945static pm_call_operator_write_node_t *
2946pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2947 assert(target->block == NULL);
2948 pm_call_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_operator_write_node_t);
2950 *node = (pm_call_operator_write_node_t) {
2951 .base = PM_NODE_INIT_NODES(parser, PM_CALL_OPERATOR_WRITE_NODE, FL(target), target, value),
2952 .receiver = target->receiver,
2953 .call_operator_loc = target->call_operator_loc,
2954 .message_loc = target->message_loc,
2956 .write_name = target->name,
2957 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
2958 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2962 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
2964 // Here we're going to free the target, since it is no longer necessary.
2965 // However, we don't want to call `pm_node_destroy` because we want to keep
2966 // around all of its children since we just reused them.
2975static pm_index_operator_write_node_t *
2976pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2977 pm_index_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_operator_write_node_t);
2979 pm_index_arguments_check(parser, target->arguments, target->block);
2981 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
2982 *node = (pm_index_operator_write_node_t) {
2983 .base = PM_NODE_INIT_NODES(parser, PM_INDEX_OPERATOR_WRITE_NODE, FL(target), target, value),
2984 .receiver = target->receiver,
2985 .call_operator_loc = target->call_operator_loc,
2986 .opening_loc = target->opening_loc,
2987 .arguments = target->arguments,
2988 .closing_loc = target->closing_loc,
2989 .block = (pm_block_argument_node_t *) target->block,
2990 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
2991 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2995 // Here we're going to free the target, since it is no longer necessary.
2996 // However, we don't want to call `pm_node_destroy` because we want to keep
2997 // around all of its children since we just reused them.
3006static pm_call_or_write_node_t *
3007pm_call_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3008 assert(target->block == NULL);
3009 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3010 pm_call_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_or_write_node_t);
3012 *node = (pm_call_or_write_node_t) {
3013 .base = PM_NODE_INIT_NODES(parser, PM_CALL_OR_WRITE_NODE, FL(target), target, value),
3014 .receiver = target->receiver,
3015 .call_operator_loc = target->call_operator_loc,
3016 .message_loc = target->message_loc,
3018 .write_name = target->name,
3019 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3023 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3025 // Here we're going to free the target, since it is no longer necessary.
3026 // However, we don't want to call `pm_node_destroy` because we want to keep
3027 // around all of its children since we just reused them.
3036static pm_index_or_write_node_t *
3037pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3038 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3039 pm_index_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_or_write_node_t);
3041 pm_index_arguments_check(parser, target->arguments, target->block);
3043 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3044 *node = (pm_index_or_write_node_t) {
3045 .base = PM_NODE_INIT_NODES(parser, PM_INDEX_OR_WRITE_NODE, FL(target), target, value),
3046 .receiver = target->receiver,
3047 .call_operator_loc = target->call_operator_loc,
3048 .opening_loc = target->opening_loc,
3049 .arguments = target->arguments,
3050 .closing_loc = target->closing_loc,
3051 .block = (pm_block_argument_node_t *) target->block,
3052 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3056 // Here we're going to free the target, since it is no longer necessary.
3057 // However, we don't want to call `pm_node_destroy` because we want to keep
3058 // around all of its children since we just reused them.
3068static pm_call_target_node_t *
3069pm_call_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3070 pm_call_target_node_t *node = PM_NODE_ALLOC(parser, pm_call_target_node_t);
3072 *node = (pm_call_target_node_t) {
3073 .base = PM_NODE_INIT_NODE(parser, PM_CALL_TARGET_NODE, FL(target), target),
3074 .receiver = target->receiver,
3075 .call_operator_loc = target->call_operator_loc,
3076 .name = target->name,
3077 .message_loc = target->message_loc
3080 // Here we're going to free the target, since it is no longer necessary.
3081 // However, we don't want to call `pm_node_destroy` because we want to keep
3082 // around all of its children since we just reused them.
3092static pm_index_target_node_t *
3093pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3094 pm_index_target_node_t *node = PM_NODE_ALLOC(parser, pm_index_target_node_t);
3096 pm_index_arguments_check(parser, target->arguments, target->block);
3097 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3099 *node = (pm_index_target_node_t) {
3100 .base = PM_NODE_INIT_NODE(parser, PM_INDEX_TARGET_NODE, FL(target) | PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE, target),
3101 .receiver = target->receiver,
3102 .opening_loc = target->opening_loc,
3103 .arguments = target->arguments,
3104 .closing_loc = target->closing_loc,
3105 .block = (pm_block_argument_node_t *) target->block,
3108 // Here we're going to free the target, since it is no longer necessary.
3109 // However, we don't want to call `pm_node_destroy` because we want to keep
3110 // around all of its children since we just reused them.
3119static pm_capture_pattern_node_t *
3120pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_local_variable_target_node_t *target, const pm_token_t *operator) {
3121 pm_capture_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_capture_pattern_node_t);
3123 *node = (pm_capture_pattern_node_t) {
3124 .base = PM_NODE_INIT_NODES(parser, PM_CAPTURE_PATTERN_NODE, 0, value, target),
3127 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
3136static pm_case_node_t *
3137pm_case_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3138 pm_case_node_t *node = PM_NODE_ALLOC(parser, pm_case_node_t);
3140 *node = (pm_case_node_t) {
3141 .base = PM_NODE_INIT_TOKENS(parser, PM_CASE_NODE, 0, case_keyword, end_keyword),
3142 .predicate = predicate,
3143 .else_clause = NULL,
3144 .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
3145 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3156pm_case_node_condition_append(pm_case_node_t *node, pm_node_t *condition) {
3157 assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
3159 pm_node_list_append(&node->conditions, condition);
3160 node->base.location.end = condition->location.end;
3167pm_case_node_else_clause_set(pm_case_node_t *node, pm_else_node_t *else_clause) {
3168 node->else_clause = else_clause;
3169 node->base.location.end = else_clause->base.location.end;
3176pm_case_node_end_keyword_loc_set(pm_case_node_t *node, const pm_token_t *end_keyword) {
3177 node->base.location.end = end_keyword->end;
3178 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
3184static pm_case_match_node_t *
3185pm_case_match_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3186 pm_case_match_node_t *node = PM_NODE_ALLOC(parser, pm_case_match_node_t);
3188 *node = (pm_case_match_node_t) {
3189 .base = PM_NODE_INIT_TOKENS(parser, PM_CASE_MATCH_NODE, 0, case_keyword, end_keyword),
3190 .predicate = predicate,
3191 .else_clause = NULL,
3192 .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
3193 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3204pm_case_match_node_condition_append(pm_case_match_node_t *node, pm_node_t *condition) {
3205 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
3207 pm_node_list_append(&node->conditions, condition);
3208 node->base.location.end = condition->location.end;
3215pm_case_match_node_else_clause_set(pm_case_match_node_t *node, pm_else_node_t *else_clause) {
3216 node->else_clause = else_clause;
3217 node->base.location.end = else_clause->base.location.end;
3224pm_case_match_node_end_keyword_loc_set(pm_case_match_node_t *node, const pm_token_t *end_keyword) {
3225 node->base.location.end = end_keyword->end;
3226 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
3232static pm_class_node_t *
3233pm_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) {
3234 pm_class_node_t *node = PM_NODE_ALLOC(parser, pm_class_node_t);
3236 *node = (pm_class_node_t) {
3237 .base = PM_NODE_INIT_TOKENS(parser, PM_CLASS_NODE, 0, class_keyword, end_keyword),
3239 .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
3240 .constant_path = constant_path,
3241 .inheritance_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(inheritance_operator),
3242 .superclass = superclass,
3244 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3245 .name = pm_parser_constant_id_token(parser, name)
3254static pm_class_variable_and_write_node_t *
3255pm_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) {
3256 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3257 pm_class_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_and_write_node_t);
3259 *node = (pm_class_variable_and_write_node_t) {
3260 .base = PM_NODE_INIT_NODES(parser, PM_CLASS_VARIABLE_AND_WRITE_NODE, 0, target, value),
3261 .name = target->name,
3262 .name_loc = target->base.location,
3263 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3273static pm_class_variable_operator_write_node_t *
3274pm_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) {
3275 pm_class_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_operator_write_node_t);
3277 *node = (pm_class_variable_operator_write_node_t) {
3278 .base = PM_NODE_INIT_NODES(parser, PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE, 0, target, value),
3279 .name = target->name,
3280 .name_loc = target->base.location,
3281 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3283 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3292static pm_class_variable_or_write_node_t *
3293pm_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) {
3294 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3295 pm_class_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_or_write_node_t);
3297 *node = (pm_class_variable_or_write_node_t) {
3298 .base = PM_NODE_INIT_NODES(parser, PM_CLASS_VARIABLE_OR_WRITE_NODE, 0, target, value),
3299 .name = target->name,
3300 .name_loc = target->base.location,
3301 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3311static pm_class_variable_read_node_t *
3312pm_class_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
3313 assert(token->type == PM_TOKEN_CLASS_VARIABLE);
3314 pm_class_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_read_node_t);
3316 *node = (pm_class_variable_read_node_t) {
3317 .base = PM_NODE_INIT_TOKEN(parser, PM_CLASS_VARIABLE_READ_NODE, 0, token),
3318 .name = pm_parser_constant_id_token(parser, token)
3330static inline pm_node_flags_t
3331pm_implicit_array_write_flags(const pm_node_t *node, pm_node_flags_t flags) {
3332 if (PM_NODE_TYPE_P(node, PM_ARRAY_NODE) && ((const pm_array_node_t *) node)->opening_loc.start == NULL) {
3341static pm_class_variable_write_node_t *
3342pm_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) {
3343 pm_class_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_write_node_t);
3344 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
3346 *node = (pm_class_variable_write_node_t) {
3347 .base = PM_NODE_INIT_NODES(parser, PM_CLASS_VARIABLE_WRITE_NODE, flags, read_node, value),
3348 .name = read_node->name,
3349 .name_loc = PM_LOCATION_NODE_VALUE(UP(read_node)),
3350 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3360static pm_constant_path_and_write_node_t *
3361pm_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) {
3362 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3363 pm_constant_path_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_and_write_node_t);
3365 *node = (pm_constant_path_and_write_node_t) {
3366 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_PATH_AND_WRITE_NODE, 0, target, value),
3368 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3378static pm_constant_path_operator_write_node_t *
3379pm_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) {
3380 pm_constant_path_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_operator_write_node_t);
3382 *node = (pm_constant_path_operator_write_node_t) {
3383 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_PATH_OPERATOR_WRITE_NODE, 0, target, value),
3385 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3387 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3396static pm_constant_path_or_write_node_t *
3397pm_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) {
3398 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3399 pm_constant_path_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_or_write_node_t);
3401 *node = (pm_constant_path_or_write_node_t) {
3402 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_PATH_OR_WRITE_NODE, 0, target, value),
3404 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3414static pm_constant_path_node_t *
3415pm_constant_path_node_create(pm_parser_t *parser, pm_node_t *parent, const pm_token_t *delimiter, const pm_token_t *name_token) {
3416 pm_assert_value_expression(parser, parent);
3417 pm_constant_path_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_node_t);
3419 pm_constant_id_t name = PM_CONSTANT_ID_UNSET;
3420 if (name_token->type == PM_TOKEN_CONSTANT) {
3421 name = pm_parser_constant_id_token(parser, name_token);
3424 if (parent == NULL) {
3425 *node = (pm_constant_path_node_t) {
3426 .base = PM_NODE_INIT_TOKENS(parser, PM_CONSTANT_PATH_NODE, 0, delimiter, name_token),
3429 .delimiter_loc = PM_LOCATION_TOKEN_VALUE(delimiter),
3430 .name_loc = PM_LOCATION_TOKEN_VALUE(name_token)
3433 *node = (pm_constant_path_node_t) {
3434 .base = PM_NODE_INIT_NODE_TOKEN(parser, PM_CONSTANT_PATH_NODE, 0, parent, name_token),
3437 .delimiter_loc = PM_LOCATION_TOKEN_VALUE(delimiter),
3438 .name_loc = PM_LOCATION_TOKEN_VALUE(name_token)
3448static pm_constant_path_write_node_t *
3449pm_constant_path_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3450 pm_constant_path_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_write_node_t);
3451 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
3453 *node = (pm_constant_path_write_node_t) {
3454 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_PATH_WRITE_NODE, flags, target, value),
3456 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3466static pm_constant_and_write_node_t *
3467pm_constant_and_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3468 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3469 pm_constant_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_and_write_node_t);
3471 *node = (pm_constant_and_write_node_t) {
3472 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_AND_WRITE_NODE, 0, target, value),
3473 .name = target->name,
3474 .name_loc = target->base.location,
3475 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3485static pm_constant_operator_write_node_t *
3486pm_constant_operator_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3487 pm_constant_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_operator_write_node_t);
3489 *node = (pm_constant_operator_write_node_t) {
3490 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_OPERATOR_WRITE_NODE, 0, target, value),
3491 .name = target->name,
3492 .name_loc = target->base.location,
3493 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3495 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3504static pm_constant_or_write_node_t *
3505pm_constant_or_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3506 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3507 pm_constant_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_or_write_node_t);
3509 *node = (pm_constant_or_write_node_t) {
3510 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_OR_WRITE_NODE, 0, target, value),
3511 .name = target->name,
3512 .name_loc = target->base.location,
3513 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3523static pm_constant_read_node_t *
3524pm_constant_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
3525 assert(name->type == PM_TOKEN_CONSTANT || name->type == PM_TOKEN_MISSING);
3526 pm_constant_read_node_t *node = PM_NODE_ALLOC(parser, pm_constant_read_node_t);
3528 *node = (pm_constant_read_node_t) {
3529 .base = PM_NODE_INIT_TOKEN(parser, PM_CONSTANT_READ_NODE, 0, name),
3530 .name = pm_parser_constant_id_token(parser, name)
3539static pm_constant_write_node_t *
3540pm_constant_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3541 pm_constant_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_write_node_t);
3542 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
3544 *node = (pm_constant_write_node_t) {
3545 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_WRITE_NODE, flags, target, value),
3546 .name = target->name,
3547 .name_loc = target->base.location,
3548 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3559pm_def_node_receiver_check(pm_parser_t *parser, const pm_node_t *node) {
3560 switch (PM_NODE_TYPE(node)) {
3561 case PM_BEGIN_NODE: {
3562 const pm_begin_node_t *cast = (pm_begin_node_t *) node;
3563 if (cast->statements != NULL) pm_def_node_receiver_check(parser, UP(cast->statements));
3566 case PM_PARENTHESES_NODE: {
3567 const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node;
3568 if (cast->body != NULL) pm_def_node_receiver_check(parser, cast->body);
3571 case PM_STATEMENTS_NODE: {
3572 const pm_statements_node_t *cast = (const pm_statements_node_t *) node;
3573 pm_def_node_receiver_check(parser, cast->body.nodes[cast->body.size - 1]);
3578 case PM_IMAGINARY_NODE:
3579 case PM_INTEGER_NODE:
3580 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
3581 case PM_INTERPOLATED_STRING_NODE:
3582 case PM_INTERPOLATED_SYMBOL_NODE:
3583 case PM_INTERPOLATED_X_STRING_NODE:
3584 case PM_RATIONAL_NODE:
3585 case PM_REGULAR_EXPRESSION_NODE:
3586 case PM_SOURCE_ENCODING_NODE:
3587 case PM_SOURCE_FILE_NODE:
3588 case PM_SOURCE_LINE_NODE:
3589 case PM_STRING_NODE:
3590 case PM_SYMBOL_NODE:
3591 case PM_X_STRING_NODE:
3592 pm_parser_err_node(parser, node, PM_ERR_SINGLETON_FOR_LITERALS);
3602static pm_def_node_t *
3604 pm_parser_t *parser,
3605 pm_constant_id_t name,
3606 const pm_token_t *name_loc,
3607 pm_node_t *receiver,
3608 pm_parameters_node_t *parameters,
3610 pm_constant_id_list_t *locals,
3611 const pm_token_t *def_keyword,
3612 const pm_token_t *operator,
3613 const pm_token_t *lparen,
3614 const pm_token_t *rparen,
3615 const pm_token_t *equal,
3616 const pm_token_t *end_keyword
3618 pm_def_node_t *node = PM_NODE_ALLOC(parser, pm_def_node_t);
3620 if (receiver != NULL) {
3621 pm_def_node_receiver_check(parser, receiver);
3624 *node = (pm_def_node_t) {
3626 (end_keyword->type == PM_TOKEN_NOT_PROVIDED)
3627 ? PM_NODE_INIT_TOKEN_NODE(parser, PM_DEF_NODE, 0, def_keyword, body)
3628 : PM_NODE_INIT_TOKENS(parser, PM_DEF_NODE, 0, def_keyword, end_keyword)
3631 .name_loc = PM_LOCATION_TOKEN_VALUE(name_loc),
3632 .receiver = receiver,
3633 .parameters = parameters,
3636 .def_keyword_loc = PM_LOCATION_TOKEN_VALUE(def_keyword),
3637 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3638 .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
3639 .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
3640 .equal_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(equal),
3641 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
3650static pm_defined_node_t *
3651pm_defined_node_create(pm_parser_t *parser, const pm_token_t *lparen, pm_node_t *value, const pm_token_t *rparen, const pm_token_t *keyword) {
3652 pm_defined_node_t *node = PM_NODE_ALLOC(parser, pm_defined_node_t);
3654 *node = (pm_defined_node_t) {
3656 (rparen->type == PM_TOKEN_NOT_PROVIDED)
3657 ? PM_NODE_INIT_TOKEN_NODE(parser, PM_DEFINED_NODE, 0, keyword, value)
3658 : PM_NODE_INIT_TOKENS(parser, PM_DEFINED_NODE, 0, keyword, rparen)
3660 .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
3662 .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
3663 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
3672static pm_else_node_t *
3673pm_else_node_create(pm_parser_t *parser, const pm_token_t *else_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
3674 pm_else_node_t *node = PM_NODE_ALLOC(parser, pm_else_node_t);
3676 *node = (pm_else_node_t) {
3678 ((end_keyword->type == PM_TOKEN_NOT_PROVIDED) && (statements != NULL))
3679 ? PM_NODE_INIT_TOKEN_NODE(parser, PM_ELSE_NODE, 0, else_keyword, statements)
3680 : PM_NODE_INIT_TOKENS(parser, PM_ELSE_NODE, 0, else_keyword, end_keyword)
3682 .else_keyword_loc = PM_LOCATION_TOKEN_VALUE(else_keyword),
3683 .statements = statements,
3684 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
3693static pm_embedded_statements_node_t *
3694pm_embedded_statements_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
3695 pm_embedded_statements_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_statements_node_t);
3697 *node = (pm_embedded_statements_node_t) {
3698 .base = PM_NODE_INIT_TOKENS(parser, PM_EMBEDDED_STATEMENTS_NODE, 0, opening, closing),
3699 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
3700 .statements = statements,
3701 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
3710static pm_embedded_variable_node_t *
3711pm_embedded_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
3712 pm_embedded_variable_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_variable_node_t);
3714 *node = (pm_embedded_variable_node_t) {
3715 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_EMBEDDED_VARIABLE_NODE, 0, operator, variable),
3716 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3717 .variable = variable
3726static pm_ensure_node_t *
3727pm_ensure_node_create(pm_parser_t *parser, const pm_token_t *ensure_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
3728 pm_ensure_node_t *node = PM_NODE_ALLOC(parser, pm_ensure_node_t);
3730 *node = (pm_ensure_node_t) {
3731 .base = PM_NODE_INIT_TOKENS(parser, PM_ENSURE_NODE, 0, ensure_keyword, end_keyword),
3732 .ensure_keyword_loc = PM_LOCATION_TOKEN_VALUE(ensure_keyword),
3733 .statements = statements,
3734 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
3743static pm_false_node_t *
3744pm_false_node_create(pm_parser_t *parser, const pm_token_t *token) {
3745 assert(token->type == PM_TOKEN_KEYWORD_FALSE);
3746 pm_false_node_t *node = PM_NODE_ALLOC(parser, pm_false_node_t);
3748 *node = (pm_false_node_t) {
3749 .base = PM_NODE_INIT_TOKEN(parser, PM_FALSE_NODE, PM_NODE_FLAG_STATIC_LITERAL, token)
3759static pm_find_pattern_node_t *
3760pm_find_pattern_node_create(pm_parser_t *parser, pm_node_list_t *nodes) {
3761 pm_find_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_find_pattern_node_t);
3763 pm_node_t *left = nodes->nodes[0];
3764 assert(PM_NODE_TYPE_P(left, PM_SPLAT_NODE));
3765 pm_splat_node_t *left_splat_node = (pm_splat_node_t *) left;
3769 if (nodes->size == 1) {
3770 right = UP(pm_missing_node_create(parser, left->location.end, left->location.end));
3772 right = nodes->nodes[nodes->size - 1];
3773 assert(PM_NODE_TYPE_P(right, PM_SPLAT_NODE));
3776#if PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS
3777 // FindPatternNode#right is typed as SplatNode in this case, so replace the potential MissingNode with a SplatNode.
3778 // The resulting AST will anyway be ignored, but this file still needs to compile.
3779 pm_splat_node_t *right_splat_node = PM_NODE_TYPE_P(right, PM_SPLAT_NODE) ? (pm_splat_node_t *) right : left_splat_node;
3781 pm_node_t *right_splat_node = right;
3783 *node = (pm_find_pattern_node_t) {
3784 .base = PM_NODE_INIT_NODES(parser, PM_FIND_PATTERN_NODE, 0, left, right),
3786 .left = left_splat_node,
3787 .right = right_splat_node,
3789 .opening_loc = { 0 },
3790 .closing_loc = { 0 }
3793 // For now we're going to just copy over each pointer manually. This could be
3794 // much more efficient, as we could instead resize the node list to only point
3796 for (size_t index = 1; index < nodes->size - 1; index++) {
3797 pm_node_list_append(&node->requireds, nodes->nodes[index]);
3808pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
3809 ptrdiff_t diff = token->end - token->start;
3810 if (diff <= 0) return 0.0;
3812 // First, get a buffer of the content.
3813 size_t length = (size_t) diff;
3814 char *buffer = xmalloc(sizeof(char) * (length + 1));
3815 memcpy((void *) buffer, token->start, length);
3817 // Next, determine if we need to replace the decimal point because of
3818 // locale-specific options, and then normalize them if we have to.
3819 char decimal_point = *localeconv()->decimal_point;
3820 if (decimal_point != '.') {
3821 for (size_t index = 0; index < length; index++) {
3822 if (buffer[index] == '.') buffer[index] = decimal_point;
3826 // Next, handle underscores by removing them from the buffer.
3827 for (size_t index = 0; index < length; index++) {
3828 if (buffer[index] == '_') {
3829 memmove((void *) (buffer + index), (void *) (buffer + index + 1), length - index);
3834 // Null-terminate the buffer so that strtod cannot read off the end.
3835 buffer[length] = '\0';
3837 // Now, call strtod to parse the value. Note that CRuby has their own
3838 // version of strtod which avoids locales. We're okay using the locale-aware
3839 // version because we've already validated through the parser that the token
3840 // is in a valid format.
3843 double value = strtod(buffer, &eptr);
3845 // This should never happen, because we've already checked that the token
3846 // is in a valid format. However it's good to be safe.
3847 if ((eptr != buffer + length) || (errno != 0 && errno != ERANGE)) {
3848 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, (*token), PM_ERR_FLOAT_PARSE);
3849 xfree((void *) buffer);
3853 // If errno is set, then it should only be ERANGE. At this point we need to
3854 // check if it's infinity (it should be).
3855 if (errno == ERANGE && PRISM_ISINF(value)) {
3857 const char *ellipsis;
3863 warn_width = (int) length;
3867 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);
3868 value = (value < 0.0) ? -HUGE_VAL : HUGE_VAL;
3871 // Finally we can free the buffer and return the value.
3872 xfree((void *) buffer);
3879static pm_float_node_t *
3880pm_float_node_create(pm_parser_t *parser, const pm_token_t *token) {
3881 assert(token->type == PM_TOKEN_FLOAT);
3882 pm_float_node_t *node = PM_NODE_ALLOC(parser, pm_float_node_t);
3884 *node = (pm_float_node_t) {
3885 .base = PM_NODE_INIT_TOKEN(parser, PM_FLOAT_NODE, PM_NODE_FLAG_STATIC_LITERAL, token),
3886 .value = pm_double_parse(parser, token)
3895static pm_imaginary_node_t *
3896pm_float_node_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
3897 assert(token->type == PM_TOKEN_FLOAT_IMAGINARY);
3899 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
3900 *node = (pm_imaginary_node_t) {
3901 .base = PM_NODE_INIT_TOKEN(parser, PM_IMAGINARY_NODE, PM_NODE_FLAG_STATIC_LITERAL, token),
3902 .numeric = UP(pm_float_node_create(parser, &((pm_token_t) {
3903 .type = PM_TOKEN_FLOAT,
3904 .start = token->start,
3905 .end = token->end - 1
3915static pm_rational_node_t *
3916pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
3917 assert(token->type == PM_TOKEN_FLOAT_RATIONAL);
3919 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
3920 *node = (pm_rational_node_t) {
3921 .base = PM_NODE_INIT_TOKEN(parser, PM_RATIONAL_NODE, PM_INTEGER_BASE_FLAGS_DECIMAL | PM_NODE_FLAG_STATIC_LITERAL, token),
3923 .denominator = { 0 }
3926 const uint8_t *start = token->start;
3927 const uint8_t *end = token->end - 1; // r
3929 while (start < end && *start == '0') start++; // 0.1 -> .1
3930 while (end > start && end[-1] == '0') end--; // 1.0 -> 1.
3932 size_t length = (size_t) (end - start);
3934 node->denominator.value = 1;
3938 const uint8_t *point = memchr(start, '.', length);
3939 assert(point && "should have a decimal point");
3941 uint8_t *digits = xmalloc(length);
3942 if (digits == NULL) {
3943 fputs("[pm_float_node_rational_create] Failed to allocate memory", stderr);
3947 memcpy(digits, start, (unsigned long) (point - start));
3948 memcpy(digits + (point - start), point + 1, (unsigned long) (end - point - 1));
3949 pm_integer_parse(&node->numerator, PM_INTEGER_BASE_DEFAULT, digits, digits + length - 1);
3952 if (end - point > 1) memset(digits + 1, '0', (size_t) (end - point - 1));
3953 pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + (end - point));
3956 pm_integers_reduce(&node->numerator, &node->denominator);
3964static pm_imaginary_node_t *
3965pm_float_node_rational_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
3966 assert(token->type == PM_TOKEN_FLOAT_RATIONAL_IMAGINARY);
3968 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
3969 *node = (pm_imaginary_node_t) {
3970 .base = PM_NODE_INIT_TOKEN(parser, PM_IMAGINARY_NODE, PM_NODE_FLAG_STATIC_LITERAL, token),
3971 .numeric = UP(pm_float_node_rational_create(parser, &((pm_token_t) {
3972 .type = PM_TOKEN_FLOAT_RATIONAL,
3973 .start = token->start,
3974 .end = token->end - 1
3984static pm_for_node_t *
3986 pm_parser_t *parser,
3988 pm_node_t *collection,
3989 pm_statements_node_t *statements,
3990 const pm_token_t *for_keyword,
3991 const pm_token_t *in_keyword,
3992 const pm_token_t *do_keyword,
3993 const pm_token_t *end_keyword
3995 pm_for_node_t *node = PM_NODE_ALLOC(parser, pm_for_node_t);
3997 *node = (pm_for_node_t) {
3998 .base = PM_NODE_INIT_TOKENS(parser, PM_FOR_NODE, 0, for_keyword, end_keyword),
4000 .collection = collection,
4001 .statements = statements,
4002 .for_keyword_loc = PM_LOCATION_TOKEN_VALUE(for_keyword),
4003 .in_keyword_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
4004 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
4005 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
4014static pm_forwarding_arguments_node_t *
4015pm_forwarding_arguments_node_create(pm_parser_t *parser, const pm_token_t *token) {
4016 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4017 pm_forwarding_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_arguments_node_t);
4019 *node = (pm_forwarding_arguments_node_t) {
4020 .base = PM_NODE_INIT_TOKEN(parser, PM_FORWARDING_ARGUMENTS_NODE, 0, token)
4029static pm_forwarding_parameter_node_t *
4030pm_forwarding_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
4031 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4032 pm_forwarding_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_parameter_node_t);
4034 *node = (pm_forwarding_parameter_node_t) {
4035 .base = PM_NODE_INIT_TOKEN(parser, PM_FORWARDING_PARAMETER_NODE, 0, token)
4044static pm_forwarding_super_node_t *
4045pm_forwarding_super_node_create(pm_parser_t *parser, const pm_token_t *token, pm_arguments_t *arguments) {
4046 assert(arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_NODE));
4047 assert(token->type == PM_TOKEN_KEYWORD_SUPER);
4048 pm_forwarding_super_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_super_node_t);
4050 pm_block_node_t *block = NULL;
4051 if (arguments->block != NULL) {
4052 block = (pm_block_node_t *) arguments->block;
4055 *node = (pm_forwarding_super_node_t) {
4058 ? PM_NODE_INIT_TOKEN(parser, PM_FORWARDING_SUPER_NODE, 0, token)
4059 : PM_NODE_INIT_TOKEN_NODE(parser, PM_FORWARDING_SUPER_NODE, 0, token, block)
4071static pm_hash_pattern_node_t *
4072pm_hash_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4073 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4075 *node = (pm_hash_pattern_node_t) {
4076 .base = PM_NODE_INIT_TOKENS(parser, PM_HASH_PATTERN_NODE, 0, opening, closing),
4078 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4079 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
4090static pm_hash_pattern_node_t *
4091pm_hash_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *elements, pm_node_t *rest) {
4092 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4094 const uint8_t *start;
4097 if (elements->size > 0) {
4099 start = elements->nodes[0]->location.start;
4100 end = rest->location.end;
4102 start = elements->nodes[0]->location.start;
4103 end = elements->nodes[elements->size - 1]->location.end;
4106 assert(rest != NULL);
4107 start = rest->location.start;
4108 end = rest->location.end;
4111 *node = (pm_hash_pattern_node_t) {
4112 .base = PM_NODE_INIT(parser, PM_HASH_PATTERN_NODE, 0, start, end),
4116 .opening_loc = { 0 },
4117 .closing_loc = { 0 }
4121 PM_NODE_LIST_FOREACH(elements, index, element) {
4122 pm_node_list_append(&node->elements, element);
4131static pm_constant_id_t
4132pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
4133 switch (PM_NODE_TYPE(target)) {
4134 case PM_GLOBAL_VARIABLE_READ_NODE:
4135 return ((pm_global_variable_read_node_t *) target)->name;
4136 case PM_BACK_REFERENCE_READ_NODE:
4137 return ((pm_back_reference_read_node_t *) target)->name;
4138 case PM_NUMBERED_REFERENCE_READ_NODE:
4139 // This will only ever happen in the event of a syntax error, but we
4140 // still need to provide something for the node.
4141 return pm_parser_constant_id_location(parser, target->location.start, target->location.end);
4143 assert(false && "unreachable");
4144 return (pm_constant_id_t) -1;
4151static pm_global_variable_and_write_node_t *
4152pm_global_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4153 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4154 pm_global_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_and_write_node_t);
4156 *node = (pm_global_variable_and_write_node_t) {
4157 .base = PM_NODE_INIT_NODES(parser, PM_GLOBAL_VARIABLE_AND_WRITE_NODE, 0, target, value),
4158 .name = pm_global_variable_write_name(parser, target),
4159 .name_loc = target->location,
4160 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4170static pm_global_variable_operator_write_node_t *
4171pm_global_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4172 pm_global_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_operator_write_node_t);
4174 *node = (pm_global_variable_operator_write_node_t) {
4175 .base = PM_NODE_INIT_NODES(parser, PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE, 0, target, value),
4176 .name = pm_global_variable_write_name(parser, target),
4177 .name_loc = target->location,
4178 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4180 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
4189static pm_global_variable_or_write_node_t *
4190pm_global_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4191 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4192 pm_global_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_or_write_node_t);
4194 *node = (pm_global_variable_or_write_node_t) {
4195 .base = PM_NODE_INIT_NODES(parser, PM_GLOBAL_VARIABLE_OR_WRITE_NODE, 0, target, value),
4196 .name = pm_global_variable_write_name(parser, target),
4197 .name_loc = target->location,
4198 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4208static pm_global_variable_read_node_t *
4209pm_global_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
4210 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4212 *node = (pm_global_variable_read_node_t) {
4213 .base = PM_NODE_INIT_TOKEN(parser, PM_GLOBAL_VARIABLE_READ_NODE, 0, name),
4214 .name = pm_parser_constant_id_token(parser, name)
4223static pm_global_variable_read_node_t *
4224pm_global_variable_read_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name) {
4225 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4227 *node = (pm_global_variable_read_node_t) {
4228 .base = PM_NODE_INIT_BASE(parser, PM_GLOBAL_VARIABLE_READ_NODE, 0),
4238static pm_global_variable_write_node_t *
4239pm_global_variable_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4240 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4241 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
4243 *node = (pm_global_variable_write_node_t) {
4244 .base = PM_NODE_INIT_NODES(parser, PM_GLOBAL_VARIABLE_WRITE_NODE, flags, target, value),
4245 .name = pm_global_variable_write_name(parser, target),
4246 .name_loc = PM_LOCATION_NODE_VALUE(target),
4247 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
4257static pm_global_variable_write_node_t *
4258pm_global_variable_write_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name, pm_node_t *value) {
4259 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4261 *node = (pm_global_variable_write_node_t) {
4262 .base = PM_NODE_INIT_BASE(parser, PM_GLOBAL_VARIABLE_WRITE_NODE, 0),
4264 .name_loc = PM_LOCATION_NULL_VALUE(parser),
4265 .operator_loc = PM_LOCATION_NULL_VALUE(parser),
4275static pm_hash_node_t *
4276pm_hash_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4277 assert(opening != NULL);
4278 pm_hash_node_t *node = PM_NODE_ALLOC(parser, pm_hash_node_t);
4280 *node = (pm_hash_node_t) {
4281 .base = PM_NODE_INIT_TOKEN(parser, PM_HASH_NODE, PM_NODE_FLAG_STATIC_LITERAL, opening),
4282 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4283 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
4294pm_hash_node_elements_append(pm_hash_node_t *hash, pm_node_t *element) {
4295 pm_node_list_append(&hash->elements, element);
4297 bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE);
4298 if (static_literal) {
4299 pm_assoc_node_t *assoc = (pm_assoc_node_t *) element;
4300 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);
4301 static_literal = static_literal && PM_NODE_FLAG_P(assoc->key, PM_NODE_FLAG_STATIC_LITERAL);
4302 static_literal = static_literal && PM_NODE_FLAG_P(assoc, PM_NODE_FLAG_STATIC_LITERAL);
4305 if (!static_literal) {
4306 pm_node_flag_unset(UP(hash), PM_NODE_FLAG_STATIC_LITERAL);
4311pm_hash_node_closing_loc_set(pm_hash_node_t *hash, pm_token_t *token) {
4312 hash->base.location.end = token->end;
4313 hash->closing_loc = PM_LOCATION_TOKEN_VALUE(token);
4319static pm_if_node_t *
4320pm_if_node_create(pm_parser_t *parser,
4321 const pm_token_t *if_keyword,
4322 pm_node_t *predicate,
4323 const pm_token_t *then_keyword,
4324 pm_statements_node_t *statements,
4325 pm_node_t *subsequent,
4326 const pm_token_t *end_keyword
4328 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4329 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4332 if (end_keyword->type != PM_TOKEN_NOT_PROVIDED) {
4333 end = end_keyword->end;
4334 } else if (subsequent != NULL) {
4335 end = subsequent->location.end;
4336 } else if (pm_statements_node_body_length(statements) != 0) {
4337 end = statements->base.location.end;
4339 end = predicate->location.end;
4342 *node = (pm_if_node_t) {
4343 .base = PM_NODE_INIT(parser, PM_IF_NODE, PM_NODE_FLAG_NEWLINE, if_keyword->start, end),
4344 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4345 .predicate = predicate,
4346 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
4347 .statements = statements,
4348 .subsequent = subsequent,
4349 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
4358static pm_if_node_t *
4359pm_if_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *if_keyword, pm_node_t *predicate) {
4360 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4361 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4363 pm_statements_node_t *statements = pm_statements_node_create(parser);
4364 pm_statements_node_body_append(parser, statements, statement, true);
4366 *node = (pm_if_node_t) {
4367 .base = PM_NODE_INIT_NODES(parser, PM_IF_NODE, PM_NODE_FLAG_NEWLINE, statement, predicate),
4368 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4369 .predicate = predicate,
4370 .then_keyword_loc = { 0 },
4371 .statements = statements,
4373 .end_keyword_loc = { 0 }
4382static pm_if_node_t *
4383pm_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) {
4384 pm_assert_value_expression(parser, predicate);
4385 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4387 pm_statements_node_t *if_statements = pm_statements_node_create(parser);
4388 pm_statements_node_body_append(parser, if_statements, true_expression, true);
4390 pm_statements_node_t *else_statements = pm_statements_node_create(parser);
4391 pm_statements_node_body_append(parser, else_statements, false_expression, true);
4393 pm_token_t end_keyword = not_provided(parser);
4394 pm_else_node_t *else_node = pm_else_node_create(parser, colon, else_statements, &end_keyword);
4396 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4398 *node = (pm_if_node_t) {
4399 .base = PM_NODE_INIT_NODES(parser, PM_IF_NODE, PM_NODE_FLAG_NEWLINE, predicate, false_expression),
4400 .if_keyword_loc = { 0 },
4401 .predicate = predicate,
4402 .then_keyword_loc = PM_LOCATION_TOKEN_VALUE(qmark),
4403 .statements = if_statements,
4404 .subsequent = UP(else_node),
4405 .end_keyword_loc = { 0 }
4413pm_if_node_end_keyword_loc_set(pm_if_node_t *node, const pm_token_t *keyword) {
4414 node->base.location.end = keyword->end;
4415 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4419pm_else_node_end_keyword_loc_set(pm_else_node_t *node, const pm_token_t *keyword) {
4420 node->base.location.end = keyword->end;
4421 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4427static pm_implicit_node_t *
4428pm_implicit_node_create(pm_parser_t *parser, pm_node_t *value) {
4429 pm_implicit_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_node_t);
4431 *node = (pm_implicit_node_t) {
4432 .base = PM_NODE_INIT_NODE(parser, PM_IMPLICIT_NODE, 0, value),
4442static pm_implicit_rest_node_t *
4443pm_implicit_rest_node_create(pm_parser_t *parser, const pm_token_t *token) {
4444 assert(token->type == PM_TOKEN_COMMA);
4446 pm_implicit_rest_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_rest_node_t);
4448 *node = (pm_implicit_rest_node_t) {
4449 .base = PM_NODE_INIT_TOKEN(parser, PM_IMPLICIT_REST_NODE, 0, token)
4458static pm_integer_node_t *
4459pm_integer_node_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4460 assert(token->type == PM_TOKEN_INTEGER);
4461 pm_integer_node_t *node = PM_NODE_ALLOC(parser, pm_integer_node_t);
4463 *node = (pm_integer_node_t) {
4464 .base = PM_NODE_INIT_TOKEN(parser, PM_INTEGER_NODE, base | PM_NODE_FLAG_STATIC_LITERAL, token),
4468 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4470 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4471 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4472 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4473 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4474 default: assert(false && "unreachable"); break;
4477 pm_integer_parse(&node->value, integer_base, token->start, token->end);
4485static pm_imaginary_node_t *
4486pm_integer_node_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4487 assert(token->type == PM_TOKEN_INTEGER_IMAGINARY);
4489 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4490 *node = (pm_imaginary_node_t) {
4491 .base = PM_NODE_INIT_TOKEN(parser, PM_IMAGINARY_NODE, PM_NODE_FLAG_STATIC_LITERAL, token),
4492 .numeric = UP(pm_integer_node_create(parser, base, &((pm_token_t) {
4493 .type = PM_TOKEN_INTEGER,
4494 .start = token->start,
4495 .end = token->end - 1
4506static pm_rational_node_t *
4507pm_integer_node_rational_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4508 assert(token->type == PM_TOKEN_INTEGER_RATIONAL);
4510 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
4511 *node = (pm_rational_node_t) {
4512 .base = PM_NODE_INIT_TOKEN(parser, PM_RATIONAL_NODE, base | PM_NODE_FLAG_STATIC_LITERAL, token),
4514 .denominator = { .value = 1, 0 }
4517 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4519 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4520 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4521 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4522 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4523 default: assert(false && "unreachable"); break;
4526 pm_integer_parse(&node->numerator, integer_base, token->start, token->end - 1);
4535static pm_imaginary_node_t *
4536pm_integer_node_rational_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4537 assert(token->type == PM_TOKEN_INTEGER_RATIONAL_IMAGINARY);
4539 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4540 *node = (pm_imaginary_node_t) {
4541 .base = PM_NODE_INIT_TOKEN(parser, PM_IMAGINARY_NODE, PM_NODE_FLAG_STATIC_LITERAL, token),
4542 .numeric = UP(pm_integer_node_rational_create(parser, base, &((pm_token_t) {
4543 .type = PM_TOKEN_INTEGER_RATIONAL,
4544 .start = token->start,
4545 .end = token->end - 1
4555static pm_in_node_t *
4556pm_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) {
4557 pm_in_node_t *node = PM_NODE_ALLOC(parser, pm_in_node_t);
4560 if (statements != NULL) {
4561 end = statements->base.location.end;
4562 } else if (then_keyword->type != PM_TOKEN_NOT_PROVIDED) {
4563 end = then_keyword->end;
4565 end = pattern->location.end;
4568 *node = (pm_in_node_t) {
4569 .base = PM_NODE_INIT(parser, PM_IN_NODE, 0, in_keyword->start, end),
4571 .statements = statements,
4572 .in_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
4573 .then_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword)
4582static pm_instance_variable_and_write_node_t *
4583pm_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) {
4584 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4585 pm_instance_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_and_write_node_t);
4587 *node = (pm_instance_variable_and_write_node_t) {
4588 .base = PM_NODE_INIT_NODES(parser, PM_INSTANCE_VARIABLE_AND_WRITE_NODE, 0, target, value),
4589 .name = target->name,
4590 .name_loc = target->base.location,
4591 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4601static pm_instance_variable_operator_write_node_t *
4602pm_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) {
4603 pm_instance_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_operator_write_node_t);
4605 *node = (pm_instance_variable_operator_write_node_t) {
4606 .base = PM_NODE_INIT_NODES(parser, PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE, 0, target, value),
4607 .name = target->name,
4608 .name_loc = target->base.location,
4609 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4611 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
4620static pm_instance_variable_or_write_node_t *
4621pm_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) {
4622 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4623 pm_instance_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_or_write_node_t);
4625 *node = (pm_instance_variable_or_write_node_t) {
4626 .base = PM_NODE_INIT_NODES(parser, PM_INSTANCE_VARIABLE_OR_WRITE_NODE, 0, target, value),
4627 .name = target->name,
4628 .name_loc = target->base.location,
4629 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4639static pm_instance_variable_read_node_t *
4640pm_instance_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
4641 assert(token->type == PM_TOKEN_INSTANCE_VARIABLE);
4642 pm_instance_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_read_node_t);
4644 *node = (pm_instance_variable_read_node_t) {
4645 .base = PM_NODE_INIT_TOKEN(parser, PM_INSTANCE_VARIABLE_READ_NODE, 0, token),
4646 .name = pm_parser_constant_id_token(parser, token)
4656static pm_instance_variable_write_node_t *
4657pm_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) {
4658 pm_instance_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_write_node_t);
4659 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
4661 *node = (pm_instance_variable_write_node_t) {
4662 .base = PM_NODE_INIT_NODES(parser, PM_INSTANCE_VARIABLE_WRITE_NODE, flags, read_node, value),
4663 .name = read_node->name,
4664 .name_loc = PM_LOCATION_NODE_VALUE(read_node),
4665 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
4678pm_interpolated_node_append(pm_node_t *node, pm_node_list_t *parts, pm_node_t *part) {
4679 switch (PM_NODE_TYPE(part)) {
4680 case PM_STRING_NODE:
4681 pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
4683 case PM_EMBEDDED_STATEMENTS_NODE: {
4684 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
4685 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
4687 if (embedded == NULL) {
4688 // If there are no statements or more than one statement, then
4689 // we lose the static literal flag.
4690 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
4691 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
4692 // If the embedded statement is a string, then we can keep the
4693 // static literal flag and mark the string as frozen.
4694 pm_node_flag_set(embedded, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
4695 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
4696 // If the embedded statement is an interpolated string and it's
4697 // a static literal, then we can keep the static literal flag.
4699 // Otherwise we lose the static literal flag.
4700 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
4705 case PM_EMBEDDED_VARIABLE_NODE:
4706 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
4709 assert(false && "unexpected node type");
4713 pm_node_list_append(parts, part);
4719static pm_interpolated_regular_expression_node_t *
4720pm_interpolated_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4721 pm_interpolated_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_regular_expression_node_t);
4723 *node = (pm_interpolated_regular_expression_node_t) {
4724 .base = PM_NODE_INIT_TOKEN(parser, PM_INTERPOLATED_REGULAR_EXPRESSION_NODE, PM_NODE_FLAG_STATIC_LITERAL, opening),
4725 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4726 .closing_loc = PM_LOCATION_TOKEN_VALUE(opening),
4734pm_interpolated_regular_expression_node_append(pm_interpolated_regular_expression_node_t *node, pm_node_t *part) {
4735 if (node->base.location.start > part->location.start) {
4736 node->base.location.start = part->location.start;
4738 if (node->base.location.end < part->location.end) {
4739 node->base.location.end = part->location.end;
4742 pm_interpolated_node_append(UP(node), &node->parts, part);
4746pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_interpolated_regular_expression_node_t *node, const pm_token_t *closing) {
4747 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
4748 node->base.location.end = closing->end;
4749 pm_node_flag_set(UP(node), pm_regular_expression_flags_create(parser, closing));
4776pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_node_t *part) {
4777#define CLEAR_FLAGS(node) \
4778 node->base.flags = (pm_node_flags_t) (FL(node) & ~(PM_NODE_FLAG_STATIC_LITERAL | PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE))
4780#define MUTABLE_FLAGS(node) \
4781 node->base.flags = (pm_node_flags_t) ((FL(node) | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE) & ~PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN);
4783 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
4784 node->base.location.start = part->location.start;
4787 node->base.location.end = MAX(node->base.location.end, part->location.end);
4789 switch (PM_NODE_TYPE(part)) {
4790 case PM_STRING_NODE:
4791 // If inner string is not frozen, it stops being a static literal. We should *not* clear other flags,
4792 // because concatenating two frozen strings (`'foo' 'bar'`) is still frozen. This holds true for
4793 // as long as this interpolation only consists of other string literals.
4794 if (!PM_NODE_FLAG_P(part, PM_STRING_FLAGS_FROZEN)) {
4795 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
4797 part->flags = (pm_node_flags_t) ((part->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
4799 case PM_INTERPOLATED_STRING_NODE:
4800 if (PM_NODE_FLAG_P(part, PM_NODE_FLAG_STATIC_LITERAL)) {
4801 // If the string that we're concatenating is a static literal,
4802 // then we can keep the static literal flag for this string.
4804 // Otherwise, we lose the static literal flag here and we should
4805 // also clear the mutability flags.
4809 case PM_EMBEDDED_STATEMENTS_NODE: {
4810 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
4811 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
4813 if (embedded == NULL) {
4814 // If we're embedding multiple statements or no statements, then
4815 // the string is not longer a static literal.
4817 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
4818 // If the embedded statement is a string, then we can make that
4819 // string as frozen and static literal, and not touch the static
4820 // literal status of this string.
4821 embedded->flags = (pm_node_flags_t) ((embedded->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
4823 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
4824 MUTABLE_FLAGS(node);
4826 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
4827 // If the embedded statement is an interpolated string, but that
4828 // string is marked as static literal, then we can keep our
4829 // static literal status for this string.
4830 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
4831 MUTABLE_FLAGS(node);
4834 // In all other cases, we lose the static literal flag here and
4841 case PM_EMBEDDED_VARIABLE_NODE:
4842 // Embedded variables clear static literal, which means we also
4843 // should clear the mutability flags.
4846 case PM_X_STRING_NODE:
4847 case PM_INTERPOLATED_X_STRING_NODE:
4848 case PM_SYMBOL_NODE:
4849 case PM_INTERPOLATED_SYMBOL_NODE:
4850 // These will only happen in error cases. But we want to handle it
4851 // here so that we don't fail the assertion.
4855 assert(false && "unexpected node type");
4859 pm_node_list_append(&node->parts, part);
4868static pm_interpolated_string_node_t *
4869pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
4870 pm_interpolated_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_string_node_t);
4871 pm_node_flags_t flags = PM_NODE_FLAG_STATIC_LITERAL;
4873 switch (parser->frozen_string_literal) {
4874 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
4875 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE;
4877 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
4878 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN;
4882 *node = (pm_interpolated_string_node_t) {
4883 .base = PM_NODE_INIT_TOKENS(parser, PM_INTERPOLATED_STRING_NODE, flags, opening, closing),
4884 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
4885 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
4889 if (parts != NULL) {
4891 PM_NODE_LIST_FOREACH(parts, index, part) {
4892 pm_interpolated_string_node_append(node, part);
4903pm_interpolated_string_node_closing_set(pm_interpolated_string_node_t *node, const pm_token_t *closing) {
4904 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
4905 node->base.location.end = closing->end;
4909pm_interpolated_symbol_node_append(pm_interpolated_symbol_node_t *node, pm_node_t *part) {
4910 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
4911 node->base.location.start = part->location.start;
4914 pm_interpolated_node_append(UP(node), &node->parts, part);
4915 node->base.location.end = MAX(node->base.location.end, part->location.end);
4919pm_interpolated_symbol_node_closing_loc_set(pm_interpolated_symbol_node_t *node, const pm_token_t *closing) {
4920 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
4921 node->base.location.end = closing->end;
4927static pm_interpolated_symbol_node_t *
4928pm_interpolated_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
4929 pm_interpolated_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_symbol_node_t);
4931 *node = (pm_interpolated_symbol_node_t) {
4932 .base = PM_NODE_INIT_TOKENS(parser, PM_INTERPOLATED_SYMBOL_NODE, PM_NODE_FLAG_STATIC_LITERAL, opening, closing),
4933 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
4934 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
4938 if (parts != NULL) {
4940 PM_NODE_LIST_FOREACH(parts, index, part) {
4941 pm_interpolated_symbol_node_append(node, part);
4951static pm_interpolated_x_string_node_t *
4952pm_interpolated_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4953 pm_interpolated_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_x_string_node_t);
4955 *node = (pm_interpolated_x_string_node_t) {
4956 .base = PM_NODE_INIT_TOKENS(parser, PM_INTERPOLATED_X_STRING_NODE, 0, opening, closing),
4957 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
4958 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
4966pm_interpolated_xstring_node_append(pm_interpolated_x_string_node_t *node, pm_node_t *part) {
4967 pm_interpolated_node_append(UP(node), &node->parts, part);
4968 node->base.location.end = part->location.end;
4972pm_interpolated_xstring_node_closing_set(pm_interpolated_x_string_node_t *node, const pm_token_t *closing) {
4973 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
4974 node->base.location.end = closing->end;
4980static pm_it_local_variable_read_node_t *
4981pm_it_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
4982 pm_it_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_it_local_variable_read_node_t);
4984 *node = (pm_it_local_variable_read_node_t) {
4985 .base = PM_NODE_INIT_TOKEN(parser, PM_IT_LOCAL_VARIABLE_READ_NODE, 0, name),
4994static pm_it_parameters_node_t *
4995pm_it_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4996 pm_it_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_it_parameters_node_t);
4998 *node = (pm_it_parameters_node_t) {
4999 .base = PM_NODE_INIT_TOKENS(parser, PM_IT_PARAMETERS_NODE, 0, opening, closing),
5008static pm_keyword_hash_node_t *
5009pm_keyword_hash_node_create(pm_parser_t *parser) {
5010 pm_keyword_hash_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_hash_node_t);
5012 *node = (pm_keyword_hash_node_t) {
5013 .base = PM_NODE_INIT_UNSET(parser, PM_KEYWORD_HASH_NODE, PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS),
5024pm_keyword_hash_node_elements_append(pm_keyword_hash_node_t *hash, pm_node_t *element) {
5025 // If the element being added is not an AssocNode or does not have a symbol
5026 // key, then we want to turn the SYMBOL_KEYS flag off.
5027 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE) || !PM_NODE_TYPE_P(((pm_assoc_node_t *) element)->key, PM_SYMBOL_NODE)) {
5028 pm_node_flag_unset(UP(hash), PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS);
5031 pm_node_list_append(&hash->elements, element);
5032 if (hash->base.location.start == NULL) {
5033 hash->base.location.start = element->location.start;
5035 hash->base.location.end = element->location.end;
5041static pm_required_keyword_parameter_node_t *
5042pm_required_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name) {
5043 pm_required_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_keyword_parameter_node_t);
5045 *node = (pm_required_keyword_parameter_node_t) {
5046 .base = PM_NODE_INIT_TOKEN(parser, PM_REQUIRED_KEYWORD_PARAMETER_NODE, 0, name),
5047 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5048 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5057static pm_optional_keyword_parameter_node_t *
5058pm_optional_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, pm_node_t *value) {
5059 pm_optional_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_keyword_parameter_node_t);
5061 *node = (pm_optional_keyword_parameter_node_t) {
5062 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_OPTIONAL_KEYWORD_PARAMETER_NODE, 0, name, value),
5063 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5064 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5074static pm_keyword_rest_parameter_node_t *
5075pm_keyword_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
5076 pm_keyword_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_rest_parameter_node_t);
5078 *node = (pm_keyword_rest_parameter_node_t) {
5080 (name->type == PM_TOKEN_NOT_PROVIDED)
5081 ? PM_NODE_INIT_TOKEN(parser, PM_KEYWORD_REST_PARAMETER_NODE, 0, operator)
5082 : PM_NODE_INIT_TOKENS(parser, PM_KEYWORD_REST_PARAMETER_NODE, 0, operator, name)
5084 .name = pm_parser_optional_constant_id_token(parser, name),
5085 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
5086 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5095static pm_lambda_node_t *
5096pm_lambda_node_create(
5097 pm_parser_t *parser,
5098 pm_constant_id_list_t *locals,
5099 const pm_token_t *operator,
5100 const pm_token_t *opening,
5101 const pm_token_t *closing,
5102 pm_node_t *parameters,
5105 pm_lambda_node_t *node = PM_NODE_ALLOC(parser, pm_lambda_node_t);
5107 *node = (pm_lambda_node_t) {
5108 .base = PM_NODE_INIT_TOKENS(parser, PM_LAMBDA_NODE, 0, operator, closing),
5110 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5111 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5112 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
5113 .parameters = parameters,
5123static pm_local_variable_and_write_node_t *
5124pm_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) {
5125 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));
5126 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5127 pm_local_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_and_write_node_t);
5129 *node = (pm_local_variable_and_write_node_t) {
5130 .base = PM_NODE_INIT_NODES(parser, PM_LOCAL_VARIABLE_AND_WRITE_NODE, 0, target, value),
5131 .name_loc = target->location,
5132 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5144static pm_local_variable_operator_write_node_t *
5145pm_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) {
5146 pm_local_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_operator_write_node_t);
5148 *node = (pm_local_variable_operator_write_node_t) {
5149 .base = PM_NODE_INIT_NODES(parser, PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE, 0, target, value),
5150 .name_loc = target->location,
5151 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5154 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
5164static pm_local_variable_or_write_node_t *
5165pm_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) {
5166 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));
5167 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5168 pm_local_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_or_write_node_t);
5170 *node = (pm_local_variable_or_write_node_t) {
5171 .base = PM_NODE_INIT_NODES(parser, PM_LOCAL_VARIABLE_OR_WRITE_NODE, 0, target, value),
5172 .name_loc = target->location,
5173 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5185static pm_local_variable_read_node_t *
5186pm_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) {
5187 if (!missing) pm_locals_read(&pm_parser_scope_find(parser, depth)->locals, name_id);
5189 pm_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_read_node_t);
5191 *node = (pm_local_variable_read_node_t) {
5192 .base = PM_NODE_INIT_TOKEN(parser, PM_LOCAL_VARIABLE_READ_NODE, 0, name),
5203static pm_local_variable_read_node_t *
5204pm_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5205 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5206 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, false);
5213static pm_local_variable_read_node_t *
5214pm_local_variable_read_node_missing_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5215 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5216 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, true);
5222static pm_local_variable_write_node_t *
5223pm_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) {
5224 pm_local_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_write_node_t);
5225 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
5227 *node = (pm_local_variable_write_node_t) {
5228 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_LOCAL_VARIABLE_WRITE_NODE, flags, name_loc, value),
5232 .name_loc = *name_loc,
5233 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator)
5243pm_token_is_it(const uint8_t *start, const uint8_t *end) {
5244 return (end - start == 2) && (start[0] == 'i') && (start[1] == 't');
5252pm_token_is_numbered_parameter(const uint8_t *start, const uint8_t *end) {
5253 return (end - start == 2) && (start[0] == '_') && (start[1] != '0') && (pm_char_is_decimal_digit(start[1]));
5261pm_refute_numbered_parameter(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
5262 if (pm_token_is_numbered_parameter(start, end)) {
5263 PM_PARSER_ERR_FORMAT(parser, start, end, PM_ERR_PARAMETER_NUMBERED_RESERVED, start);
5271static pm_local_variable_target_node_t *
5272pm_local_variable_target_node_create(pm_parser_t *parser, const pm_location_t *location, pm_constant_id_t name, uint32_t depth) {
5273 pm_refute_numbered_parameter(parser, location->start, location->end);
5274 pm_local_variable_target_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_target_node_t);
5276 *node = (pm_local_variable_target_node_t) {
5277 .base = PM_NODE_INIT_TOKEN(parser, PM_LOCAL_VARIABLE_TARGET_NODE, 0, location),
5288static pm_match_predicate_node_t *
5289pm_match_predicate_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5290 pm_assert_value_expression(parser, value);
5292 pm_match_predicate_node_t *node = PM_NODE_ALLOC(parser, pm_match_predicate_node_t);
5294 *node = (pm_match_predicate_node_t) {
5295 .base = PM_NODE_INIT_NODES(parser, PM_MATCH_PREDICATE_NODE, 0, value, pattern),
5298 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5307static pm_match_required_node_t *
5308pm_match_required_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5309 pm_assert_value_expression(parser, value);
5311 pm_match_required_node_t *node = PM_NODE_ALLOC(parser, pm_match_required_node_t);
5313 *node = (pm_match_required_node_t) {
5314 .base = PM_NODE_INIT_NODES(parser, PM_MATCH_REQUIRED_NODE, 0, value, pattern),
5317 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5326static pm_match_write_node_t *
5327pm_match_write_node_create(pm_parser_t *parser, pm_call_node_t *call) {
5328 pm_match_write_node_t *node = PM_NODE_ALLOC(parser, pm_match_write_node_t);
5330 *node = (pm_match_write_node_t) {
5331 .base = PM_NODE_INIT_NODE(parser, PM_MATCH_WRITE_NODE, 0, call),
5342static pm_module_node_t *
5343pm_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) {
5344 pm_module_node_t *node = PM_NODE_ALLOC(parser, pm_module_node_t);
5346 *node = (pm_module_node_t) {
5347 .base = PM_NODE_INIT_TOKENS(parser, PM_MODULE_NODE, 0, module_keyword, end_keyword),
5348 .locals = (locals == NULL ? ((pm_constant_id_list_t) { .ids = NULL, .size = 0, .capacity = 0 }) : *locals),
5349 .module_keyword_loc = PM_LOCATION_TOKEN_VALUE(module_keyword),
5350 .constant_path = constant_path,
5352 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
5353 .name = pm_parser_constant_id_token(parser, name)
5362static pm_multi_target_node_t *
5363pm_multi_target_node_create(pm_parser_t *parser) {
5364 pm_multi_target_node_t *node = PM_NODE_ALLOC(parser, pm_multi_target_node_t);
5366 *node = (pm_multi_target_node_t) {
5367 .base = PM_NODE_INIT_UNSET(parser, PM_MULTI_TARGET_NODE, 0),
5371 .lparen_loc = { 0 },
5382pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t *node, pm_node_t *target) {
5383 if (PM_NODE_TYPE_P(target, PM_SPLAT_NODE)) {
5384 if (node->rest == NULL) {
5385 node->rest = target;
5387 pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
5388 pm_node_list_append(&node->rights, target);
5390 } else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
5391 if (node->rest == NULL) {
5392 node->rest = target;
5394 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
5395 pm_node_list_append(&node->rights, target);
5397 } else if (node->rest == NULL) {
5398 pm_node_list_append(&node->lefts, target);
5400 pm_node_list_append(&node->rights, target);
5403 if (node->base.location.start == NULL || (node->base.location.start > target->location.start)) {
5404 node->base.location.start = target->location.start;
5407 if (node->base.location.end == NULL || (node->base.location.end < target->location.end)) {
5408 node->base.location.end = target->location.end;
5416pm_multi_target_node_opening_set(pm_multi_target_node_t *node, const pm_token_t *lparen) {
5417 node->base.location.start = lparen->start;
5418 node->lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen);
5425pm_multi_target_node_closing_set(pm_multi_target_node_t *node, const pm_token_t *rparen) {
5426 node->base.location.end = rparen->end;
5427 node->rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen);
5433static pm_multi_write_node_t *
5434pm_multi_write_node_create(pm_parser_t *parser, pm_multi_target_node_t *target, const pm_token_t *operator, pm_node_t *value) {
5435 pm_multi_write_node_t *node = PM_NODE_ALLOC(parser, pm_multi_write_node_t);
5436 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
5438 *node = (pm_multi_write_node_t) {
5439 .base = PM_NODE_INIT_NODES(parser, PM_MULTI_WRITE_NODE, flags, target, value),
5440 .lefts = target->lefts,
5441 .rest = target->rest,
5442 .rights = target->rights,
5443 .lparen_loc = target->lparen_loc,
5444 .rparen_loc = target->rparen_loc,
5445 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5449 // Explicitly do not call pm_node_destroy here because we want to keep
5450 // around all of the information within the MultiWriteNode node.
5459static pm_next_node_t *
5460pm_next_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
5461 assert(keyword->type == PM_TOKEN_KEYWORD_NEXT);
5462 pm_next_node_t *node = PM_NODE_ALLOC(parser, pm_next_node_t);
5464 *node = (pm_next_node_t) {
5467 ? PM_NODE_INIT_TOKEN(parser, PM_NEXT_NODE, 0, keyword)
5468 : PM_NODE_INIT_TOKEN_NODE(parser, PM_NEXT_NODE, 0, keyword, arguments)
5470 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
5471 .arguments = arguments
5480static pm_nil_node_t *
5481pm_nil_node_create(pm_parser_t *parser, const pm_token_t *token) {
5482 assert(token->type == PM_TOKEN_KEYWORD_NIL);
5483 pm_nil_node_t *node = PM_NODE_ALLOC(parser, pm_nil_node_t);
5485 *node = (pm_nil_node_t) {
5486 .base = PM_NODE_INIT_TOKEN(parser, PM_NIL_NODE, PM_NODE_FLAG_STATIC_LITERAL, token)
5495static pm_no_keywords_parameter_node_t *
5496pm_no_keywords_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
5497 assert(operator->type == PM_TOKEN_USTAR_STAR || operator->type == PM_TOKEN_STAR_STAR);
5498 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
5499 pm_no_keywords_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_no_keywords_parameter_node_t);
5501 *node = (pm_no_keywords_parameter_node_t) {
5502 .base = PM_NODE_INIT_TOKENS(parser, PM_NO_KEYWORDS_PARAMETER_NODE, 0, operator, keyword),
5503 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5504 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
5513static pm_numbered_parameters_node_t *
5514pm_numbered_parameters_node_create(pm_parser_t *parser, const pm_location_t *location, uint8_t maximum) {
5515 pm_numbered_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_parameters_node_t);
5517 *node = (pm_numbered_parameters_node_t) {
5518 .base = PM_NODE_INIT_TOKEN(parser, PM_NUMBERED_PARAMETERS_NODE, 0, location),
5529#define NTH_REF_MAX ((uint32_t) (INT_MAX >> 1))
5538pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *token) {
5539 const uint8_t *start = token->start + 1;
5540 const uint8_t *end = token->end;
5542 ptrdiff_t diff = end - start;
5544#if PTRDIFF_MAX > SIZE_MAX
5545 assert(diff < (ptrdiff_t) SIZE_MAX);
5547 size_t length = (size_t) diff;
5549 char *digits = xcalloc(length + 1, sizeof(char));
5550 memcpy(digits, start, length);
5551 digits[length] = '\0';
5555 unsigned long value = strtoul(digits, &endptr, 10);
5557 if ((digits == endptr) || (*endptr != '\0')) {
5558 pm_parser_err(parser, start, end, PM_ERR_INVALID_NUMBER_DECIMAL);
5564 if ((errno == ERANGE) || (value > NTH_REF_MAX)) {
5565 PM_PARSER_WARN_FORMAT(parser, start, end, PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start);
5569 return (uint32_t) value;
5577static pm_numbered_reference_read_node_t *
5578pm_numbered_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5579 assert(name->type == PM_TOKEN_NUMBERED_REFERENCE);
5580 pm_numbered_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_reference_read_node_t);
5582 *node = (pm_numbered_reference_read_node_t) {
5583 .base = PM_NODE_INIT_TOKEN(parser, PM_NUMBERED_REFERENCE_READ_NODE, 0, name),
5584 .number = pm_numbered_reference_read_node_number(parser, name)
5593static pm_optional_parameter_node_t *
5594pm_optional_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator, pm_node_t *value) {
5595 pm_optional_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_parameter_node_t);
5597 *node = (pm_optional_parameter_node_t) {
5598 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_OPTIONAL_PARAMETER_NODE, 0, name, value),
5599 .name = pm_parser_constant_id_token(parser, name),
5600 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5601 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5611static pm_or_node_t *
5612pm_or_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
5613 pm_assert_value_expression(parser, left);
5615 pm_or_node_t *node = PM_NODE_ALLOC(parser, pm_or_node_t);
5617 *node = (pm_or_node_t) {
5618 .base = PM_NODE_INIT_NODES(parser, PM_OR_NODE, 0, left, right),
5621 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5630static pm_parameters_node_t *
5631pm_parameters_node_create(pm_parser_t *parser) {
5632 pm_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_parameters_node_t);
5634 *node = (pm_parameters_node_t) {
5635 .base = PM_NODE_INIT_UNSET(parser, PM_PARAMETERS_NODE, 0),
5637 .keyword_rest = NULL,
5652pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param) {
5653 if (params->base.location.start == NULL) {
5654 params->base.location.start = param->location.start;
5656 params->base.location.start = params->base.location.start < param->location.start ? params->base.location.start : param->location.start;
5659 if (params->base.location.end == NULL) {
5660 params->base.location.end = param->location.end;
5662 params->base.location.end = params->base.location.end > param->location.end ? params->base.location.end : param->location.end;
5670pm_parameters_node_requireds_append(pm_parameters_node_t *params, pm_node_t *param) {
5671 pm_parameters_node_location_set(params, param);
5672 pm_node_list_append(¶ms->requireds, param);
5679pm_parameters_node_optionals_append(pm_parameters_node_t *params, pm_optional_parameter_node_t *param) {
5680 pm_parameters_node_location_set(params, UP(param));
5681 pm_node_list_append(¶ms->optionals, UP(param));
5688pm_parameters_node_posts_append(pm_parameters_node_t *params, pm_node_t *param) {
5689 pm_parameters_node_location_set(params, param);
5690 pm_node_list_append(¶ms->posts, param);
5697pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
5698 pm_parameters_node_location_set(params, param);
5699 params->rest = param;
5706pm_parameters_node_keywords_append(pm_parameters_node_t *params, pm_node_t *param) {
5707 pm_parameters_node_location_set(params, param);
5708 pm_node_list_append(¶ms->keywords, param);
5715pm_parameters_node_keyword_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
5716 assert(params->keyword_rest == NULL);
5717 pm_parameters_node_location_set(params, param);
5718 params->keyword_rest = param;
5725pm_parameters_node_block_set(pm_parameters_node_t *params, pm_block_parameter_node_t *param) {
5726 assert(params->block == NULL);
5727 pm_parameters_node_location_set(params, UP(param));
5728 params->block = param;
5734static pm_program_node_t *
5735pm_program_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, pm_statements_node_t *statements) {
5736 pm_program_node_t *node = PM_NODE_ALLOC(parser, pm_program_node_t);
5738 *node = (pm_program_node_t) {
5739 .base = PM_NODE_INIT_NODE(parser, PM_PROGRAM_NODE, 0, statements),
5741 .statements = statements
5750static pm_parentheses_node_t *
5751pm_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) {
5752 pm_parentheses_node_t *node = PM_NODE_ALLOC(parser, pm_parentheses_node_t);
5754 *node = (pm_parentheses_node_t) {
5755 .base = PM_NODE_INIT_TOKENS(parser, PM_PARENTHESES_NODE, flags, opening, closing),
5757 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5758 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
5767static pm_pinned_expression_node_t *
5768pm_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) {
5769 pm_pinned_expression_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_expression_node_t);
5771 *node = (pm_pinned_expression_node_t) {
5772 .base = PM_NODE_INIT_TOKENS(parser, PM_PINNED_EXPRESSION_NODE, 0, operator, rparen),
5773 .expression = expression,
5774 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5775 .lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen),
5776 .rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen)
5785static pm_pinned_variable_node_t *
5786pm_pinned_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
5787 pm_pinned_variable_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_variable_node_t);
5789 *node = (pm_pinned_variable_node_t) {
5790 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_PINNED_VARIABLE_NODE, 0, operator, variable),
5791 .variable = variable,
5792 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5801static pm_post_execution_node_t *
5802pm_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) {
5803 pm_post_execution_node_t *node = PM_NODE_ALLOC(parser, pm_post_execution_node_t);
5805 *node = (pm_post_execution_node_t) {
5806 .base = PM_NODE_INIT_TOKENS(parser, PM_POST_EXECUTION_NODE, 0, keyword, closing),
5807 .statements = statements,
5808 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
5809 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5810 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
5819static pm_pre_execution_node_t *
5820pm_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) {
5821 pm_pre_execution_node_t *node = PM_NODE_ALLOC(parser, pm_pre_execution_node_t);
5823 *node = (pm_pre_execution_node_t) {
5824 .base = PM_NODE_INIT_TOKENS(parser, PM_PRE_EXECUTION_NODE, 0, keyword, closing),
5825 .statements = statements,
5826 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
5827 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5828 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
5837static pm_range_node_t *
5838pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
5839 pm_assert_value_expression(parser, left);
5840 pm_assert_value_expression(parser, right);
5842 pm_range_node_t *node = PM_NODE_ALLOC(parser, pm_range_node_t);
5843 pm_node_flags_t flags = 0;
5845 // Indicate that this node is an exclusive range if the operator is `...`.
5846 if (operator->type == PM_TOKEN_DOT_DOT_DOT || operator->type == PM_TOKEN_UDOT_DOT_DOT) {
5847 flags |= PM_RANGE_FLAGS_EXCLUDE_END;
5850 // Indicate that this node is a static literal (i.e., can be compiled with
5851 // a putobject in CRuby) if the left and right are implicit nil, explicit
5852 // nil, or integers.
5854 (left == NULL || PM_NODE_TYPE_P(left, PM_NIL_NODE) || PM_NODE_TYPE_P(left, PM_INTEGER_NODE)) &&
5855 (right == NULL || PM_NODE_TYPE_P(right, PM_NIL_NODE) || PM_NODE_TYPE_P(right, PM_INTEGER_NODE))
5857 flags |= PM_NODE_FLAG_STATIC_LITERAL;
5860 *node = (pm_range_node_t) {
5861 .base = PM_NODE_INIT(parser, PM_RANGE_NODE, flags, (left == NULL ? operator->start : left->location.start), (right == NULL ? operator->end : right->location.end)),
5864 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5873static pm_redo_node_t *
5874pm_redo_node_create(pm_parser_t *parser, const pm_token_t *token) {
5875 assert(token->type == PM_TOKEN_KEYWORD_REDO);
5876 pm_redo_node_t *node = PM_NODE_ALLOC(parser, pm_redo_node_t);
5878 *node = (pm_redo_node_t) {
5879 .base = PM_NODE_INIT_TOKEN(parser, PM_REDO_NODE, 0, token)
5889static pm_regular_expression_node_t *
5890pm_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) {
5891 pm_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_regular_expression_node_t);
5892 pm_node_flags_t flags = pm_regular_expression_flags_create(parser, closing) | PM_NODE_FLAG_STATIC_LITERAL;
5894 *node = (pm_regular_expression_node_t) {
5895 .base = PM_NODE_INIT_TOKENS(parser, PM_REGULAR_EXPRESSION_NODE, flags, opening, closing),
5896 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5897 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
5898 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
5899 .unescaped = *unescaped
5908static inline pm_regular_expression_node_t *
5909pm_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
5910 return pm_regular_expression_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
5916static pm_required_parameter_node_t *
5917pm_required_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
5918 pm_required_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_parameter_node_t);
5920 *node = (pm_required_parameter_node_t) {
5921 .base = PM_NODE_INIT_TOKEN(parser, PM_REQUIRED_PARAMETER_NODE, 0, token),
5922 .name = pm_parser_constant_id_token(parser, token)
5931static pm_rescue_modifier_node_t *
5932pm_rescue_modifier_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *keyword, pm_node_t *rescue_expression) {
5933 pm_rescue_modifier_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_modifier_node_t);
5935 *node = (pm_rescue_modifier_node_t) {
5936 .base = PM_NODE_INIT_NODES(parser, PM_RESCUE_MODIFIER_NODE, 0, expression, rescue_expression),
5937 .expression = expression,
5938 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
5939 .rescue_expression = rescue_expression
5948static pm_rescue_node_t *
5949pm_rescue_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
5950 pm_rescue_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_node_t);
5952 *node = (pm_rescue_node_t) {
5953 .base = PM_NODE_INIT_TOKEN(parser, PM_RESCUE_NODE, 0, keyword),
5954 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
5955 .operator_loc = { 0 },
5956 .then_keyword_loc = { 0 },
5967pm_rescue_node_operator_set(pm_rescue_node_t *node, const pm_token_t *operator) {
5968 node->operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
5975pm_rescue_node_reference_set(pm_rescue_node_t *node, pm_node_t *reference) {
5976 node->reference = reference;
5977 node->base.location.end = reference->location.end;
5984pm_rescue_node_statements_set(pm_rescue_node_t *node, pm_statements_node_t *statements) {
5985 node->statements = statements;
5986 if (pm_statements_node_body_length(statements) > 0) {
5987 node->base.location.end = statements->base.location.end;
5995pm_rescue_node_subsequent_set(pm_rescue_node_t *node, pm_rescue_node_t *subsequent) {
5996 node->subsequent = subsequent;
5997 node->base.location.end = subsequent->base.location.end;
6004pm_rescue_node_exceptions_append(pm_rescue_node_t *node, pm_node_t *exception) {
6005 pm_node_list_append(&node->exceptions, exception);
6006 node->base.location.end = exception->location.end;
6012static pm_rest_parameter_node_t *
6013pm_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
6014 pm_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_rest_parameter_node_t);
6016 *node = (pm_rest_parameter_node_t) {
6018 (name->type == PM_TOKEN_NOT_PROVIDED)
6019 ? PM_NODE_INIT_TOKEN(parser, PM_REST_PARAMETER_NODE, 0, operator)
6020 : PM_NODE_INIT_TOKENS(parser, PM_REST_PARAMETER_NODE, 0, operator, name)
6022 .name = pm_parser_optional_constant_id_token(parser, name),
6023 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
6024 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6033static pm_retry_node_t *
6034pm_retry_node_create(pm_parser_t *parser, const pm_token_t *token) {
6035 assert(token->type == PM_TOKEN_KEYWORD_RETRY);
6036 pm_retry_node_t *node = PM_NODE_ALLOC(parser, pm_retry_node_t);
6038 *node = (pm_retry_node_t) {
6039 .base = PM_NODE_INIT_TOKEN(parser, PM_RETRY_NODE, 0, token)
6048static pm_return_node_t *
6049pm_return_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6050 pm_return_node_t *node = PM_NODE_ALLOC(parser, pm_return_node_t);
6052 *node = (pm_return_node_t) {
6055 ? PM_NODE_INIT_TOKEN(parser, PM_RETURN_NODE, 0, keyword)
6056 : PM_NODE_INIT_TOKEN_NODE(parser, PM_RETURN_NODE, 0, keyword, arguments)
6058 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6059 .arguments = arguments
6068static pm_self_node_t *
6069pm_self_node_create(pm_parser_t *parser, const pm_token_t *token) {
6070 assert(token->type == PM_TOKEN_KEYWORD_SELF);
6071 pm_self_node_t *node = PM_NODE_ALLOC(parser, pm_self_node_t);
6073 *node = (pm_self_node_t) {
6074 .base = PM_NODE_INIT_TOKEN(parser, PM_SELF_NODE, 0, token)
6083static pm_shareable_constant_node_t *
6084pm_shareable_constant_node_create(pm_parser_t *parser, pm_node_t *write, pm_shareable_constant_value_t value) {
6085 pm_shareable_constant_node_t *node = PM_NODE_ALLOC(parser, pm_shareable_constant_node_t);
6087 *node = (pm_shareable_constant_node_t) {
6088 .base = PM_NODE_INIT_NODE(parser, PM_SHAREABLE_CONSTANT_NODE, (pm_node_flags_t) value, write),
6098static pm_singleton_class_node_t *
6099pm_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) {
6100 pm_singleton_class_node_t *node = PM_NODE_ALLOC(parser, pm_singleton_class_node_t);
6102 *node = (pm_singleton_class_node_t) {
6103 .base = PM_NODE_INIT_TOKENS(parser, PM_SINGLETON_CLASS_NODE, 0, class_keyword, end_keyword),
6105 .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
6106 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6107 .expression = expression,
6109 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
6118static pm_source_encoding_node_t *
6119pm_source_encoding_node_create(pm_parser_t *parser, const pm_token_t *token) {
6120 assert(token->type == PM_TOKEN_KEYWORD___ENCODING__);
6121 pm_source_encoding_node_t *node = PM_NODE_ALLOC(parser, pm_source_encoding_node_t);
6123 *node = (pm_source_encoding_node_t) {
6124 .base = PM_NODE_INIT_TOKEN(parser, PM_SOURCE_ENCODING_NODE, PM_NODE_FLAG_STATIC_LITERAL, token)
6133static pm_source_file_node_t*
6134pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword) {
6135 pm_source_file_node_t *node = PM_NODE_ALLOC(parser, pm_source_file_node_t);
6136 assert(file_keyword->type == PM_TOKEN_KEYWORD___FILE__);
6138 pm_node_flags_t flags = 0;
6140 switch (parser->frozen_string_literal) {
6141 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6142 flags |= PM_STRING_FLAGS_MUTABLE;
6144 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6145 flags |= PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6149 *node = (pm_source_file_node_t) {
6150 .base = PM_NODE_INIT_TOKEN(parser, PM_SOURCE_FILE_NODE, flags, file_keyword),
6151 .filepath = parser->filepath
6160static pm_source_line_node_t *
6161pm_source_line_node_create(pm_parser_t *parser, const pm_token_t *token) {
6162 assert(token->type == PM_TOKEN_KEYWORD___LINE__);
6163 pm_source_line_node_t *node = PM_NODE_ALLOC(parser, pm_source_line_node_t);
6165 *node = (pm_source_line_node_t) {
6166 .base = PM_NODE_INIT_TOKEN(parser, PM_SOURCE_LINE_NODE, PM_NODE_FLAG_STATIC_LITERAL, token)
6175static pm_splat_node_t *
6176pm_splat_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
6177 pm_splat_node_t *node = PM_NODE_ALLOC(parser, pm_splat_node_t);
6179 *node = (pm_splat_node_t) {
6181 (expression == NULL)
6182 ? PM_NODE_INIT_TOKEN(parser, PM_SPLAT_NODE, 0, operator)
6183 : PM_NODE_INIT_TOKEN_NODE(parser, PM_SPLAT_NODE, 0, operator, expression)
6185 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6186 .expression = expression
6195static pm_statements_node_t *
6196pm_statements_node_create(pm_parser_t *parser) {
6197 pm_statements_node_t *node = PM_NODE_ALLOC(parser, pm_statements_node_t);
6199 *node = (pm_statements_node_t) {
6200 .base = PM_NODE_INIT_BASE(parser, PM_STATEMENTS_NODE, 0),
6211pm_statements_node_body_length(pm_statements_node_t *node) {
6212 return node && node->body.size;
6219pm_statements_node_location_set(pm_statements_node_t *node, const uint8_t *start, const uint8_t *end) {
6220 node->base.location = (pm_location_t) { .start = start, .end = end };
6228pm_statements_node_body_update(pm_statements_node_t *node, pm_node_t *statement) {
6229 if (pm_statements_node_body_length(node) == 0 || statement->location.start < node->base.location.start) {
6230 node->base.location.start = statement->location.start;
6233 if (statement->location.end > node->base.location.end) {
6234 node->base.location.end = statement->location.end;
6242pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline) {
6243 pm_statements_node_body_update(node, statement);
6245 if (node->body.size > 0) {
6246 const pm_node_t *previous = node->body.nodes[node->body.size - 1];
6248 switch (PM_NODE_TYPE(previous)) {
6253 case PM_RETURN_NODE:
6254 pm_parser_warn_node(parser, statement, PM_WARN_UNREACHABLE_STATEMENT);
6261 pm_node_list_append(&node->body, statement);
6262 if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
6269pm_statements_node_body_prepend(pm_statements_node_t *node, pm_node_t *statement) {
6270 pm_statements_node_body_update(node, statement);
6271 pm_node_list_prepend(&node->body, statement);
6272 pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
6278static inline pm_string_node_t *
6279pm_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) {
6280 pm_string_node_t *node = PM_NODE_ALLOC(parser, pm_string_node_t);
6281 pm_node_flags_t flags = 0;
6283 switch (parser->frozen_string_literal) {
6284 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6285 flags = PM_STRING_FLAGS_MUTABLE;
6287 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6288 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6292 const uint8_t *start = (opening->type == PM_TOKEN_NOT_PROVIDED ? content->start : opening->start);
6293 const uint8_t *end = (closing->type == PM_TOKEN_NOT_PROVIDED ? content->end : closing->end);
6295 *node = (pm_string_node_t) {
6296 .base = PM_NODE_INIT(parser, PM_STRING_NODE, flags, start, end),
6297 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
6298 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
6299 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
6300 .unescaped = *string
6309static pm_string_node_t *
6310pm_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6311 return pm_string_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6318static pm_string_node_t *
6319pm_string_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6320 pm_string_node_t *node = pm_string_node_create_unescaped(parser, opening, content, closing, &parser->current_string);
6321 parser->current_string = PM_STRING_EMPTY;
6328static pm_super_node_t *
6329pm_super_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_t *arguments) {
6330 assert(keyword->type == PM_TOKEN_KEYWORD_SUPER);
6331 pm_super_node_t *node = PM_NODE_ALLOC(parser, pm_super_node_t);
6333 const uint8_t *end = pm_arguments_end(arguments);
6335 assert(false && "unreachable");
6338 *node = (pm_super_node_t) {
6339 .base = PM_NODE_INIT(parser, PM_SUPER_NODE, 0, keyword->start, end),
6340 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6341 .lparen_loc = arguments->opening_loc,
6342 .arguments = arguments->arguments,
6343 .rparen_loc = arguments->closing_loc,
6344 .block = arguments->block
6355pm_ascii_only_p(const pm_string_t *contents) {
6356 const size_t length = pm_string_length(contents);
6357 const uint8_t *source = pm_string_source(contents);
6359 for (size_t index = 0; index < length; index++) {
6360 if (source[index] & 0x80) return false;
6370parse_symbol_encoding_validate_utf8(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
6371 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
6372 size_t width = pm_encoding_utf_8_char_width(cursor, end - cursor);
6375 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
6388parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
6389 const pm_encoding_t *encoding = parser->encoding;
6391 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
6392 size_t width = encoding->char_width(cursor, end - cursor);
6395 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
6412static inline pm_node_flags_t
6413parse_symbol_encoding(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents, bool validate) {
6414 if (parser->explicit_encoding != NULL) {
6415 // A Symbol may optionally have its encoding explicitly set. This will
6416 // happen if an escape sequence results in a non-ASCII code point.
6417 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
6418 if (validate) parse_symbol_encoding_validate_utf8(parser, location, contents);
6419 return PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING;
6420 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
6421 return PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING;
6422 } else if (validate) {
6423 parse_symbol_encoding_validate_other(parser, location, contents);
6425 } else if (pm_ascii_only_p(contents)) {
6426 // Ruby stipulates that all source files must use an ASCII-compatible
6427 // encoding. Thus, all symbols appearing in source are eligible for
6428 // "downgrading" to US-ASCII.
6429 return PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING;
6430 } else if (validate) {
6431 parse_symbol_encoding_validate_other(parser, location, contents);
6437static pm_node_flags_t
6438parse_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) {
6439 assert ((modifier == 'n' && modifier_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) ||
6440 (modifier == 'u' && modifier_encoding == PM_ENCODING_UTF_8_ENTRY) ||
6441 (modifier == 'e' && modifier_encoding == PM_ENCODING_EUC_JP_ENTRY) ||
6442 (modifier == 's' && modifier_encoding == PM_ENCODING_WINDOWS_31J_ENTRY));
6444 // There's special validation logic used if a string does not contain any character escape sequences.
6445 if (parser->explicit_encoding == NULL) {
6446 // If an ASCII-only string without character escapes is used with an encoding modifier, then resulting Regexp
6447 // has the modifier encoding, unless the ASCII-8BIT modifier is used, in which case the Regexp "downgrades" to
6448 // the US-ASCII encoding.
6450 return modifier == 'n' ? PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING : flags;
6453 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
6455 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
6457 } else if (parser->encoding != modifier_encoding) {
6458 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_ENCODING_OPTION_MISMATCH, modifier, parser->encoding->name);
6460 if (modifier == 'n' && !ascii_only) {
6461 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));
6468 // 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.
6469 bool mixed_encoding = false;
6471 if (mixed_encoding) {
6472 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
6473 } else if (modifier != 'n' && parser->explicit_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) {
6474 // 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.
6475 bool valid_string_in_modifier_encoding = true;
6477 if (!valid_string_in_modifier_encoding) {
6478 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
6480 } else if (modifier != 'u' && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
6481 // 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.
6482 if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
6483 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));
6487 // We've determined the encoding would naturally be EUC-JP and there is no need to force the encoding to anything else.
6497static pm_node_flags_t
6498parse_and_validate_regular_expression_encoding(pm_parser_t *parser, const pm_string_t *source, bool ascii_only, pm_node_flags_t flags) {
6499 // 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.
6500 bool valid_unicode_range = true;
6501 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY && !valid_unicode_range) {
6502 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));
6506 // US-ASCII strings do not admit multi-byte character literals. However, character escape sequences corresponding
6507 // to multi-byte characters are allowed.
6508 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY && parser->explicit_encoding == NULL && !ascii_only) {
6509 // CRuby will continue processing even though a SyntaxError has already been detected. It may result in the
6510 // following error message appearing twice. We do the same for compatibility.
6511 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
6522 if (flags & PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT) {
6523 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'n', PM_ENCODING_ASCII_8BIT_ENTRY);
6526 if (flags & PM_REGULAR_EXPRESSION_FLAGS_UTF_8) {
6527 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'u', PM_ENCODING_UTF_8_ENTRY);
6530 if (flags & PM_REGULAR_EXPRESSION_FLAGS_EUC_JP) {
6531 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'e', PM_ENCODING_EUC_JP_ENTRY);
6534 if (flags & PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J) {
6535 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 's', PM_ENCODING_WINDOWS_31J_ENTRY);
6538 // At this point no encoding modifiers will be present on the regular expression as they would have already
6539 // been processed. Ruby stipulates that all source files must use an ASCII-compatible encoding. Thus, all
6540 // regular expressions without an encoding modifier appearing in source are eligible for "downgrading" to US-ASCII.
6542 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING;
6545 // A Regexp may optionally have its encoding explicitly set via a character escape sequence in the source string
6546 // or by specifying a modifier.
6548 // NB: an explicitly set encoding is ignored by Ruby if the Regexp consists of only US ASCII code points.
6549 if (parser->explicit_encoding != NULL) {
6550 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
6551 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING;
6552 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
6553 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING;
6564static pm_symbol_node_t *
6565pm_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) {
6566 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
6568 const uint8_t *start = (opening->type == PM_TOKEN_NOT_PROVIDED ? value->start : opening->start);
6569 const uint8_t *end = (closing->type == PM_TOKEN_NOT_PROVIDED ? value->end : closing->end);
6571 *node = (pm_symbol_node_t) {
6572 .base = PM_NODE_INIT(parser, PM_SYMBOL_NODE, PM_NODE_FLAG_STATIC_LITERAL | flags, start, end),
6573 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
6574 .value_loc = PM_LOCATION_TOKEN_VALUE(value),
6575 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
6576 .unescaped = *unescaped
6585static inline pm_symbol_node_t *
6586pm_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
6587 return pm_symbol_node_create_unescaped(parser, opening, value, closing, &PM_STRING_EMPTY, 0);
6593static pm_symbol_node_t *
6594pm_symbol_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
6595 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));
6596 parser->current_string = PM_STRING_EMPTY;
6603static pm_symbol_node_t *
6604pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
6605 pm_symbol_node_t *node;
6607 switch (token->type) {
6608 case PM_TOKEN_LABEL: {
6609 pm_token_t opening = not_provided(parser);
6610 pm_token_t closing = { .type = PM_TOKEN_LABEL_END, .start = token->end - 1, .end = token->end };
6612 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end - 1 };
6613 node = pm_symbol_node_create(parser, &opening, &label, &closing);
6615 assert((label.end - label.start) >= 0);
6616 pm_string_shared_init(&node->unescaped, label.start, label.end);
6617 pm_node_flag_set(UP(node), parse_symbol_encoding(parser, &label, &node->unescaped, false));
6621 case PM_TOKEN_MISSING: {
6622 pm_token_t opening = not_provided(parser);
6623 pm_token_t closing = not_provided(parser);
6625 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end };
6626 node = pm_symbol_node_create(parser, &opening, &label, &closing);
6630 assert(false && "unreachable");
6641static pm_symbol_node_t *
6642pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
6643 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
6645 *node = (pm_symbol_node_t) {
6646 .base = PM_NODE_INIT_BASE(parser, PM_SYMBOL_NODE, PM_NODE_FLAG_STATIC_LITERAL | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING),
6647 .value_loc = PM_LOCATION_NULL_VALUE(parser),
6651 pm_string_constant_init(&node->unescaped, content, strlen(content));
6659pm_symbol_node_label_p(pm_node_t *node) {
6660 const uint8_t *end = NULL;
6662 switch (PM_NODE_TYPE(node)) {
6663 case PM_SYMBOL_NODE:
6664 end = ((pm_symbol_node_t *) node)->closing_loc.end;
6666 case PM_INTERPOLATED_SYMBOL_NODE:
6667 end = ((pm_interpolated_symbol_node_t *) node)->closing_loc.end;
6673 return (end != NULL) && (end[-1] == ':');
6679static pm_symbol_node_t *
6680pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const pm_token_t *opening, const pm_token_t *closing) {
6681 pm_symbol_node_t *new_node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
6683 *new_node = (pm_symbol_node_t) {
6684 .base = PM_NODE_INIT_TOKENS(parser, PM_SYMBOL_NODE, PM_NODE_FLAG_STATIC_LITERAL, opening, closing),
6685 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
6686 .value_loc = node->content_loc,
6687 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
6688 .unescaped = node->unescaped
6691 pm_token_t content = { .type = PM_TOKEN_IDENTIFIER, .start = node->content_loc.start, .end = node->content_loc.end };
6692 pm_node_flag_set(UP(new_node), parse_symbol_encoding(parser, &content, &node->unescaped, true));
6694 // We are explicitly _not_ using pm_node_destroy here because we don't want
6695 // to trash the unescaped string. We could instead copy the string if we
6696 // know that it is owned, but we're taking the fast path for now.
6705static pm_string_node_t *
6706pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
6707 pm_string_node_t *new_node = PM_NODE_ALLOC(parser, pm_string_node_t);
6708 pm_node_flags_t flags = 0;
6710 switch (parser->frozen_string_literal) {
6711 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6712 flags = PM_STRING_FLAGS_MUTABLE;
6714 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6715 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6719 *new_node = (pm_string_node_t) {
6720 .base = PM_NODE_INIT_NODE(parser, PM_STRING_NODE, flags, node),
6721 .opening_loc = node->opening_loc,
6722 .content_loc = node->value_loc,
6723 .closing_loc = node->closing_loc,
6724 .unescaped = node->unescaped
6727 // We are explicitly _not_ using pm_node_destroy here because we don't want
6728 // to trash the unescaped string. We could instead copy the string if we
6729 // know that it is owned, but we're taking the fast path for now.
6738static pm_true_node_t *
6739pm_true_node_create(pm_parser_t *parser, const pm_token_t *token) {
6740 assert(token->type == PM_TOKEN_KEYWORD_TRUE);
6741 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
6743 *node = (pm_true_node_t) {
6744 .base = PM_NODE_INIT_TOKEN(parser, PM_TRUE_NODE, PM_NODE_FLAG_STATIC_LITERAL, token)
6753static pm_true_node_t *
6754pm_true_node_synthesized_create(pm_parser_t *parser) {
6755 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
6757 *node = (pm_true_node_t) {
6758 .base = PM_NODE_INIT_BASE(parser, PM_TRUE_NODE, PM_NODE_FLAG_STATIC_LITERAL)
6767static pm_undef_node_t *
6768pm_undef_node_create(pm_parser_t *parser, const pm_token_t *token) {
6769 assert(token->type == PM_TOKEN_KEYWORD_UNDEF);
6770 pm_undef_node_t *node = PM_NODE_ALLOC(parser, pm_undef_node_t);
6772 *node = (pm_undef_node_t) {
6773 .base = PM_NODE_INIT_TOKEN(parser, PM_UNDEF_NODE, 0, token),
6774 .keyword_loc = PM_LOCATION_TOKEN_VALUE(token),
6785pm_undef_node_append(pm_undef_node_t *node, pm_node_t *name) {
6786 node->base.location.end = name->location.end;
6787 pm_node_list_append(&node->names, name);
6793static pm_unless_node_t *
6794pm_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) {
6795 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6797 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
6798 pm_node_t *end = statements == NULL ? predicate : UP(statements);
6800 *node = (pm_unless_node_t) {
6801 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_UNLESS_NODE, PM_NODE_FLAG_NEWLINE, keyword, end),
6802 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6803 .predicate = predicate,
6804 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
6805 .statements = statements,
6806 .else_clause = NULL,
6807 .end_keyword_loc = { 0 }
6816static pm_unless_node_t *
6817pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *unless_keyword, pm_node_t *predicate) {
6818 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6819 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
6821 pm_statements_node_t *statements = pm_statements_node_create(parser);
6822 pm_statements_node_body_append(parser, statements, statement, true);
6824 *node = (pm_unless_node_t) {
6825 .base = PM_NODE_INIT_NODES(parser, PM_UNLESS_NODE, PM_NODE_FLAG_NEWLINE, statement, predicate),
6826 .keyword_loc = PM_LOCATION_TOKEN_VALUE(unless_keyword),
6827 .predicate = predicate,
6828 .then_keyword_loc = { 0 },
6829 .statements = statements,
6830 .else_clause = NULL,
6831 .end_keyword_loc = { 0 }
6838pm_unless_node_end_keyword_loc_set(pm_unless_node_t *node, const pm_token_t *end_keyword) {
6839 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
6840 node->base.location.end = end_keyword->end;
6849pm_loop_modifier_block_exits(pm_parser_t *parser, pm_statements_node_t *statements) {
6850 assert(parser->current_block_exits != NULL);
6852 // All of the block exits that we want to remove should be within the
6853 // statements, and since we are modifying the statements, we shouldn't have
6854 // to check the end location.
6855 const uint8_t *start = statements->base.location.start;
6857 for (size_t index = parser->current_block_exits->size; index > 0; index--) {
6858 pm_node_t *block_exit = parser->current_block_exits->nodes[index - 1];
6859 if (block_exit->location.start < start) break;
6861 // Implicitly remove from the list by lowering the size.
6862 parser->current_block_exits->size--;
6869static pm_until_node_t *
6870pm_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) {
6871 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
6872 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6874 *node = (pm_until_node_t) {
6875 .base = PM_NODE_INIT_TOKENS(parser, PM_UNTIL_NODE, flags, keyword, closing),
6876 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6877 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
6878 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
6879 .predicate = predicate,
6880 .statements = statements
6889static pm_until_node_t *
6890pm_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) {
6891 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
6892 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6893 pm_loop_modifier_block_exits(parser, statements);
6895 *node = (pm_until_node_t) {
6896 .base = PM_NODE_INIT_NODES(parser, PM_UNTIL_NODE, flags, statements, predicate),
6897 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6898 .do_keyword_loc = { 0 },
6899 .closing_loc = { 0 },
6900 .predicate = predicate,
6901 .statements = statements
6910static pm_when_node_t *
6911pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
6912 pm_when_node_t *node = PM_NODE_ALLOC(parser, pm_when_node_t);
6914 *node = (pm_when_node_t) {
6915 .base = PM_NODE_INIT_TOKEN(parser, PM_WHEN_NODE, 0, keyword),
6916 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6918 .then_keyword_loc = { 0 },
6929pm_when_node_conditions_append(pm_when_node_t *node, pm_node_t *condition) {
6930 node->base.location.end = condition->location.end;
6931 pm_node_list_append(&node->conditions, condition);
6938pm_when_node_then_keyword_loc_set(pm_when_node_t *node, const pm_token_t *then_keyword) {
6939 node->base.location.end = then_keyword->end;
6940 node->then_keyword_loc = PM_LOCATION_TOKEN_VALUE(then_keyword);
6947pm_when_node_statements_set(pm_when_node_t *node, pm_statements_node_t *statements) {
6948 if (statements->base.location.end > node->base.location.end) {
6949 node->base.location.end = statements->base.location.end;
6952 node->statements = statements;
6958static pm_while_node_t *
6959pm_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) {
6960 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
6961 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6963 *node = (pm_while_node_t) {
6964 .base = PM_NODE_INIT_TOKENS(parser, PM_WHILE_NODE, flags, keyword, closing),
6965 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6966 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
6967 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
6968 .predicate = predicate,
6969 .statements = statements
6978static pm_while_node_t *
6979pm_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) {
6980 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
6981 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6982 pm_loop_modifier_block_exits(parser, statements);
6984 *node = (pm_while_node_t) {
6985 .base = PM_NODE_INIT_NODES(parser, PM_WHILE_NODE, flags, statements, predicate),
6986 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6987 .do_keyword_loc = { 0 },
6988 .closing_loc = { 0 },
6989 .predicate = predicate,
6990 .statements = statements
6999static pm_while_node_t *
7000pm_while_node_synthesized_create(pm_parser_t *parser, pm_node_t *predicate, pm_statements_node_t *statements) {
7001 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7003 *node = (pm_while_node_t) {
7004 .base = PM_NODE_INIT_BASE(parser, PM_WHILE_NODE, 0),
7005 .keyword_loc = PM_LOCATION_NULL_VALUE(parser),
7006 .do_keyword_loc = PM_LOCATION_NULL_VALUE(parser),
7007 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
7008 .predicate = predicate,
7009 .statements = statements
7019static pm_x_string_node_t *
7020pm_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) {
7021 pm_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_x_string_node_t);
7023 *node = (pm_x_string_node_t) {
7024 .base = PM_NODE_INIT_TOKENS(parser, PM_X_STRING_NODE, PM_STRING_FLAGS_FROZEN, opening, closing),
7025 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
7026 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
7027 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
7028 .unescaped = *unescaped
7037static inline pm_x_string_node_t *
7038pm_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7039 return pm_xstring_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7045static pm_yield_node_t *
7046pm_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) {
7047 pm_yield_node_t *node = PM_NODE_ALLOC(parser, pm_yield_node_t);
7050 if (rparen_loc->start != NULL) {
7051 end = rparen_loc->end;
7052 } else if (arguments != NULL) {
7053 end = arguments->base.location.end;
7054 } else if (lparen_loc->start != NULL) {
7055 end = lparen_loc->end;
7060 *node = (pm_yield_node_t) {
7061 .base = PM_NODE_INIT(parser, PM_YIELD_NODE, 0, keyword->start, end),
7062 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7063 .lparen_loc = *lparen_loc,
7064 .arguments = arguments,
7065 .rparen_loc = *rparen_loc
7076pm_parser_local_depth_constant_id(pm_parser_t *parser, pm_constant_id_t constant_id) {
7077 pm_scope_t *scope = parser->current_scope;
7080 while (scope != NULL) {
7081 if (pm_locals_find(&scope->locals, constant_id) != UINT32_MAX) return depth;
7082 if (scope->closed) break;
7084 scope = scope->previous;
7097pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
7098 return pm_parser_local_depth_constant_id(parser, pm_parser_constant_id_token(parser, token));
7105pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7106 pm_locals_write(&parser->current_scope->locals, constant_id, start, end, reads);
7112static pm_constant_id_t
7113pm_parser_local_add_location(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7114 pm_constant_id_t constant_id = pm_parser_constant_id_location(parser, start, end);
7115 if (constant_id != 0) pm_parser_local_add(parser, constant_id, start, end, reads);
7122static inline pm_constant_id_t
7123pm_parser_local_add_token(pm_parser_t *parser, pm_token_t *token, uint32_t reads) {
7124 return pm_parser_local_add_location(parser, token->start, token->end, reads);
7130static pm_constant_id_t
7131pm_parser_local_add_owned(pm_parser_t *parser, uint8_t *start, size_t length) {
7132 pm_constant_id_t constant_id = pm_parser_constant_id_owned(parser, start, length);
7133 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
7140static pm_constant_id_t
7141pm_parser_local_add_constant(pm_parser_t *parser, const char *start, size_t length) {
7142 pm_constant_id_t constant_id = pm_parser_constant_id_constant(parser, start, length);
7143 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
7155pm_parser_parameter_name_check(pm_parser_t *parser, const pm_token_t *name) {
7156 // We want to check whether the parameter name is a numbered parameter or
7158 pm_refute_numbered_parameter(parser, name->start, name->end);
7160 // Otherwise we'll fetch the constant id for the parameter name and check
7161 // whether it's already in the current scope.
7162 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, name);
7164 if (pm_locals_find(&parser->current_scope->locals, constant_id) != UINT32_MAX) {
7165 // Add an error if the parameter doesn't start with _ and has been seen before
7166 if ((name->start < name->end) && (*name->start != '_')) {
7167 pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NAME_DUPLICATED);
7178pm_parser_scope_pop(pm_parser_t *parser) {
7179 pm_scope_t *scope = parser->current_scope;
7180 parser->current_scope = scope->previous;
7181 pm_locals_free(&scope->locals);
7182 pm_node_list_free(&scope->implicit_parameters);
7186/******************************************************************************/
7188/******************************************************************************/
7194pm_state_stack_push(pm_state_stack_t *stack, bool value) {
7195 *stack = (*stack << 1) | (value & 1);
7202pm_state_stack_pop(pm_state_stack_t *stack) {
7210pm_state_stack_p(const pm_state_stack_t *stack) {
7215pm_accepts_block_stack_push(pm_parser_t *parser, bool value) {
7216 // Use the negation of the value to prevent stack overflow.
7217 pm_state_stack_push(&parser->accepts_block_stack, !value);
7221pm_accepts_block_stack_pop(pm_parser_t *parser) {
7222 pm_state_stack_pop(&parser->accepts_block_stack);
7226pm_accepts_block_stack_p(pm_parser_t *parser) {
7227 return !pm_state_stack_p(&parser->accepts_block_stack);
7231pm_do_loop_stack_push(pm_parser_t *parser, bool value) {
7232 pm_state_stack_push(&parser->do_loop_stack, value);
7236pm_do_loop_stack_pop(pm_parser_t *parser) {
7237 pm_state_stack_pop(&parser->do_loop_stack);
7241pm_do_loop_stack_p(pm_parser_t *parser) {
7242 return pm_state_stack_p(&parser->do_loop_stack);
7245/******************************************************************************/
7246/* Lexer check helpers */
7247/******************************************************************************/
7253static inline uint8_t
7254peek_at(const pm_parser_t *parser, const uint8_t *cursor) {
7255 if (cursor < parser->end) {
7267static inline uint8_t
7268peek_offset(pm_parser_t *parser, ptrdiff_t offset) {
7269 return peek_at(parser, parser->current.end + offset);
7276static inline uint8_t
7277peek(const pm_parser_t *parser) {
7278 return peek_at(parser, parser->current.end);
7286match(pm_parser_t *parser, uint8_t value) {
7287 if (peek(parser) == value) {
7288 parser->current.end++;
7299match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
7300 if (peek_at(parser, cursor) == '\n') {
7303 if (peek_at(parser, cursor) == '\r' && peek_at(parser, cursor + 1) == '\n') {
7315match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
7316 return match_eol_at(parser, parser->current.end + offset);
7325match_eol(pm_parser_t *parser) {
7326 return match_eol_at(parser, parser->current.end);
7332static inline const uint8_t *
7333next_newline(const uint8_t *cursor, ptrdiff_t length) {
7334 assert(length >= 0);
7336 // Note that it's okay for us to use memchr here to look for \n because none
7337 // of the encodings that we support have \n as a component of a multi-byte
7339 return memchr(cursor, '\n', (size_t) length);
7346ambiguous_operator_p(const pm_parser_t *parser, bool space_seen) {
7347 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));
7355parser_lex_magic_comment_encoding_value(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
7356 const pm_encoding_t *encoding = pm_encoding_find(start, end);
7358 if (encoding != NULL) {
7359 if (parser->encoding != encoding) {
7360 parser->encoding = encoding;
7361 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
7364 parser->encoding_changed = (encoding != PM_ENCODING_UTF_8_ENTRY);
7376parser_lex_magic_comment_encoding(pm_parser_t *parser) {
7377 const uint8_t *cursor = parser->current.start + 1;
7378 const uint8_t *end = parser->current.end;
7380 bool separator = false;
7382 if (end - cursor <= 6) return;
7383 switch (cursor[6]) {
7384 case 'C': case 'c': cursor += 6; continue;
7385 case 'O': case 'o': cursor += 5; continue;
7386 case 'D': case 'd': cursor += 4; continue;
7387 case 'I': case 'i': cursor += 3; continue;
7388 case 'N': case 'n': cursor += 2; continue;
7389 case 'G': case 'g': cursor += 1; continue;
7396 if (pm_char_is_whitespace(*cursor)) break;
7399 if (pm_strncasecmp(cursor - 6, (const uint8_t *) "coding", 6) == 0) break;
7405 if (++cursor >= end) return;
7406 } while (pm_char_is_whitespace(*cursor));
7408 if (separator) break;
7409 if (*cursor != '=' && *cursor != ':') return;
7415 const uint8_t *value_start = cursor;
7416 while ((*cursor == '-' || *cursor == '_' || parser->encoding->alnum_char(cursor, 1)) && ++cursor < end);
7418 if (!parser_lex_magic_comment_encoding_value(parser, value_start, cursor)) {
7419 // If we were unable to parse the encoding value, then we've got an
7420 // issue because we didn't understand the encoding that the user was
7421 // trying to use. In this case we'll keep using the default encoding but
7422 // add an error to the parser to indicate an unsuccessful parse.
7423 pm_parser_err(parser, value_start, cursor, PM_ERR_INVALID_ENCODING_MAGIC_COMMENT);
7428 PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE,
7429 PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE,
7430 PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID
7431} pm_magic_comment_boolean_value_t;
7437static pm_magic_comment_boolean_value_t
7438parser_lex_magic_comment_boolean_value(const uint8_t *value_start, uint32_t value_length) {
7439 if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "true", 4) == 0) {
7440 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE;
7441 } else if (value_length == 5 && pm_strncasecmp(value_start, (const uint8_t *) "false", 5) == 0) {
7442 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE;
7444 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID;
7449pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
7450 return b == '\'' || b == '"' || b == ':' || b == ';';
7458static inline const uint8_t *
7459parser_lex_magic_comment_emacs_marker(
pm_parser_t *parser,
const uint8_t *cursor,
const uint8_t *end) {
7460 while ((cursor + 3 <= end) && (cursor = pm_memchr(cursor,
'-', (
size_t) (end - cursor), parser->
encoding_changed, parser->
encoding)) != NULL) {
7461 if (cursor + 3 <= end && cursor[1] ==
'*' && cursor[2] ==
'-') {
7480parser_lex_magic_comment(
pm_parser_t *parser,
bool semantic_token_seen) {
7483 const uint8_t *start = parser->
current.start + 1;
7484 const uint8_t *end = parser->
current.end;
7485 if (end - start <= 7)
return false;
7487 const uint8_t *cursor;
7488 bool indicator =
false;
7490 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
7493 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
7504 while (cursor < end) {
7505 while (cursor < end && (pm_char_is_magic_comment_key_delimiter(*cursor) || pm_char_is_whitespace(*cursor))) cursor++;
7507 const uint8_t *key_start = cursor;
7508 while (cursor < end && (!pm_char_is_magic_comment_key_delimiter(*cursor) && !pm_char_is_whitespace(*cursor))) cursor++;
7510 const uint8_t *key_end = cursor;
7511 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7512 if (cursor == end)
break;
7514 if (*cursor ==
':') {
7517 if (!indicator)
return false;
7521 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7522 if (cursor == end)
break;
7524 const uint8_t *value_start;
7525 const uint8_t *value_end;
7527 if (*cursor ==
'"') {
7528 value_start = ++cursor;
7529 for (; cursor < end && *cursor !=
'"'; cursor++) {
7530 if (*cursor ==
'\\' && (cursor + 1 < end)) cursor++;
7533 if (cursor < end && *cursor ==
'"') cursor++;
7535 value_start = cursor;
7536 while (cursor < end && *cursor !=
'"' && *cursor !=
';' && !pm_char_is_whitespace(*cursor)) cursor++;
7541 while (cursor < end && (*cursor ==
';' || pm_char_is_whitespace(*cursor))) cursor++;
7543 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7544 if (cursor != end)
return false;
7550 const size_t key_length = (size_t) (key_end - key_start);
7554 pm_string_shared_init(&key, key_start, key_end);
7556 uint8_t *buffer =
xmalloc(key_length);
7557 if (buffer == NULL)
break;
7559 memcpy(buffer, key_start, key_length);
7560 buffer[dash - key_start] =
'_';
7562 while ((dash = pm_memchr(dash + 1,
'-', (
size_t) (key_end - dash - 1), parser->
encoding_changed, parser->
encoding)) != NULL) {
7563 buffer[dash - key_start] =
'_';
7566 pm_string_owned_init(&key, buffer, key_length);
7572 uint32_t value_length = (uint32_t) (value_end - value_start);
7578 (key_length == 8 && pm_strncasecmp(key_source, (
const uint8_t *)
"encoding", 8) == 0) ||
7579 (key_length == 6 && pm_strncasecmp(key_source, (
const uint8_t *)
"coding", 6) == 0)
7581 result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
7585 if (key_length == 11) {
7586 if (pm_strncasecmp(key_source, (
const uint8_t *)
"warn_indent", 11) == 0) {
7587 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7588 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7589 PM_PARSER_WARN_TOKEN_FORMAT(
7592 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7594 (
const char *) key_source,
7596 (
const char *) value_start
7599 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7602 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7607 }
else if (key_length == 21) {
7608 if (pm_strncasecmp(key_source, (
const uint8_t *)
"frozen_string_literal", 21) == 0) {
7611 if (semantic_token_seen) {
7612 pm_parser_warn_token(parser, &parser->
current, PM_WARN_IGNORED_FROZEN_STRING_LITERAL);
7614 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7615 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7616 PM_PARSER_WARN_TOKEN_FORMAT(
7619 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7621 (
const char *) key_source,
7623 (
const char *) value_start
7626 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7629 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7635 }
else if (key_length == 24) {
7636 if (pm_strncasecmp(key_source, (
const uint8_t *)
"shareable_constant_value", 24) == 0) {
7637 const uint8_t *cursor = parser->
current.start;
7638 while ((cursor > parser->
start) && ((cursor[-1] ==
' ') || (cursor[-1] ==
'\t'))) cursor--;
7640 if (!((cursor == parser->
start) || (cursor[-1] ==
'\n'))) {
7641 pm_parser_warn_token(parser, &parser->
current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
7642 }
else if (value_length == 4 && pm_strncasecmp(value_start, (
const uint8_t *)
"none", 4) == 0) {
7643 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
7644 }
else if (value_length == 7 && pm_strncasecmp(value_start, (
const uint8_t *)
"literal", 7) == 0) {
7645 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
7646 }
else if (value_length == 23 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_everything", 23) == 0) {
7647 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING);
7648 }
else if (value_length == 17 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_copy", 17) == 0) {
7649 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY);
7651 PM_PARSER_WARN_TOKEN_FORMAT(
7654 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7656 (
const char *) key_source,
7658 (
const char *) value_start
7686static const uint32_t context_terminators[] = {
7688 [
PM_CONTEXT_BEGIN] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7691 [
PM_CONTEXT_BEGIN_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7693 [
PM_CONTEXT_BLOCK_KEYWORDS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7697 [
PM_CONTEXT_BLOCK_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7698 [
PM_CONTEXT_CASE_WHEN] = (1U << PM_TOKEN_KEYWORD_WHEN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
7699 [
PM_CONTEXT_CASE_IN] = (1U << PM_TOKEN_KEYWORD_IN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
7700 [
PM_CONTEXT_CLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7703 [
PM_CONTEXT_CLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7704 [
PM_CONTEXT_DEF] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7707 [
PM_CONTEXT_DEF_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7712 [
PM_CONTEXT_ELSIF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
7716 [
PM_CONTEXT_IF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
7718 [
PM_CONTEXT_LAMBDA_DO_END] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7721 [
PM_CONTEXT_LAMBDA_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7724 [
PM_CONTEXT_MODULE] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7727 [
PM_CONTEXT_MODULE_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7731 [
PM_CONTEXT_PREDICATE] = (1U << PM_TOKEN_KEYWORD_THEN) | (1U << PM_TOKEN_NEWLINE) | (1U << PM_TOKEN_SEMICOLON),
7734 [
PM_CONTEXT_SCLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7737 [
PM_CONTEXT_SCLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7739 [
PM_CONTEXT_UNLESS] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7746 return token->type < 32 && (context_terminators[context] & (1U << token->type));
7757 while (context_node != NULL) {
7758 if (context_terminator(context_node->
context, token))
return context_node->
context;
7759 context_node = context_node->
prev;
7768 if (context_node == NULL)
return false;
7793 while (context_node != NULL) {
7794 if (context_node->
context == context)
return true;
7795 context_node = context_node->
prev;
7805 while (context_node != NULL) {
7806 switch (context_node->
context) {
7827 context_node = context_node->
prev;
7842 assert(
false &&
"unreachable");
7900 assert(
false &&
"unreachable");
7909pm_strspn_number_validate(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const uint8_t *invalid) {
7910 if (invalid != NULL) {
7911 pm_diagnostic_id_t diag_id = (invalid == (
string + length - 1)) ? PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING : PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER;
7912 pm_parser_err(parser, invalid, invalid + 1, diag_id);
7917pm_strspn_binary_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
7918 const uint8_t *invalid = NULL;
7919 size_t length = pm_strspn_binary_number(
string, parser->
end -
string, &invalid);
7920 pm_strspn_number_validate(parser,
string, length, invalid);
7925pm_strspn_octal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
7926 const uint8_t *invalid = NULL;
7927 size_t length = pm_strspn_octal_number(
string, parser->
end -
string, &invalid);
7928 pm_strspn_number_validate(parser,
string, length, invalid);
7933pm_strspn_decimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
7934 const uint8_t *invalid = NULL;
7935 size_t length = pm_strspn_decimal_number(
string, parser->
end -
string, &invalid);
7936 pm_strspn_number_validate(parser,
string, length, invalid);
7941pm_strspn_hexadecimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
7942 const uint8_t *invalid = NULL;
7943 size_t length = pm_strspn_hexadecimal_number(
string, parser->
end -
string, &invalid);
7944 pm_strspn_number_validate(parser,
string, length, invalid);
7948static pm_token_type_t
7949lex_optional_float_suffix(
pm_parser_t *parser,
bool* seen_e) {
7950 pm_token_type_t
type = PM_TOKEN_INTEGER;
7954 if (peek(parser) ==
'.') {
7955 if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
7957 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
7958 type = PM_TOKEN_FLOAT;
7968 if ((peek(parser) ==
'e') || (peek(parser) ==
'E')) {
7969 if ((peek_offset(parser, 1) ==
'+') || (peek_offset(parser, 1) ==
'-')) {
7972 if (pm_char_is_decimal_digit(peek(parser))) {
7974 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
7976 pm_parser_err_current(parser, PM_ERR_INVALID_FLOAT_EXPONENT);
7978 }
else if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
7980 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
7986 type = PM_TOKEN_FLOAT;
7992static pm_token_type_t
7993lex_numeric_prefix(
pm_parser_t *parser,
bool* seen_e) {
7994 pm_token_type_t
type = PM_TOKEN_INTEGER;
7997 if (peek_offset(parser, -1) ==
'0') {
7998 switch (*parser->
current.end) {
8003 if (pm_char_is_decimal_digit(peek(parser))) {
8004 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8007 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_DECIMAL);
8016 if (pm_char_is_binary_digit(peek(parser))) {
8017 parser->
current.end += pm_strspn_binary_number_validate(parser, parser->
current.end);
8020 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
8030 if (pm_char_is_octal_digit(peek(parser))) {
8031 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8034 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
8050 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8058 if (pm_char_is_hexadecimal_digit(peek(parser))) {
8059 parser->
current.end += pm_strspn_hexadecimal_number_validate(parser, parser->
current.end);
8062 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
8065 parser->
integer_base = PM_INTEGER_BASE_FLAGS_HEXADECIMAL;
8070 type = lex_optional_float_suffix(parser, seen_e);
8077 type = lex_optional_float_suffix(parser, seen_e);
8084 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8087 type = lex_optional_float_suffix(parser, seen_e);
8093 if (peek_offset(parser, 0) ==
'.' && pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8094 const uint8_t *fraction_start = parser->
current.end;
8095 const uint8_t *fraction_end = parser->
current.end + 2;
8096 fraction_end += pm_strspn_decimal_digit(fraction_end, parser->
end - fraction_end);
8097 pm_parser_err(parser, fraction_start, fraction_end, PM_ERR_INVALID_NUMBER_FRACTION);
8103static pm_token_type_t
8105 pm_token_type_t
type = PM_TOKEN_INTEGER;
8109 bool seen_e =
false;
8110 type = lex_numeric_prefix(parser, &seen_e);
8112 const uint8_t *end = parser->
current.end;
8113 pm_token_type_t suffix_type =
type;
8115 if (
type == PM_TOKEN_INTEGER) {
8116 if (match(parser,
'r')) {
8117 suffix_type = PM_TOKEN_INTEGER_RATIONAL;
8119 if (match(parser,
'i')) {
8120 suffix_type = PM_TOKEN_INTEGER_RATIONAL_IMAGINARY;
8122 }
else if (match(parser,
'i')) {
8123 suffix_type = PM_TOKEN_INTEGER_IMAGINARY;
8126 if (!seen_e && match(parser,
'r')) {
8127 suffix_type = PM_TOKEN_FLOAT_RATIONAL;
8129 if (match(parser,
'i')) {
8130 suffix_type = PM_TOKEN_FLOAT_RATIONAL_IMAGINARY;
8132 }
else if (match(parser,
'i')) {
8133 suffix_type = PM_TOKEN_FLOAT_IMAGINARY;
8137 const uint8_t b = peek(parser);
8138 if (b !=
'\0' && (b >= 0x80 || ((b >=
'a' && b <=
'z') || (b >=
'A' && b <=
'Z')) || b ==
'_')) {
8148static pm_token_type_t
8151 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
8152 return PM_TOKEN_GLOBAL_VARIABLE;
8157 bool allow_multiple =
true;
8159 switch (*parser->
current.end) {
8177 return PM_TOKEN_GLOBAL_VARIABLE;
8184 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_BACK_REFERENCE;
8190 if ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0) {
8193 }
while ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0);
8197 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
current, diag_id);
8200 return PM_TOKEN_GLOBAL_VARIABLE;
8213 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_NUMBERED_REFERENCE;
8217 allow_multiple =
false;
8222 if ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0) {
8225 }
while (allow_multiple && (width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0);
8226 }
else if (pm_char_is_whitespace(peek(parser))) {
8229 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
8235 PM_PARSER_ERR_FORMAT(parser, parser->
current.start, end, diag_id, (
int) (end - parser->
current.start), (
const char *) parser->
current.start);
8238 return PM_TOKEN_GLOBAL_VARIABLE;
8255static inline pm_token_type_t
8256lex_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) {
8257 if (memcmp(current_start, value, vlen) == 0) {
8260 if (parser->
lex_state & PM_LEX_STATE_FNAME) {
8261 lex_state_set(parser, PM_LEX_STATE_ENDFN);
8263 lex_state_set(parser, state);
8264 if (state == PM_LEX_STATE_BEG) {
8268 if ((modifier_type != PM_TOKEN_EOF) && !(last_state & (PM_LEX_STATE_BEG | PM_LEX_STATE_LABELED | PM_LEX_STATE_CLASS))) {
8269 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
8270 return modifier_type;
8277 return PM_TOKEN_EOF;
8280static pm_token_type_t
8281lex_identifier(
pm_parser_t *parser,
bool previous_command_start) {
8284 const uint8_t *end = parser->
end;
8285 const uint8_t *current_start = parser->
current.start;
8286 const uint8_t *current_end = parser->
current.end;
8289 if (encoding_changed) {
8290 while ((width = char_is_identifier(parser, current_end, end - current_end)) > 0) {
8291 current_end += width;
8294 while ((width = char_is_identifier_utf8(current_end, end - current_end)) > 0) {
8295 current_end += width;
8298 parser->
current.end = current_end;
8302 width = (size_t) (current_end - current_start);
8304 if (current_end < end) {
8305 if (((current_end + 1 >= end) || (current_end[1] !=
'=')) && (match(parser,
'!') || match(parser,
'?'))) {
8311 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
8312 (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')
8316 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
8317 (void) match(parser,
':');
8318 return PM_TOKEN_LABEL;
8321 if (parser->
lex_state != PM_LEX_STATE_DOT) {
8322 if (width == 8 && (lex_keyword(parser, current_start,
"defined?", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_DEFINED, PM_TOKEN_EOF) != PM_TOKEN_EOF)) {
8323 return PM_TOKEN_KEYWORD_DEFINED;
8327 return PM_TOKEN_METHOD_NAME;
8330 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,
'=')) {
8333 return PM_TOKEN_IDENTIFIER;
8337 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
8338 peek(parser) ==
':' && peek_offset(parser, 1) !=
':'
8342 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
8343 (void) match(parser,
':');
8344 return PM_TOKEN_LABEL;
8348 if (parser->
lex_state != PM_LEX_STATE_DOT) {
8349 pm_token_type_t
type;
8352 if (lex_keyword(parser, current_start,
"do", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_DO, PM_TOKEN_EOF) != PM_TOKEN_EOF) {
8353 if (pm_do_loop_stack_p(parser)) {
8354 return PM_TOKEN_KEYWORD_DO_LOOP;
8356 return PM_TOKEN_KEYWORD_DO;
8359 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;
8360 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;
8361 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;
8364 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;
8365 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;
8366 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;
8367 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;
8368 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;
8369 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;
8370 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;
8373 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;
8374 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;
8375 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;
8376 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;
8377 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;
8378 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;
8379 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;
8380 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;
8383 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;
8384 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;
8385 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;
8386 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;
8387 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;
8388 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;
8389 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;
8390 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;
8391 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;
8392 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;
8393 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;
8394 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;
8395 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;
8398 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;
8399 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;
8400 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;
8401 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;
8402 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;
8405 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;
8406 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;
8409 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;
8414 if (encoding_changed) {
8415 return parser->
encoding->
isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8417 return pm_encoding_utf_8_isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8443static pm_token_type_t
8444lex_interpolation(
pm_parser_t *parser,
const uint8_t *pound) {
8447 if (pound + 1 >= parser->
end) {
8448 parser->
current.end = pound + 1;
8449 return PM_TOKEN_STRING_CONTENT;
8458 if (pound + 2 >= parser->
end) {
8459 parser->
current.end = pound + 1;
8460 return PM_TOKEN_STRING_CONTENT;
8465 const uint8_t *variable = pound + 2;
8466 if (*variable ==
'@' && pound + 3 < parser->
end) variable++;
8468 if (char_is_identifier_start(parser, variable, parser->
end - variable)) {
8472 if (pound > parser->
current.start) {
8474 return PM_TOKEN_STRING_CONTENT;
8479 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
8480 parser->
current.end = pound + 1;
8481 return PM_TOKEN_EMBVAR;
8487 parser->
current.end = pound + 1;
8488 return PM_TOKEN_NOT_PROVIDED;
8493 if (pound + 2 >= parser->
end) {
8494 parser->
current.end = pound + 1;
8495 return PM_TOKEN_STRING_CONTENT;
8501 const uint8_t *check = pound + 2;
8503 if (pound[2] ==
'-') {
8504 if (pound + 3 >= parser->
end) {
8505 parser->
current.end = pound + 2;
8506 return PM_TOKEN_STRING_CONTENT;
8517 char_is_identifier_start(parser, check, parser->
end - check) ||
8518 (pound[2] !=
'-' && (pm_char_is_decimal_digit(pound[2]) || char_is_global_name_punctuation(pound[2])))
8523 if (pound > parser->
current.start) {
8525 return PM_TOKEN_STRING_CONTENT;
8530 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
8531 parser->
current.end = pound + 1;
8532 return PM_TOKEN_EMBVAR;
8537 parser->
current.end = pound + 1;
8538 return PM_TOKEN_NOT_PROVIDED;
8543 if (pound > parser->
current.start) {
8545 return PM_TOKEN_STRING_CONTENT;
8552 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBEXPR });
8553 parser->
current.end = pound + 2;
8555 pm_do_loop_stack_push(parser,
false);
8556 return PM_TOKEN_EMBEXPR_BEGIN;
8561 parser->
current.end = pound + 1;
8562 return PM_TOKEN_NOT_PROVIDED;
8566static const uint8_t PM_ESCAPE_FLAG_NONE = 0x0;
8567static const uint8_t PM_ESCAPE_FLAG_CONTROL = 0x1;
8568static const uint8_t PM_ESCAPE_FLAG_META = 0x2;
8569static const uint8_t PM_ESCAPE_FLAG_SINGLE = 0x4;
8570static const uint8_t PM_ESCAPE_FLAG_REGEXP = 0x8;
8575static const bool ascii_printable_chars[] = {
8576 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
8577 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8578 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8579 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8580 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8581 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
8582 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8583 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
8587char_is_ascii_printable(
const uint8_t b) {
8588 return (b < 0x80) && ascii_printable_chars[b];
8595static inline uint8_t
8596escape_hexadecimal_digit(
const uint8_t value) {
8597 return (uint8_t) ((value <=
'9') ? (value -
'0') : (value & 0x7) + 9);
8605static inline uint32_t
8606escape_unicode(
pm_parser_t *parser,
const uint8_t *
string,
size_t length) {
8608 for (
size_t index = 0; index < length; index++) {
8609 if (index != 0) value <<= 4;
8610 value |= escape_hexadecimal_digit(
string[index]);
8615 if (value >= 0xD800 && value <= 0xDFFF) {
8616 pm_parser_err(parser,
string,
string + length, PM_ERR_ESCAPE_INVALID_UNICODE);
8626static inline uint8_t
8627escape_byte(uint8_t value,
const uint8_t flags) {
8628 if (flags & PM_ESCAPE_FLAG_CONTROL) value &= 0x9f;
8629 if (flags & PM_ESCAPE_FLAG_META) value |= 0x80;
8637escape_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) {
8641 if (value >= 0x80 || flags & PM_ESCAPE_FLAG_SINGLE) {
8649 if (!pm_buffer_append_unicode_codepoint(buffer, value)) {
8650 pm_parser_err(parser, start, end, PM_ERR_ESCAPE_INVALID_UNICODE);
8651 pm_buffer_append_byte(buffer, 0xEF);
8652 pm_buffer_append_byte(buffer, 0xBF);
8653 pm_buffer_append_byte(buffer, 0xBD);
8665 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_MIXED_ENCODING, parser->
encoding->
name);
8671 pm_buffer_append_byte(buffer,
byte);
8691 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8692 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X",
byte);
8695 escape_write_byte_encoded(parser, buffer,
byte);
8707 width = pm_encoding_utf_8_char_width(parser->
current.end, parser->
end - parser->
current.end);
8711 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(*parser->
current.end++, flags));
8712 }
else if (width > 1) {
8714 pm_buffer_t *b = (flags & PM_ESCAPE_FLAG_REGEXP) ? regular_expression_buffer : buffer;
8715 pm_buffer_append_bytes(b, parser->
current.end, width);
8721 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
8731escape_read_warn(
pm_parser_t *parser, uint8_t flags, uint8_t flag,
const char *
type) {
8732#define FLAG(value) ((value & PM_ESCAPE_FLAG_CONTROL) ? "\\C-" : (value & PM_ESCAPE_FLAG_META) ? "\\M-" : "")
8734 PM_PARSER_WARN_TOKEN_FORMAT(
8737 PM_WARN_INVALID_CHARACTER,
8751 uint8_t peeked = peek(parser);
8755 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\\', flags));
8760 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\'', flags));
8765 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\a', flags));
8770 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\b', flags));
8775 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\033', flags));
8780 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\f', flags));
8785 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\n', flags));
8790 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\r', flags));
8795 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
' ', flags));
8800 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\t', flags));
8805 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\v', flags));
8808 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': {
8809 uint8_t value = (uint8_t) (*parser->
current.end -
'0');
8812 if (pm_char_is_octal_digit(peek(parser))) {
8813 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
8816 if (pm_char_is_octal_digit(peek(parser))) {
8817 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
8822 value = escape_byte(value, flags);
8823 escape_write_byte(parser, buffer, regular_expression_buffer, flags, value);
8827 const uint8_t *start = parser->
current.end - 1;
8830 uint8_t
byte = peek(parser);
8832 if (pm_char_is_hexadecimal_digit(
byte)) {
8833 uint8_t value = escape_hexadecimal_digit(
byte);
8836 byte = peek(parser);
8837 if (pm_char_is_hexadecimal_digit(
byte)) {
8838 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(
byte));
8842 value = escape_byte(value, flags);
8843 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8844 if (flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) {
8845 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X", value);
8847 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
8851 escape_write_byte_encoded(parser, buffer, value);
8853 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
8859 const uint8_t *start = parser->
current.end - 1;
8863 const uint8_t *start = parser->
current.end - 2;
8864 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
8865 }
else if (peek(parser) ==
'{') {
8866 const uint8_t *unicode_codepoints_start = parser->
current.end - 2;
8871 if ((whitespace = pm_strspn_inline_whitespace(parser->
current.end, parser->
end - parser->
current.end)) > 0) {
8872 parser->
current.end += whitespace;
8873 }
else if (peek(parser) ==
'\\' && peek_offset(parser, 1) ==
'n') {
8884 const uint8_t *extra_codepoints_start = NULL;
8885 int codepoints_count = 0;
8888 const uint8_t *unicode_start = parser->
current.end;
8889 size_t hexadecimal_length = pm_strspn_hexadecimal_digit(parser->
current.end, parser->
end - parser->
current.end);
8891 if (hexadecimal_length > 6) {
8893 pm_parser_err(parser, unicode_start, unicode_start + hexadecimal_length, PM_ERR_ESCAPE_INVALID_UNICODE_LONG);
8894 }
else if (hexadecimal_length == 0) {
8897 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8901 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
8903 pm_parser_err(parser, parser->
current.end, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE);
8904 pm_parser_err(parser, parser->
current.end, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
8910 parser->
current.end += hexadecimal_length;
8912 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count == 2) {
8913 extra_codepoints_start = unicode_start;
8916 uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length);
8917 escape_write_unicode(parser, buffer, flags, unicode_start, parser->
current.end, value);
8924 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count > 1) {
8925 pm_parser_err(parser, extra_codepoints_start, parser->
current.end - 1, PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL);
8929 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_LIST, (
int) (parser->
current.end - start), start);
8930 }
else if (peek(parser) ==
'}') {
8933 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8937 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
8939 pm_parser_err(parser, unicode_codepoints_start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
8943 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8944 pm_buffer_append_bytes(regular_expression_buffer, unicode_codepoints_start, (
size_t) (parser->
current.end - unicode_codepoints_start));
8947 size_t length = pm_strspn_hexadecimal_digit(parser->
current.end, MIN(parser->
end - parser->
current.end, 4));
8950 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8951 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
8953 const uint8_t *start = parser->
current.end - 2;
8954 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
8956 }
else if (length == 4) {
8957 uint32_t value = escape_unicode(parser, parser->
current.end, 4);
8959 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8960 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end + 4 - start));
8963 escape_write_unicode(parser, buffer, flags, start, parser->
current.end + 4, value);
8966 parser->
current.end += length;
8968 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8972 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
8974 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_UNICODE);
8983 if (flags & PM_ESCAPE_FLAG_CONTROL) {
8984 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
8988 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
8992 uint8_t peeked = peek(parser);
8996 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9002 if (match(parser,
'u') || match(parser,
'U')) {
9003 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9007 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9011 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9012 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9016 escape_read_warn(parser, flags, 0,
"\\t");
9017 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9020 if (!char_is_ascii_printable(peeked)) {
9021 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9026 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9033 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9034 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9037 if (peek(parser) !=
'-') {
9039 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9045 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9049 uint8_t peeked = peek(parser);
9053 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9059 if (match(parser,
'u') || match(parser,
'U')) {
9060 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9064 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9068 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9069 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9073 escape_read_warn(parser, flags, 0,
"\\t");
9074 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9077 if (!char_is_ascii_printable(peeked)) {
9079 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9084 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9091 if (flags & PM_ESCAPE_FLAG_META) {
9092 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META_REPEAT);
9095 if (peek(parser) !=
'-') {
9097 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
9103 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
9107 uint8_t peeked = peek(parser);
9112 if (match(parser,
'u') || match(parser,
'U')) {
9113 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9117 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_META);
9121 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_META,
"\\s");
9122 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9126 escape_read_warn(parser, flags & ((uint8_t) ~PM_ESCAPE_FLAG_CONTROL), PM_ESCAPE_FLAG_META,
"\\t");
9127 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9130 if (!char_is_ascii_printable(peeked)) {
9132 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
9137 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9142 if (peek_offset(parser, 1) ==
'\n') {
9144 escape_write_byte_encoded(parser, buffer, escape_byte(
'\n', flags));
9150 if ((flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) && !char_is_ascii_printable(peeked)) {
9152 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
9156 escape_write_escape_encoded(parser, buffer, regular_expression_buffer, flags);
9158 pm_parser_err_current(parser, PM_ERR_INVALID_ESCAPE_CHARACTER);
9190static pm_token_type_t
9192 if (lex_state_end_p(parser)) {
9193 lex_state_set(parser, PM_LEX_STATE_BEG);
9194 return PM_TOKEN_QUESTION_MARK;
9198 pm_parser_err_current(parser, PM_ERR_INCOMPLETE_QUESTION_MARK);
9200 return PM_TOKEN_CHARACTER_LITERAL;
9203 if (pm_char_is_whitespace(*parser->
current.end)) {
9204 lex_state_set(parser, PM_LEX_STATE_BEG);
9205 return PM_TOKEN_QUESTION_MARK;
9208 lex_state_set(parser, PM_LEX_STATE_BEG);
9210 if (match(parser,
'\\')) {
9211 lex_state_set(parser, PM_LEX_STATE_END);
9214 pm_buffer_init_capacity(&buffer, 3);
9216 escape_read(parser, &buffer, NULL, PM_ESCAPE_FLAG_SINGLE);
9219 return PM_TOKEN_CHARACTER_LITERAL;
9228 (parser->
current.end + encoding_width >= parser->
end) ||
9229 !char_is_identifier(parser, parser->
current.end + encoding_width, parser->
end - (parser->
current.end + encoding_width))
9232 lex_state_set(parser, PM_LEX_STATE_END);
9233 parser->
current.end += encoding_width;
9235 return PM_TOKEN_CHARACTER_LITERAL;
9239 return PM_TOKEN_QUESTION_MARK;
9246static pm_token_type_t
9248 pm_token_type_t
type = match(parser,
'@') ? PM_TOKEN_CLASS_VARIABLE : PM_TOKEN_INSTANCE_VARIABLE;
9249 const uint8_t *end = parser->
end;
9252 if ((width = char_is_identifier_start(parser, parser->
current.end, end - parser->
current.end)) > 0) {
9255 while ((width = char_is_identifier(parser, parser->
current.end, end - parser->
current.end)) > 0) {
9258 }
else if (parser->
current.end < end && pm_char_is_decimal_digit(*parser->
current.end)) {
9259 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE;
9261 diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS_3_3 : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE_3_3;
9265 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, diag_id, (
int) ((parser->
current.end + width) - parser->
current.start), (
const char *) parser->
current.start);
9267 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_CLASS_VARIABLE_BARE : PM_ERR_INSTANCE_VARIABLE_BARE;
9268 pm_parser_err_token(parser, &parser->
current, diag_id);
9274 lex_mode_pop(parser);
9296 if (comment == NULL)
return NULL;
9311static pm_token_type_t
9314 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
9316 if (newline == NULL) {
9319 pm_newline_list_append(&parser->
newline_list, newline);
9320 parser->
current.end = newline + 1;
9323 parser->
current.type = PM_TOKEN_EMBDOC_BEGIN;
9324 parser_lex_callback(parser);
9327 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_EMBDOC);
9328 if (comment == NULL)
return PM_TOKEN_EOF;
9332 while (parser->
current.end + 4 <= parser->
end) {
9338 (memcmp(parser->
current.end,
"=end", 4) == 0) &&
9341 pm_char_is_whitespace(parser->
current.end[4]) ||
9342 (parser->
current.end[4] ==
'\0') ||
9343 (parser->
current.end[4] ==
'\004') ||
9344 (parser->
current.end[4] ==
'\032')
9347 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
9349 if (newline == NULL) {
9352 pm_newline_list_append(&parser->
newline_list, newline);
9353 parser->
current.end = newline + 1;
9356 parser->
current.type = PM_TOKEN_EMBDOC_END;
9357 parser_lex_callback(parser);
9362 return PM_TOKEN_EMBDOC_END;
9367 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
9369 if (newline == NULL) {
9372 pm_newline_list_append(&parser->
newline_list, newline);
9373 parser->
current.end = newline + 1;
9376 parser->
current.type = PM_TOKEN_EMBDOC_LINE;
9377 parser_lex_callback(parser);
9380 pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
9385 return PM_TOKEN_EOF;
9395 parser->
current.type = PM_TOKEN_IGNORED_NEWLINE;
9396 parser_lex_callback(parser);
9420 const uint8_t *cursor = parser->
current.end;
9422 while (cursor < parser->end && *cursor !=
'\n' && *cursor !=
'#') {
9423 if (!pm_char_is_inline_whitespace(*cursor++))
return false;
9486 pm_buffer_append_byte(&token_buffer->
buffer,
byte);
9503 width = pm_encoding_utf_8_char_width(parser->
current.end, parser->
end - parser->
current.end);
9508 return (width == 0 ? 1 : width);
9516 size_t width = parser_char_width(parser);
9517 pm_buffer_append_bytes(&token_buffer->
buffer, parser->
current.end, width);
9523 size_t width = parser_char_width(parser);
9530pm_slice_ascii_only_p(
const uint8_t *value,
size_t length) {
9531 for (
size_t index = 0; index < length; index++) {
9532 if (value[index] & 0x80)
return false;
9567 if (token_buffer->
cursor == NULL) {
9570 pm_buffer_append_bytes(&token_buffer->
buffer, token_buffer->
cursor, (
size_t) (parser->
current.end - token_buffer->
cursor));
9571 pm_token_buffer_copy(parser, token_buffer);
9583 pm_regexp_token_buffer_copy(parser, token_buffer);
9587#define PM_TOKEN_BUFFER_DEFAULT_SIZE 16
9599 const uint8_t *start;
9600 if (token_buffer->
cursor == NULL) {
9601 pm_buffer_init_capacity(&token_buffer->
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9602 start = parser->
current.start;
9604 start = token_buffer->
cursor;
9607 const uint8_t *end = parser->
current.end - 1;
9608 assert(end >= start);
9609 pm_buffer_append_bytes(&token_buffer->
buffer, start, (
size_t) (end - start));
9611 token_buffer->
cursor = end;
9616 const uint8_t *start;
9618 pm_buffer_init_capacity(&token_buffer->
base.
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9619 pm_buffer_init_capacity(&token_buffer->
regexp_buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9620 start = parser->
current.start;
9625 const uint8_t *end = parser->
current.end - 1;
9626 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, (
size_t) (end - start));
9627 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, (
size_t) (end - start));
9632#undef PM_TOKEN_BUFFER_DEFAULT_SIZE
9640 size_t whitespace = 0;
9643 case PM_HEREDOC_INDENT_NONE:
9648 case PM_HEREDOC_INDENT_DASH:
9650 *cursor += pm_strspn_inline_whitespace(*cursor, parser->
end - *cursor);
9652 case PM_HEREDOC_INDENT_TILDE:
9655 while (*cursor < parser->end && pm_char_is_inline_whitespace(**cursor)) {
9656 if (**cursor ==
'\t') {
9657 whitespace = (whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
9676 size_t eol_length = match_eol(parser);
9683 parser_flush_heredoc_end(parser);
9689 uint8_t delimiter = *parser->
current.end;
9693 if (eol_length == 2) {
9694 delimiter = *(parser->
current.end + 1);
9697 parser->
current.end += eol_length;
9701 return *parser->
current.end++;
9708#define LEX(token_type) parser->current.type = token_type; parser_lex_callback(parser); return
9727 bool lexed_comment =
false;
9735 case PM_LEX_DEFAULT:
9736 case PM_LEX_EMBEXPR:
9753 bool space_seen =
false;
9757 bool chomping =
true;
9758 while (parser->
current.end < parser->
end && chomping) {
9759 switch (*parser->
current.end) {
9768 if (match_eol_offset(parser, 1)) {
9771 pm_parser_warn(parser, parser->
current.end, parser->
current.end + 1, PM_WARN_UNEXPECTED_CARRIAGE_RETURN);
9777 size_t eol_length = match_eol_offset(parser, 1);
9783 parser->
current.end += eol_length + 1;
9787 }
else if (pm_char_is_inline_whitespace(*parser->
current.end)) {
9820 switch (*parser->
current.end++) {
9828 const uint8_t *ending = next_newline(parser->
current.end, parser->
end - parser->
current.end);
9829 parser->
current.end = ending == NULL ? parser->
end : ending;
9834 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_INLINE);
9837 if (ending) parser->
current.end++;
9838 parser->
current.type = PM_TOKEN_COMMENT;
9839 parser_lex_callback(parser);
9851 parser_lex_magic_comment_encoding(parser);
9855 lexed_comment =
true;
9861 size_t eol_length = match_eol_at(parser, parser->
current.end - 1);
9873 if (!lexed_comment) {
9874 parser->
current.end += eol_length - 1;
9883 parser_flush_heredoc_end(parser);
9888 switch (lex_state_ignored_p(parser)) {
9889 case PM_IGNORED_NEWLINE_NONE:
9891 case PM_IGNORED_NEWLINE_PATTERN:
9893 if (!lexed_comment) parser_lex_ignored_newline(parser);
9894 lex_state_set(parser, PM_LEX_STATE_BEG);
9896 parser->
current.type = PM_TOKEN_NEWLINE;
9900 case PM_IGNORED_NEWLINE_ALL:
9901 if (!lexed_comment) parser_lex_ignored_newline(parser);
9902 lexed_comment =
false;
9903 goto lex_next_token;
9911 next_content += pm_strspn_inline_whitespace(next_content, parser->
end - next_content);
9913 if (next_content < parser->end) {
9919 if (next_content[0] ==
'#') {
9921 const uint8_t *following = next_newline(next_content, parser->
end - next_content);
9923 while (following && (following + 1 < parser->
end)) {
9925 following += pm_strspn_inline_whitespace(following, parser->
end - following);
9929 if (peek_at(parser, following) !=
'#')
break;
9933 following = next_newline(following, parser->
end - following);
9938 if (lex_state_ignored_p(parser)) {
9939 if (!lexed_comment) parser_lex_ignored_newline(parser);
9940 lexed_comment =
false;
9941 goto lex_next_token;
9947 (peek_at(parser, following) ==
'.') ||
9948 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'.')
9950 if (!lexed_comment) parser_lex_ignored_newline(parser);
9951 lexed_comment =
false;
9952 goto lex_next_token;
9962 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'&') ||
9963 (peek_at(parser, following) ==
'|' && peek_at(parser, following + 1) ==
'|') ||
9964 (peek_at(parser, following) ==
'a' && peek_at(parser, following + 1) ==
'n' && peek_at(parser, following + 2) ==
'd' && !char_is_identifier(parser, following + 3, parser->
end - (following + 3))) ||
9965 (peek_at(parser, following) ==
'o' && peek_at(parser, following + 1) ==
'r' && !char_is_identifier(parser, following + 2, parser->
end - (following + 2)))
9968 if (!lexed_comment) parser_lex_ignored_newline(parser);
9969 lexed_comment =
false;
9970 goto lex_next_token;
9976 if (next_content[0] ==
'.') {
9980 if (peek_at(parser, next_content + 1) ==
'.') {
9981 if (!lexed_comment) parser_lex_ignored_newline(parser);
9982 lex_state_set(parser, PM_LEX_STATE_BEG);
9984 parser->
current.type = PM_TOKEN_NEWLINE;
9988 if (!lexed_comment) parser_lex_ignored_newline(parser);
9989 lex_state_set(parser, PM_LEX_STATE_DOT);
9990 parser->
current.start = next_content;
9991 parser->
current.end = next_content + 1;
9998 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'.') {
9999 if (!lexed_comment) parser_lex_ignored_newline(parser);
10000 lex_state_set(parser, PM_LEX_STATE_DOT);
10001 parser->
current.start = next_content;
10002 parser->
current.end = next_content + 2;
10004 LEX(PM_TOKEN_AMPERSAND_DOT);
10010 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'&') {
10011 if (!lexed_comment) parser_lex_ignored_newline(parser);
10012 lex_state_set(parser, PM_LEX_STATE_BEG);
10013 parser->
current.start = next_content;
10014 parser->
current.end = next_content + 2;
10016 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
10021 if (peek_at(parser, next_content) ==
'|' && peek_at(parser, next_content + 1) ==
'|') {
10022 if (!lexed_comment) parser_lex_ignored_newline(parser);
10023 lex_state_set(parser, PM_LEX_STATE_BEG);
10024 parser->
current.start = next_content;
10025 parser->
current.end = next_content + 2;
10027 LEX(PM_TOKEN_PIPE_PIPE);
10033 peek_at(parser, next_content) ==
'a' &&
10034 peek_at(parser, next_content + 1) ==
'n' &&
10035 peek_at(parser, next_content + 2) ==
'd' &&
10036 !char_is_identifier(parser, next_content + 3, parser->
end - (next_content + 3))
10038 if (!lexed_comment) parser_lex_ignored_newline(parser);
10039 lex_state_set(parser, PM_LEX_STATE_BEG);
10040 parser->
current.start = next_content;
10041 parser->
current.end = next_content + 3;
10044 LEX(PM_TOKEN_KEYWORD_AND);
10050 peek_at(parser, next_content) ==
'o' &&
10051 peek_at(parser, next_content + 1) ==
'r' &&
10052 !char_is_identifier(parser, next_content + 2, parser->
end - (next_content + 2))
10054 if (!lexed_comment) parser_lex_ignored_newline(parser);
10055 lex_state_set(parser, PM_LEX_STATE_BEG);
10056 parser->
current.start = next_content;
10057 parser->
current.end = next_content + 2;
10060 LEX(PM_TOKEN_KEYWORD_OR);
10067 lex_state_set(parser, PM_LEX_STATE_BEG);
10069 parser->
current.type = PM_TOKEN_NEWLINE;
10070 if (!lexed_comment) parser_lex_callback(parser);
10080 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10081 LEX(PM_TOKEN_COMMA);
10085 pm_token_type_t
type = PM_TOKEN_PARENTHESIS_LEFT;
10087 if (space_seen && (lex_state_arg_p(parser) || parser->
lex_state == (PM_LEX_STATE_END | PM_LEX_STATE_LABEL))) {
10088 type = PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES;
10092 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10093 pm_do_loop_stack_push(parser,
false);
10100 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10101 pm_do_loop_stack_pop(parser);
10102 LEX(PM_TOKEN_PARENTHESIS_RIGHT);
10106 lex_state_set(parser, PM_LEX_STATE_BEG);
10108 LEX(PM_TOKEN_SEMICOLON);
10113 pm_token_type_t
type = PM_TOKEN_BRACKET_LEFT;
10115 if (lex_state_operator_p(parser)) {
10116 if (match(parser,
']')) {
10118 lex_state_set(parser, PM_LEX_STATE_ARG);
10119 LEX(match(parser,
'=') ? PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL : PM_TOKEN_BRACKET_LEFT_RIGHT);
10122 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABEL);
10126 if (lex_state_beg_p(parser) || (lex_state_arg_p(parser) && (space_seen || lex_state_p(parser, PM_LEX_STATE_LABELED)))) {
10127 type = PM_TOKEN_BRACKET_LEFT_ARRAY;
10130 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10131 pm_do_loop_stack_push(parser,
false);
10137 lex_state_set(parser, PM_LEX_STATE_END);
10138 pm_do_loop_stack_pop(parser);
10139 LEX(PM_TOKEN_BRACKET_RIGHT);
10143 pm_token_type_t
type = PM_TOKEN_BRACE_LEFT;
10148 lex_state_set(parser, PM_LEX_STATE_BEG);
10149 type = PM_TOKEN_LAMBDA_BEGIN;
10150 }
else if (lex_state_p(parser, PM_LEX_STATE_LABELED)) {
10152 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10153 }
else if (lex_state_p(parser, PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_END | PM_LEX_STATE_ENDFN)) {
10156 lex_state_set(parser, PM_LEX_STATE_BEG);
10157 }
else if (lex_state_p(parser, PM_LEX_STATE_ENDARG)) {
10160 lex_state_set(parser, PM_LEX_STATE_BEG);
10163 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10168 pm_do_loop_stack_push(parser,
false);
10176 pm_do_loop_stack_pop(parser);
10179 lex_mode_pop(parser);
10180 LEX(PM_TOKEN_EMBEXPR_END);
10184 lex_state_set(parser, PM_LEX_STATE_END);
10185 LEX(PM_TOKEN_BRACE_RIGHT);
10189 if (match(parser,
'*')) {
10190 if (match(parser,
'=')) {
10191 lex_state_set(parser, PM_LEX_STATE_BEG);
10192 LEX(PM_TOKEN_STAR_STAR_EQUAL);
10195 pm_token_type_t
type = PM_TOKEN_STAR_STAR;
10197 if (lex_state_spcarg_p(parser, space_seen)) {
10198 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR_STAR);
10199 type = PM_TOKEN_USTAR_STAR;
10200 }
else if (lex_state_beg_p(parser)) {
10201 type = PM_TOKEN_USTAR_STAR;
10202 }
else if (ambiguous_operator_p(parser, space_seen)) {
10203 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"**",
"argument prefix");
10206 if (lex_state_operator_p(parser)) {
10207 lex_state_set(parser, PM_LEX_STATE_ARG);
10209 lex_state_set(parser, PM_LEX_STATE_BEG);
10215 if (match(parser,
'=')) {
10216 lex_state_set(parser, PM_LEX_STATE_BEG);
10217 LEX(PM_TOKEN_STAR_EQUAL);
10220 pm_token_type_t
type = PM_TOKEN_STAR;
10222 if (lex_state_spcarg_p(parser, space_seen)) {
10223 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR);
10224 type = PM_TOKEN_USTAR;
10225 }
else if (lex_state_beg_p(parser)) {
10226 type = PM_TOKEN_USTAR;
10227 }
else if (ambiguous_operator_p(parser, space_seen)) {
10228 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"*",
"argument prefix");
10231 if (lex_state_operator_p(parser)) {
10232 lex_state_set(parser, PM_LEX_STATE_ARG);
10234 lex_state_set(parser, PM_LEX_STATE_BEG);
10242 if (lex_state_operator_p(parser)) {
10243 lex_state_set(parser, PM_LEX_STATE_ARG);
10244 if (match(parser,
'@')) {
10245 LEX(PM_TOKEN_BANG);
10248 lex_state_set(parser, PM_LEX_STATE_BEG);
10251 if (match(parser,
'=')) {
10252 LEX(PM_TOKEN_BANG_EQUAL);
10255 if (match(parser,
'~')) {
10256 LEX(PM_TOKEN_BANG_TILDE);
10259 LEX(PM_TOKEN_BANG);
10264 current_token_starts_line(parser) &&
10266 memcmp(parser->
current.end,
"begin", 5) == 0 &&
10267 (pm_char_is_whitespace(peek_offset(parser, 5)) || (peek_offset(parser, 5) ==
'\0'))
10269 pm_token_type_t
type = lex_embdoc(parser);
10270 if (
type == PM_TOKEN_EOF) {
10274 goto lex_next_token;
10277 if (lex_state_operator_p(parser)) {
10278 lex_state_set(parser, PM_LEX_STATE_ARG);
10280 lex_state_set(parser, PM_LEX_STATE_BEG);
10283 if (match(parser,
'>')) {
10284 LEX(PM_TOKEN_EQUAL_GREATER);
10287 if (match(parser,
'~')) {
10288 LEX(PM_TOKEN_EQUAL_TILDE);
10291 if (match(parser,
'=')) {
10292 LEX(match(parser,
'=') ? PM_TOKEN_EQUAL_EQUAL_EQUAL : PM_TOKEN_EQUAL_EQUAL);
10295 LEX(PM_TOKEN_EQUAL);
10299 if (match(parser,
'<')) {
10301 !lex_state_p(parser, PM_LEX_STATE_DOT | PM_LEX_STATE_CLASS) &&
10302 !lex_state_end_p(parser) &&
10303 (!lex_state_p(parser, PM_LEX_STATE_ARG_ANY) || lex_state_p(parser, PM_LEX_STATE_LABELED) || space_seen)
10305 const uint8_t *end = parser->
current.end;
10310 if (match(parser,
'-')) {
10311 indent = PM_HEREDOC_INDENT_DASH;
10313 else if (match(parser,
'~')) {
10314 indent = PM_HEREDOC_INDENT_TILDE;
10317 if (match(parser,
'`')) {
10318 quote = PM_HEREDOC_QUOTE_BACKTICK;
10320 else if (match(parser,
'"')) {
10321 quote = PM_HEREDOC_QUOTE_DOUBLE;
10323 else if (match(parser,
'\'')) {
10324 quote = PM_HEREDOC_QUOTE_SINGLE;
10327 const uint8_t *ident_start = parser->
current.end;
10332 }
else if (quote == PM_HEREDOC_QUOTE_NONE && (width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) == 0) {
10335 if (quote == PM_HEREDOC_QUOTE_NONE) {
10336 parser->
current.end += width;
10338 while ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end))) {
10339 parser->
current.end += width;
10345 if (*parser->
current.end ==
'\r' || *parser->
current.end ==
'\n')
break;
10350 size_t ident_length = (size_t) (parser->
current.end - ident_start);
10351 bool ident_error =
false;
10353 if (quote != PM_HEREDOC_QUOTE_NONE && !match(parser, (uint8_t) quote)) {
10354 pm_parser_err(parser, ident_start, ident_start + ident_length, PM_ERR_HEREDOC_IDENTIFIER);
10355 ident_error =
true;
10360 .mode = PM_LEX_HEREDOC,
10363 .ident_start = ident_start,
10364 .ident_length = ident_length,
10368 .next_start = parser->
current.end,
10370 .line_continuation =
false
10375 const uint8_t *body_start = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10377 if (body_start == NULL) {
10382 if (!ident_error) pm_parser_err_heredoc_term(parser, ident_start, ident_length);
10383 body_start = parser->
end;
10387 pm_newline_list_append(&parser->
newline_list, body_start);
10396 LEX(PM_TOKEN_HEREDOC_START);
10400 if (match(parser,
'=')) {
10401 lex_state_set(parser, PM_LEX_STATE_BEG);
10402 LEX(PM_TOKEN_LESS_LESS_EQUAL);
10405 if (ambiguous_operator_p(parser, space_seen)) {
10406 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"<<",
"here document");
10409 if (lex_state_operator_p(parser)) {
10410 lex_state_set(parser, PM_LEX_STATE_ARG);
10412 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
10413 lex_state_set(parser, PM_LEX_STATE_BEG);
10416 LEX(PM_TOKEN_LESS_LESS);
10419 if (lex_state_operator_p(parser)) {
10420 lex_state_set(parser, PM_LEX_STATE_ARG);
10422 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
10423 lex_state_set(parser, PM_LEX_STATE_BEG);
10426 if (match(parser,
'=')) {
10427 if (match(parser,
'>')) {
10428 LEX(PM_TOKEN_LESS_EQUAL_GREATER);
10431 LEX(PM_TOKEN_LESS_EQUAL);
10434 LEX(PM_TOKEN_LESS);
10438 if (match(parser,
'>')) {
10439 if (lex_state_operator_p(parser)) {
10440 lex_state_set(parser, PM_LEX_STATE_ARG);
10442 lex_state_set(parser, PM_LEX_STATE_BEG);
10444 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_GREATER_EQUAL : PM_TOKEN_GREATER_GREATER);
10447 if (lex_state_operator_p(parser)) {
10448 lex_state_set(parser, PM_LEX_STATE_ARG);
10450 lex_state_set(parser, PM_LEX_STATE_BEG);
10453 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_EQUAL : PM_TOKEN_GREATER);
10457 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
10458 lex_mode_push_string(parser,
true, label_allowed,
'\0',
'"');
10459 LEX(PM_TOKEN_STRING_BEGIN);
10464 if (lex_state_p(parser, PM_LEX_STATE_FNAME)) {
10465 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10466 LEX(PM_TOKEN_BACKTICK);
10469 if (lex_state_p(parser, PM_LEX_STATE_DOT)) {
10470 if (previous_command_start) {
10471 lex_state_set(parser, PM_LEX_STATE_CMDARG);
10473 lex_state_set(parser, PM_LEX_STATE_ARG);
10476 LEX(PM_TOKEN_BACKTICK);
10479 lex_mode_push_string(parser,
true,
false,
'\0',
'`');
10480 LEX(PM_TOKEN_BACKTICK);
10485 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
10486 lex_mode_push_string(parser,
false, label_allowed,
'\0',
'\'');
10487 LEX(PM_TOKEN_STRING_BEGIN);
10492 LEX(lex_question_mark(parser));
10496 if (match(parser,
'&')) {
10497 lex_state_set(parser, PM_LEX_STATE_BEG);
10499 if (match(parser,
'=')) {
10500 LEX(PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
10503 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
10506 if (match(parser,
'=')) {
10507 lex_state_set(parser, PM_LEX_STATE_BEG);
10508 LEX(PM_TOKEN_AMPERSAND_EQUAL);
10511 if (match(parser,
'.')) {
10512 lex_state_set(parser, PM_LEX_STATE_DOT);
10513 LEX(PM_TOKEN_AMPERSAND_DOT);
10516 pm_token_type_t
type = PM_TOKEN_AMPERSAND;
10517 if (lex_state_spcarg_p(parser, space_seen)) {
10518 if ((peek(parser) !=
':') || (peek_offset(parser, 1) ==
'\0')) {
10519 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
10521 const uint8_t delim = peek_offset(parser, 1);
10523 if ((delim !=
'\'') && (delim !=
'"') && !char_is_identifier(parser, parser->
current.end + 1, parser->
end - (parser->
current.end + 1))) {
10524 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
10528 type = PM_TOKEN_UAMPERSAND;
10529 }
else if (lex_state_beg_p(parser)) {
10530 type = PM_TOKEN_UAMPERSAND;
10531 }
else if (ambiguous_operator_p(parser, space_seen)) {
10532 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"&",
"argument prefix");
10535 if (lex_state_operator_p(parser)) {
10536 lex_state_set(parser, PM_LEX_STATE_ARG);
10538 lex_state_set(parser, PM_LEX_STATE_BEG);
10546 if (match(parser,
'|')) {
10547 if (match(parser,
'=')) {
10548 lex_state_set(parser, PM_LEX_STATE_BEG);
10549 LEX(PM_TOKEN_PIPE_PIPE_EQUAL);
10552 if (lex_state_p(parser, PM_LEX_STATE_BEG)) {
10554 LEX(PM_TOKEN_PIPE);
10557 lex_state_set(parser, PM_LEX_STATE_BEG);
10558 LEX(PM_TOKEN_PIPE_PIPE);
10561 if (match(parser,
'=')) {
10562 lex_state_set(parser, PM_LEX_STATE_BEG);
10563 LEX(PM_TOKEN_PIPE_EQUAL);
10566 if (lex_state_operator_p(parser)) {
10567 lex_state_set(parser, PM_LEX_STATE_ARG);
10569 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10572 LEX(PM_TOKEN_PIPE);
10576 if (lex_state_operator_p(parser)) {
10577 lex_state_set(parser, PM_LEX_STATE_ARG);
10579 if (match(parser,
'@')) {
10580 LEX(PM_TOKEN_UPLUS);
10583 LEX(PM_TOKEN_PLUS);
10586 if (match(parser,
'=')) {
10587 lex_state_set(parser, PM_LEX_STATE_BEG);
10588 LEX(PM_TOKEN_PLUS_EQUAL);
10592 lex_state_beg_p(parser) ||
10593 (lex_state_spcarg_p(parser, space_seen) ? (pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS),
true) : false)
10595 lex_state_set(parser, PM_LEX_STATE_BEG);
10597 if (pm_char_is_decimal_digit(peek(parser))) {
10599 pm_token_type_t
type = lex_numeric(parser);
10600 lex_state_set(parser, PM_LEX_STATE_END);
10604 LEX(PM_TOKEN_UPLUS);
10607 if (ambiguous_operator_p(parser, space_seen)) {
10608 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"+",
"unary operator");
10611 lex_state_set(parser, PM_LEX_STATE_BEG);
10612 LEX(PM_TOKEN_PLUS);
10617 if (lex_state_operator_p(parser)) {
10618 lex_state_set(parser, PM_LEX_STATE_ARG);
10620 if (match(parser,
'@')) {
10621 LEX(PM_TOKEN_UMINUS);
10624 LEX(PM_TOKEN_MINUS);
10627 if (match(parser,
'=')) {
10628 lex_state_set(parser, PM_LEX_STATE_BEG);
10629 LEX(PM_TOKEN_MINUS_EQUAL);
10632 if (match(parser,
'>')) {
10633 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10634 LEX(PM_TOKEN_MINUS_GREATER);
10637 bool spcarg = lex_state_spcarg_p(parser, space_seen);
10638 bool is_beg = lex_state_beg_p(parser);
10639 if (!is_beg && spcarg) {
10640 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS);
10643 if (is_beg || spcarg) {
10644 lex_state_set(parser, PM_LEX_STATE_BEG);
10645 LEX(pm_char_is_decimal_digit(peek(parser)) ? PM_TOKEN_UMINUS_NUM : PM_TOKEN_UMINUS);
10648 if (ambiguous_operator_p(parser, space_seen)) {
10649 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"-",
"unary operator");
10652 lex_state_set(parser, PM_LEX_STATE_BEG);
10653 LEX(PM_TOKEN_MINUS);
10658 bool beg_p = lex_state_beg_p(parser);
10660 if (match(parser,
'.')) {
10661 if (match(parser,
'.')) {
10664 if (lex_state_p(parser, PM_LEX_STATE_END)) {
10665 lex_state_set(parser, PM_LEX_STATE_BEG);
10667 lex_state_set(parser, PM_LEX_STATE_ENDARG);
10669 LEX(PM_TOKEN_UDOT_DOT_DOT);
10673 pm_parser_warn_token(parser, &parser->
current, PM_WARN_DOT_DOT_DOT_EOL);
10676 lex_state_set(parser, PM_LEX_STATE_BEG);
10677 LEX(beg_p ? PM_TOKEN_UDOT_DOT_DOT : PM_TOKEN_DOT_DOT_DOT);
10680 lex_state_set(parser, PM_LEX_STATE_BEG);
10681 LEX(beg_p ? PM_TOKEN_UDOT_DOT : PM_TOKEN_DOT_DOT);
10684 lex_state_set(parser, PM_LEX_STATE_DOT);
10699 pm_token_type_t
type = lex_numeric(parser);
10700 lex_state_set(parser, PM_LEX_STATE_END);
10706 if (match(parser,
':')) {
10707 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)) {
10708 lex_state_set(parser, PM_LEX_STATE_BEG);
10709 LEX(PM_TOKEN_UCOLON_COLON);
10712 lex_state_set(parser, PM_LEX_STATE_DOT);
10713 LEX(PM_TOKEN_COLON_COLON);
10716 if (lex_state_end_p(parser) || pm_char_is_whitespace(peek(parser)) || peek(parser) ==
'#') {
10717 lex_state_set(parser, PM_LEX_STATE_BEG);
10718 LEX(PM_TOKEN_COLON);
10721 if (peek(parser) ==
'"' || peek(parser) ==
'\'') {
10722 lex_mode_push_string(parser, peek(parser) ==
'"',
false,
'\0', *parser->
current.end);
10726 lex_state_set(parser, PM_LEX_STATE_FNAME);
10727 LEX(PM_TOKEN_SYMBOL_BEGIN);
10731 if (lex_state_beg_p(parser)) {
10732 lex_mode_push_regexp(parser,
'\0',
'/');
10733 LEX(PM_TOKEN_REGEXP_BEGIN);
10736 if (match(parser,
'=')) {
10737 lex_state_set(parser, PM_LEX_STATE_BEG);
10738 LEX(PM_TOKEN_SLASH_EQUAL);
10741 if (lex_state_spcarg_p(parser, space_seen)) {
10742 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_SLASH);
10743 lex_mode_push_regexp(parser,
'\0',
'/');
10744 LEX(PM_TOKEN_REGEXP_BEGIN);
10747 if (ambiguous_operator_p(parser, space_seen)) {
10748 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"/",
"regexp literal");
10751 if (lex_state_operator_p(parser)) {
10752 lex_state_set(parser, PM_LEX_STATE_ARG);
10754 lex_state_set(parser, PM_LEX_STATE_BEG);
10757 LEX(PM_TOKEN_SLASH);
10761 if (lex_state_operator_p(parser)) {
10762 lex_state_set(parser, PM_LEX_STATE_ARG);
10764 lex_state_set(parser, PM_LEX_STATE_BEG);
10766 LEX(match(parser,
'=') ? PM_TOKEN_CARET_EQUAL : PM_TOKEN_CARET);
10770 if (lex_state_operator_p(parser)) {
10771 (void) match(parser,
'@');
10772 lex_state_set(parser, PM_LEX_STATE_ARG);
10774 lex_state_set(parser, PM_LEX_STATE_BEG);
10777 LEX(PM_TOKEN_TILDE);
10785 if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->
current.end >= parser->
end)) {
10786 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT_EOF);
10787 LEX(PM_TOKEN_PERCENT);
10790 if (!lex_state_beg_p(parser) && match(parser,
'=')) {
10791 lex_state_set(parser, PM_LEX_STATE_BEG);
10792 LEX(PM_TOKEN_PERCENT_EQUAL);
10794 lex_state_beg_p(parser) ||
10795 (lex_state_p(parser, PM_LEX_STATE_FITEM) && (peek(parser) ==
's')) ||
10796 lex_state_spcarg_p(parser, space_seen)
10799 if (*parser->
current.end >= 0x80) {
10800 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
10803 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10804 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10805 LEX(PM_TOKEN_STRING_BEGIN);
10810 uint8_t delimiter = peek_offset(parser, 1);
10812 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
10813 goto lex_next_token;
10816 switch (peek(parser)) {
10821 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
10823 lex_mode_push_list_eof(parser);
10826 LEX(PM_TOKEN_PERCENT_LOWER_I);
10832 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
10834 lex_mode_push_list_eof(parser);
10837 LEX(PM_TOKEN_PERCENT_UPPER_I);
10843 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10844 lex_mode_push_regexp(parser, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10846 lex_mode_push_regexp(parser,
'\0',
'\0');
10849 LEX(PM_TOKEN_REGEXP_BEGIN);
10855 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10856 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10858 lex_mode_push_string_eof(parser);
10861 LEX(PM_TOKEN_STRING_BEGIN);
10867 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10868 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10870 lex_mode_push_string_eof(parser);
10873 LEX(PM_TOKEN_STRING_BEGIN);
10879 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10880 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10881 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
10883 lex_mode_push_string_eof(parser);
10886 LEX(PM_TOKEN_SYMBOL_BEGIN);
10892 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
10894 lex_mode_push_list_eof(parser);
10897 LEX(PM_TOKEN_PERCENT_LOWER_W);
10903 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
10905 lex_mode_push_list_eof(parser);
10908 LEX(PM_TOKEN_PERCENT_UPPER_W);
10914 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10915 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10917 lex_mode_push_string_eof(parser);
10920 LEX(PM_TOKEN_PERCENT_LOWER_X);
10927 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
10928 goto lex_next_token;
10932 if (ambiguous_operator_p(parser, space_seen)) {
10933 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"%",
"string literal");
10936 lex_state_set(parser, lex_state_operator_p(parser) ? PM_LEX_STATE_ARG : PM_LEX_STATE_BEG);
10937 LEX(PM_TOKEN_PERCENT);
10942 pm_token_type_t
type = lex_global_variable(parser);
10947 lex_mode_pop(parser);
10950 lex_state_set(parser, PM_LEX_STATE_END);
10956 lex_state_set(parser, parser->
lex_state & PM_LEX_STATE_FNAME ? PM_LEX_STATE_ENDFN : PM_LEX_STATE_END);
10957 LEX(lex_at_variable(parser));
10960 if (*parser->
current.start !=
'_') {
10961 size_t width = char_is_identifier_start(parser, parser->
current.start, parser->
end - parser->
current.start);
10968 if (*parser->
current.start >= 0x80) {
10969 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *parser->
current.start);
10970 }
else if (*parser->
current.start ==
'\\') {
10971 switch (peek_at(parser, parser->
current.start + 1)) {
10974 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped space");
10978 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped form feed");
10982 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped horizontal tab");
10986 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped vertical tab");
10989 if (peek_at(parser, parser->
current.start + 2) !=
'\n') {
10991 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped carriage return");
10996 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"backslash");
10999 }
else if (char_is_ascii_printable(*parser->
current.start)) {
11000 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_PRINTABLE_CHARACTER, *parser->
current.start);
11002 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_CHARACTER, *parser->
current.start);
11005 goto lex_next_token;
11011 pm_token_type_t
type = lex_identifier(parser, previous_command_start);
11019 current_token_starts_line(parser) &&
11020 (memcmp(parser->
current.start,
"__END__", 7) == 0) &&
11021 (parser->
current.end == parser->
end || match_eol(parser))
11026 const uint8_t *cursor = parser->
current.end;
11027 while ((cursor = next_newline(cursor, parser->
end - cursor)) != NULL) {
11028 pm_newline_list_append(&parser->
newline_list, cursor++);
11032 parser->
current.type = PM_TOKEN___END__;
11033 parser_lex_callback(parser);
11043 if (
type == PM_TOKEN_IDENTIFIER ||
type == PM_TOKEN_CONSTANT ||
type == PM_TOKEN_METHOD_NAME) {
11044 if (lex_state_p(parser, PM_LEX_STATE_BEG_ANY | PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_DOT)) {
11045 if (previous_command_start) {
11046 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11048 lex_state_set(parser, PM_LEX_STATE_ARG);
11050 }
else if (parser->
lex_state == PM_LEX_STATE_FNAME) {
11051 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11053 lex_state_set(parser, PM_LEX_STATE_END);
11058 !(last_state & (PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME)) &&
11059 (
type == PM_TOKEN_IDENTIFIER) &&
11060 ((pm_parser_local_depth(parser, &parser->
current) != -1) ||
11061 pm_token_is_numbered_parameter(parser->
current.start, parser->
current.end))
11063 lex_state_set(parser, PM_LEX_STATE_END | PM_LEX_STATE_LABEL);
11070 case PM_LEX_LIST: {
11084 whitespace = pm_strspn_inline_whitespace(parser->
current.end, parser->
end - parser->
current.end);
11085 if (peek_offset(parser, (ptrdiff_t)whitespace) ==
'\n') {
11092 if (whitespace > 0) {
11093 parser->
current.end += whitespace;
11094 if (peek_offset(parser, -1) ==
'\n') {
11096 parser_flush_heredoc_end(parser);
11098 LEX(PM_TOKEN_WORDS_SEP);
11110 const uint8_t *breakpoints = lex_mode->
as.list.
breakpoints;
11111 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11117 while (breakpoint != NULL) {
11120 if (pm_char_is_whitespace(*breakpoint)) {
11121 parser->
current.end = breakpoint;
11122 pm_token_buffer_flush(parser, &token_buffer);
11123 LEX(PM_TOKEN_STRING_CONTENT);
11132 parser->
current.end = breakpoint + 1;
11133 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11140 if (breakpoint > parser->
current.start) {
11141 parser->
current.end = breakpoint;
11142 pm_token_buffer_flush(parser, &token_buffer);
11143 LEX(PM_TOKEN_STRING_CONTENT);
11148 parser->
current.end = breakpoint + 1;
11149 lex_mode_pop(parser);
11150 lex_state_set(parser, PM_LEX_STATE_END);
11151 LEX(PM_TOKEN_STRING_END);
11155 if (*breakpoint ==
'\0') {
11156 breakpoint = pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->
end - (breakpoint + 1),
true);
11163 if (*breakpoint ==
'\\') {
11164 parser->
current.end = breakpoint + 1;
11173 pm_token_buffer_escape(parser, &token_buffer);
11174 uint8_t peeked = peek(parser);
11182 pm_token_buffer_push_byte(&token_buffer, peeked);
11187 if (peek(parser) !=
'\n') {
11188 pm_token_buffer_push_byte(&token_buffer,
'\r');
11193 pm_token_buffer_push_byte(&token_buffer,
'\n');
11199 parser_flush_heredoc_end(parser);
11200 pm_token_buffer_copy(parser, &token_buffer);
11201 LEX(PM_TOKEN_STRING_CONTENT);
11211 pm_token_buffer_push_byte(&token_buffer, peeked);
11214 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
11216 pm_token_buffer_push_byte(&token_buffer,
'\\');
11217 pm_token_buffer_push_escaped(&token_buffer, parser);
11224 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11229 if (*breakpoint ==
'#') {
11230 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11232 if (
type == PM_TOKEN_NOT_PROVIDED) {
11237 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11241 if (
type == PM_TOKEN_STRING_CONTENT) {
11242 pm_token_buffer_flush(parser, &token_buffer);
11251 parser->
current.end = breakpoint + 1;
11252 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11258 pm_token_buffer_flush(parser, &token_buffer);
11259 LEX(PM_TOKEN_STRING_CONTENT);
11265 pm_token_buffer_flush(parser, &token_buffer);
11266 LEX(PM_TOKEN_STRING_CONTENT);
11268 case PM_LEX_REGEXP: {
11290 const uint8_t *breakpoints = lex_mode->
as.regexp.
breakpoints;
11291 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11294 while (breakpoint != NULL) {
11296 bool is_terminator = (*breakpoint == term);
11301 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
11302 if (term ==
'\n') {
11303 is_terminator =
true;
11309 if (term ==
'\r') {
11310 is_terminator =
false;
11316 if (is_terminator) {
11318 parser->
current.end = breakpoint + 1;
11319 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11327 if (breakpoint > parser->
current.start) {
11328 parser->
current.end = breakpoint;
11329 pm_regexp_token_buffer_flush(parser, &token_buffer);
11330 LEX(PM_TOKEN_STRING_CONTENT);
11334 size_t eol_length = match_eol_at(parser, breakpoint);
11336 parser->
current.end = breakpoint + eol_length;
11345 parser->
current.end = breakpoint + 1;
11352 lex_mode_pop(parser);
11353 lex_state_set(parser, PM_LEX_STATE_END);
11354 LEX(PM_TOKEN_REGEXP_END);
11359 if (*breakpoint && *breakpoint == lex_mode->
as.regexp.
incrementor) {
11360 parser->
current.end = breakpoint + 1;
11361 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11366 switch (*breakpoint) {
11369 parser->
current.end = breakpoint + 1;
11370 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11373 if (peek_at(parser, breakpoint + 1) !=
'\n') {
11374 parser->
current.end = breakpoint + 1;
11375 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11380 parser->
current.end = breakpoint;
11381 pm_regexp_token_buffer_escape(parser, &token_buffer);
11389 pm_newline_list_append(&parser->
newline_list, breakpoint);
11390 parser->
current.end = breakpoint + 1;
11391 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11395 parser->
current.end = breakpoint + 1;
11396 parser_flush_heredoc_end(parser);
11397 pm_regexp_token_buffer_flush(parser, &token_buffer);
11398 LEX(PM_TOKEN_STRING_CONTENT);
11403 parser->
current.end = breakpoint + 1;
11412 pm_regexp_token_buffer_escape(parser, &token_buffer);
11413 uint8_t peeked = peek(parser);
11418 if (peek(parser) !=
'\n') {
11420 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11422 pm_regexp_token_buffer_push_byte(&token_buffer,
'\r');
11423 pm_token_buffer_push_byte(&token_buffer.
base,
'\r');
11432 parser_flush_heredoc_end(parser);
11433 pm_regexp_token_buffer_copy(parser, &token_buffer);
11434 LEX(PM_TOKEN_STRING_CONTENT);
11455 case '$':
case ')':
case '*':
case '+':
11456 case '.':
case '>':
case '?':
case ']':
11457 case '^':
case '|':
case '}':
11458 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11464 pm_regexp_token_buffer_push_byte(&token_buffer, peeked);
11465 pm_token_buffer_push_byte(&token_buffer.
base, peeked);
11470 if (peeked < 0x80) pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11471 pm_regexp_token_buffer_push_escaped(&token_buffer, parser);
11476 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11482 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11484 if (
type == PM_TOKEN_NOT_PROVIDED) {
11489 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11493 if (
type == PM_TOKEN_STRING_CONTENT) {
11494 pm_regexp_token_buffer_flush(parser, &token_buffer);
11500 assert(
false &&
"unreachable");
11506 pm_regexp_token_buffer_flush(parser, &token_buffer);
11507 LEX(PM_TOKEN_STRING_CONTENT);
11513 pm_regexp_token_buffer_flush(parser, &token_buffer);
11514 LEX(PM_TOKEN_STRING_CONTENT);
11516 case PM_LEX_STRING: {
11535 const uint8_t *breakpoints = lex_mode->
as.string.
breakpoints;
11536 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11542 while (breakpoint != NULL) {
11547 parser->
current.end = breakpoint + 1;
11548 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11553 bool is_terminator = (*breakpoint == term);
11558 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
11559 if (term ==
'\n') {
11560 is_terminator =
true;
11566 if (term ==
'\r') {
11567 is_terminator =
false;
11574 if (is_terminator) {
11578 parser->
current.end = breakpoint + 1;
11579 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11586 if (breakpoint > parser->
current.start) {
11587 parser->
current.end = breakpoint;
11588 pm_token_buffer_flush(parser, &token_buffer);
11589 LEX(PM_TOKEN_STRING_CONTENT);
11594 size_t eol_length = match_eol_at(parser, breakpoint);
11596 parser->
current.end = breakpoint + eol_length;
11605 parser->
current.end = breakpoint + 1;
11608 if (lex_mode->
as.string.
label_allowed && (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')) {
11610 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
11611 lex_mode_pop(parser);
11612 LEX(PM_TOKEN_LABEL_END);
11619 parser_flush_heredoc_end(parser);
11622 lex_state_set(parser, PM_LEX_STATE_END);
11623 lex_mode_pop(parser);
11624 LEX(PM_TOKEN_STRING_END);
11627 switch (*breakpoint) {
11630 parser->
current.end = breakpoint + 1;
11631 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11634 if (peek_at(parser, breakpoint + 1) !=
'\n') {
11635 parser->
current.end = breakpoint + 1;
11636 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11643 parser->
current.end = breakpoint;
11644 pm_token_buffer_escape(parser, &token_buffer);
11645 token_buffer.
cursor = breakpoint;
11654 pm_newline_list_append(&parser->
newline_list, breakpoint);
11655 parser->
current.end = breakpoint + 1;
11656 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11660 parser->
current.end = breakpoint + 1;
11661 parser_flush_heredoc_end(parser);
11662 pm_token_buffer_flush(parser, &token_buffer);
11663 LEX(PM_TOKEN_STRING_CONTENT);
11666 parser->
current.end = breakpoint + 1;
11675 pm_token_buffer_escape(parser, &token_buffer);
11676 uint8_t peeked = peek(parser);
11680 pm_token_buffer_push_byte(&token_buffer,
'\\');
11685 if (peek(parser) !=
'\n') {
11687 pm_token_buffer_push_byte(&token_buffer,
'\\');
11689 pm_token_buffer_push_byte(&token_buffer,
'\r');
11695 pm_token_buffer_push_byte(&token_buffer,
'\\');
11696 pm_token_buffer_push_byte(&token_buffer,
'\n');
11703 parser_flush_heredoc_end(parser);
11704 pm_token_buffer_copy(parser, &token_buffer);
11705 LEX(PM_TOKEN_STRING_CONTENT);
11715 pm_token_buffer_push_byte(&token_buffer, peeked);
11718 pm_token_buffer_push_byte(&token_buffer, peeked);
11721 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
11723 pm_token_buffer_push_byte(&token_buffer,
'\\');
11724 pm_token_buffer_push_escaped(&token_buffer, parser);
11731 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11735 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11737 if (
type == PM_TOKEN_NOT_PROVIDED) {
11742 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11746 if (
type == PM_TOKEN_STRING_CONTENT) {
11747 pm_token_buffer_flush(parser, &token_buffer);
11753 assert(
false &&
"unreachable");
11758 pm_token_buffer_flush(parser, &token_buffer);
11759 LEX(PM_TOKEN_STRING_CONTENT);
11765 pm_token_buffer_flush(parser, &token_buffer);
11766 LEX(PM_TOKEN_STRING_CONTENT);
11768 case PM_LEX_HEREDOC: {
11795 lex_state_set(parser, PM_LEX_STATE_END);
11796 lex_mode_pop(parser);
11797 LEX(PM_TOKEN_HEREDOC_END);
11800 const uint8_t *ident_start = heredoc_lex_mode->
ident_start;
11805 if (current_token_starts_line(parser)) {
11806 const uint8_t *start = parser->
current.start;
11808 if (!line_continuation && (start + ident_length <= parser->end)) {
11809 const uint8_t *newline = next_newline(start, parser->
end - start);
11810 const uint8_t *ident_end = newline;
11811 const uint8_t *terminator_end = newline;
11813 if (newline == NULL) {
11814 terminator_end = parser->
end;
11815 ident_end = parser->
end;
11818 if (newline[-1] ==
'\r') {
11823 const uint8_t *terminator_start = ident_end - ident_length;
11824 const uint8_t *cursor = start;
11826 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
11827 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
11833 (cursor == terminator_start) &&
11834 (memcmp(terminator_start, ident_start, ident_length) == 0)
11836 if (newline != NULL) {
11837 pm_newline_list_append(&parser->
newline_list, newline);
11840 parser->
current.end = terminator_end;
11848 lex_state_set(parser, PM_LEX_STATE_END);
11849 lex_mode_pop(parser);
11850 LEX(PM_TOKEN_HEREDOC_END);
11854 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, heredoc_lex_mode->
indent);
11856 heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE &&
11859 peek_at(parser, start) !=
'\n'
11868 uint8_t breakpoints[] =
"\r\n\\#";
11871 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
11872 breakpoints[3] =
'\0';
11875 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11877 bool was_line_continuation =
false;
11879 while (breakpoint != NULL) {
11880 switch (*breakpoint) {
11883 parser->
current.end = breakpoint + 1;
11884 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11887 parser->
current.end = breakpoint + 1;
11889 if (peek_at(parser, breakpoint + 1) !=
'\n') {
11890 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11897 pm_token_buffer_escape(parser, &token_buffer);
11898 token_buffer.
cursor = breakpoint;
11903 parser_flush_heredoc_end(parser);
11904 parser->
current.end = breakpoint + 1;
11905 pm_token_buffer_flush(parser, &token_buffer);
11906 LEX(PM_TOKEN_STRING_CONTENT);
11909 pm_newline_list_append(&parser->
newline_list, breakpoint);
11913 const uint8_t *start = breakpoint + 1;
11915 if (!was_line_continuation && (start + ident_length <= parser->end)) {
11918 const uint8_t *newline = next_newline(start, parser->
end - start);
11920 if (newline == NULL) {
11921 newline = parser->
end;
11922 }
else if (newline[-1] ==
'\r') {
11927 const uint8_t *terminator_start = newline - ident_length;
11931 const uint8_t *cursor = start;
11933 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
11934 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
11940 cursor == terminator_start &&
11941 (memcmp(terminator_start, ident_start, ident_length) == 0)
11943 parser->
current.end = breakpoint + 1;
11944 pm_token_buffer_flush(parser, &token_buffer);
11945 LEX(PM_TOKEN_STRING_CONTENT);
11949 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->
as.heredoc.
base.
indent);
11956 if (lex_mode->
as.heredoc.
base.
indent == PM_HEREDOC_INDENT_TILDE) {
11961 parser->
current.end = breakpoint + 1;
11962 pm_token_buffer_flush(parser, &token_buffer);
11963 LEX(PM_TOKEN_STRING_CONTENT);
11968 parser->
current.end = breakpoint + 1;
11969 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11979 parser->
current.end = breakpoint + 1;
11988 pm_token_buffer_escape(parser, &token_buffer);
11989 uint8_t peeked = peek(parser);
11991 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
11995 if (peek(parser) !=
'\n') {
11996 pm_token_buffer_push_byte(&token_buffer,
'\\');
11997 pm_token_buffer_push_byte(&token_buffer,
'\r');
12002 pm_token_buffer_push_byte(&token_buffer,
'\\');
12003 pm_token_buffer_push_byte(&token_buffer,
'\n');
12005 breakpoint = parser->
current.end;
12008 pm_token_buffer_push_byte(&token_buffer,
'\\');
12009 pm_token_buffer_push_escaped(&token_buffer, parser);
12016 if (peek(parser) !=
'\n') {
12017 pm_token_buffer_push_byte(&token_buffer,
'\r');
12025 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12026 const uint8_t *end = parser->
current.end;
12031 parser->
current.end = breakpoint;
12032 pm_token_buffer_flush(parser, &token_buffer);
12036 parser->
current.end = end + 1;
12038 LEX(PM_TOKEN_STRING_CONTENT);
12041 was_line_continuation =
true;
12043 breakpoint = parser->
current.end;
12046 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12052 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12056 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12058 if (
type == PM_TOKEN_NOT_PROVIDED) {
12064 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12068 if (
type == PM_TOKEN_STRING_CONTENT) {
12069 pm_token_buffer_flush(parser, &token_buffer);
12075 assert(
false &&
"unreachable");
12078 was_line_continuation =
false;
12083 pm_token_buffer_flush(parser, &token_buffer);
12084 LEX(PM_TOKEN_STRING_CONTENT);
12090 pm_token_buffer_flush(parser, &token_buffer);
12091 LEX(PM_TOKEN_STRING_CONTENT);
12095 assert(
false &&
"unreachable");
12113 PM_BINDING_POWER_UNSET = 0,
12114 PM_BINDING_POWER_STATEMENT = 2,
12115 PM_BINDING_POWER_MODIFIER_RESCUE = 4,
12116 PM_BINDING_POWER_MODIFIER = 6,
12117 PM_BINDING_POWER_COMPOSITION = 8,
12118 PM_BINDING_POWER_NOT = 10,
12119 PM_BINDING_POWER_MATCH = 12,
12120 PM_BINDING_POWER_DEFINED = 14,
12121 PM_BINDING_POWER_MULTI_ASSIGNMENT = 16,
12122 PM_BINDING_POWER_ASSIGNMENT = 18,
12123 PM_BINDING_POWER_TERNARY = 20,
12124 PM_BINDING_POWER_RANGE = 22,
12125 PM_BINDING_POWER_LOGICAL_OR = 24,
12126 PM_BINDING_POWER_LOGICAL_AND = 26,
12127 PM_BINDING_POWER_EQUALITY = 28,
12128 PM_BINDING_POWER_COMPARISON = 30,
12129 PM_BINDING_POWER_BITWISE_OR = 32,
12130 PM_BINDING_POWER_BITWISE_AND = 34,
12131 PM_BINDING_POWER_SHIFT = 36,
12132 PM_BINDING_POWER_TERM = 38,
12133 PM_BINDING_POWER_FACTOR = 40,
12134 PM_BINDING_POWER_UMINUS = 42,
12135 PM_BINDING_POWER_EXPONENT = 44,
12136 PM_BINDING_POWER_UNARY = 46,
12137 PM_BINDING_POWER_INDEX = 48,
12138 PM_BINDING_POWER_CALL = 50,
12139 PM_BINDING_POWER_MAX = 52
12140} pm_binding_power_t;
12163#define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true, false }
12164#define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, false }
12165#define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true, false }
12166#define NON_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, true }
12167#define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false, false }
12171 [PM_TOKEN_KEYWORD_RESCUE_MODIFIER] = { PM_BINDING_POWER_MODIFIER_RESCUE, PM_BINDING_POWER_COMPOSITION,
true,
false },
12174 [PM_TOKEN_KEYWORD_IF_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12175 [PM_TOKEN_KEYWORD_UNLESS_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12176 [PM_TOKEN_KEYWORD_UNTIL_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12177 [PM_TOKEN_KEYWORD_WHILE_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12180 [PM_TOKEN_KEYWORD_AND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
12181 [PM_TOKEN_KEYWORD_OR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
12184 [PM_TOKEN_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
12185 [PM_TOKEN_KEYWORD_IN] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
12188 [PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
12189 [PM_TOKEN_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
12190 [PM_TOKEN_CARET_EQUAL] = BINDING_POWER_ASSIGNMENT,
12191 [PM_TOKEN_EQUAL] = BINDING_POWER_ASSIGNMENT,
12192 [PM_TOKEN_GREATER_GREATER_EQUAL] = BINDING_POWER_ASSIGNMENT,
12193 [PM_TOKEN_LESS_LESS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12194 [PM_TOKEN_MINUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12195 [PM_TOKEN_PERCENT_EQUAL] = BINDING_POWER_ASSIGNMENT,
12196 [PM_TOKEN_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
12197 [PM_TOKEN_PIPE_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
12198 [PM_TOKEN_PLUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12199 [PM_TOKEN_SLASH_EQUAL] = BINDING_POWER_ASSIGNMENT,
12200 [PM_TOKEN_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
12201 [PM_TOKEN_STAR_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
12204 [PM_TOKEN_QUESTION_MARK] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_TERNARY),
12207 [PM_TOKEN_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
12208 [PM_TOKEN_DOT_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
12209 [PM_TOKEN_UDOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
12210 [PM_TOKEN_UDOT_DOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
12213 [PM_TOKEN_PIPE_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_OR),
12216 [PM_TOKEN_AMPERSAND_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_AND),
12219 [PM_TOKEN_BANG_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12220 [PM_TOKEN_BANG_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12221 [PM_TOKEN_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12222 [PM_TOKEN_EQUAL_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12223 [PM_TOKEN_EQUAL_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12224 [PM_TOKEN_LESS_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12227 [PM_TOKEN_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12228 [PM_TOKEN_GREATER_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12229 [PM_TOKEN_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12230 [PM_TOKEN_LESS_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12233 [PM_TOKEN_CARET] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12234 [PM_TOKEN_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12237 [PM_TOKEN_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_AND),
12240 [PM_TOKEN_GREATER_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
12241 [PM_TOKEN_LESS_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
12244 [PM_TOKEN_MINUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
12245 [PM_TOKEN_PLUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
12248 [PM_TOKEN_PERCENT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12249 [PM_TOKEN_SLASH] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12250 [PM_TOKEN_STAR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12251 [PM_TOKEN_USTAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_FACTOR),
12254 [PM_TOKEN_UMINUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UMINUS),
12255 [PM_TOKEN_UMINUS_NUM] = { PM_BINDING_POWER_UMINUS, PM_BINDING_POWER_MAX,
false,
false },
12258 [PM_TOKEN_STAR_STAR] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_EXPONENT),
12259 [PM_TOKEN_USTAR_STAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12262 [PM_TOKEN_BANG] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12263 [PM_TOKEN_TILDE] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12264 [PM_TOKEN_UPLUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12267 [PM_TOKEN_BRACKET_LEFT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_INDEX),
12270 [PM_TOKEN_COLON_COLON] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
12271 [PM_TOKEN_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
12272 [PM_TOKEN_AMPERSAND_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL)
12275#undef BINDING_POWER_ASSIGNMENT
12276#undef LEFT_ASSOCIATIVE
12277#undef RIGHT_ASSOCIATIVE
12278#undef RIGHT_ASSOCIATIVE_UNARY
12292match2(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
12293 return match1(parser, type1) || match1(parser, type2);
12300match3(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3) {
12301 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3);
12308match4(
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) {
12309 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4);
12316match7(
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) {
12317 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7);
12324match8(
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) {
12325 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);
12336 if (match1(parser,
type)) {
12337 parser_lex(parser);
12348accept2(
pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
12349 if (match2(parser, type1, type2)) {
12350 parser_lex(parser);
12369 if (accept1(parser,
type))
return;
12372 pm_parser_err(parser, location, location, diag_id);
12384 if (accept2(parser, type1, type2))
return;
12387 pm_parser_err(parser, location, location, diag_id);
12398expect1_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
12399 if (match1(parser, PM_TOKEN_HEREDOC_END)) {
12400 parser_lex(parser);
12402 pm_parser_err_heredoc_term(parser, ident_start, ident_length);
12409parse_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);
12416parse_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) {
12417 pm_node_t *node = parse_expression(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
12418 pm_assert_value_expression(parser, node);
12441token_begins_expression_p(pm_token_type_t
type) {
12443 case PM_TOKEN_EQUAL_GREATER:
12444 case PM_TOKEN_KEYWORD_IN:
12448 case PM_TOKEN_BRACE_RIGHT:
12449 case PM_TOKEN_BRACKET_RIGHT:
12450 case PM_TOKEN_COLON:
12451 case PM_TOKEN_COMMA:
12452 case PM_TOKEN_EMBEXPR_END:
12454 case PM_TOKEN_LAMBDA_BEGIN:
12455 case PM_TOKEN_KEYWORD_DO:
12456 case PM_TOKEN_KEYWORD_DO_LOOP:
12457 case PM_TOKEN_KEYWORD_END:
12458 case PM_TOKEN_KEYWORD_ELSE:
12459 case PM_TOKEN_KEYWORD_ELSIF:
12460 case PM_TOKEN_KEYWORD_ENSURE:
12461 case PM_TOKEN_KEYWORD_THEN:
12462 case PM_TOKEN_KEYWORD_RESCUE:
12463 case PM_TOKEN_KEYWORD_WHEN:
12464 case PM_TOKEN_NEWLINE:
12465 case PM_TOKEN_PARENTHESIS_RIGHT:
12466 case PM_TOKEN_SEMICOLON:
12472 assert(pm_binding_powers[
type].left == PM_BINDING_POWER_UNSET);
12474 case PM_TOKEN_UAMPERSAND:
12478 case PM_TOKEN_UCOLON_COLON:
12479 case PM_TOKEN_UMINUS:
12480 case PM_TOKEN_UMINUS_NUM:
12481 case PM_TOKEN_UPLUS:
12482 case PM_TOKEN_BANG:
12483 case PM_TOKEN_TILDE:
12484 case PM_TOKEN_UDOT_DOT:
12485 case PM_TOKEN_UDOT_DOT_DOT:
12492 return pm_binding_powers[
type].
left == PM_BINDING_POWER_UNSET;
12501parse_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) {
12502 if (accept1(parser, PM_TOKEN_USTAR)) {
12504 pm_node_t *expression = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
12505 return UP(pm_splat_node_create(parser, &
operator, expression));
12508 return parse_value_expression(parser, binding_power, accepts_command_call,
false, diag_id, depth);
12512pm_node_unreference_each(
const pm_node_t *node,
void *data) {
12513 switch (PM_NODE_TYPE(node)) {
12518 case PM_BREAK_NODE:
12520 case PM_REDO_NODE: {
12524 while (index < parser->current_block_exits->size) {
12527 if (block_exit == node) {
12547 case PM_LOCAL_VARIABLE_READ_NODE:
12548 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
12552 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
12553 if (implicit_parameters->
nodes[index] == node) {
12557 if (index != implicit_parameters->
size - 1) {
12558 memmove(&implicit_parameters->
nodes[index], &implicit_parameters->
nodes[index + 1], (implicit_parameters->
size - index - 1) *
sizeof(
pm_node_t *));
12561 implicit_parameters->
size--;
12580 pm_visit_node(node, pm_node_unreference_each, parser);
12594 size_t length = constant->
length;
12595 uint8_t *name =
xcalloc(length + 1,
sizeof(uint8_t));
12596 if (name == NULL)
return;
12598 memcpy(name, constant->
start, length);
12599 name[length] =
'=';
12604 *name_field = pm_constant_pool_insert_owned(&parser->
constant_pool, name, length + 1);
12615 switch (PM_NODE_TYPE(target)) {
12616 case PM_SOURCE_ENCODING_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
12617 case PM_FALSE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
12618 case PM_SOURCE_FILE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
12619 case PM_SOURCE_LINE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
12620 case PM_NIL_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
12621 case PM_SELF_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
12622 case PM_TRUE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
12629 pm_node_destroy(parser, target);
12643 switch (PM_NODE_TYPE(target)) {
12644 case PM_MISSING_NODE:
12646 case PM_SOURCE_ENCODING_NODE:
12647 case PM_FALSE_NODE:
12648 case PM_SOURCE_FILE_NODE:
12649 case PM_SOURCE_LINE_NODE:
12652 case PM_TRUE_NODE: {
12655 return parse_unwriteable_target(parser, target);
12657 case PM_CLASS_VARIABLE_READ_NODE:
12659 target->
type = PM_CLASS_VARIABLE_TARGET_NODE;
12661 case PM_CONSTANT_PATH_NODE:
12662 if (context_def_p(parser)) {
12663 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
12667 target->
type = PM_CONSTANT_PATH_TARGET_NODE;
12670 case PM_CONSTANT_READ_NODE:
12671 if (context_def_p(parser)) {
12672 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
12676 target->
type = PM_CONSTANT_TARGET_NODE;
12679 case PM_BACK_REFERENCE_READ_NODE:
12680 case PM_NUMBERED_REFERENCE_READ_NODE:
12681 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
12683 case PM_GLOBAL_VARIABLE_READ_NODE:
12685 target->
type = PM_GLOBAL_VARIABLE_TARGET_NODE;
12687 case PM_LOCAL_VARIABLE_READ_NODE: {
12690 pm_node_unreference(parser, target);
12694 uint32_t name = cast->
name;
12695 uint32_t depth = cast->
depth;
12696 pm_locals_unread(&pm_parser_scope_find(parser, depth)->locals, name);
12699 target->
type = PM_LOCAL_VARIABLE_TARGET_NODE;
12703 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
12705 pm_node_t *node = UP(pm_local_variable_target_node_create(parser, &target->
location, name, 0));
12707 pm_node_unreference(parser, target);
12708 pm_node_destroy(parser, target);
12712 case PM_INSTANCE_VARIABLE_READ_NODE:
12714 target->
type = PM_INSTANCE_VARIABLE_TARGET_NODE;
12716 case PM_MULTI_TARGET_NODE:
12717 if (splat_parent) {
12720 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
12724 case PM_SPLAT_NODE: {
12733 case PM_CALL_NODE: {
12745 (call->
block == NULL)
12760 pm_node_destroy(parser, target);
12762 return UP(pm_local_variable_target_node_create(parser, &message_loc, name, 0));
12766 if (multiple && PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
12767 pm_parser_err_node(parser, (
const pm_node_t *) call, PM_ERR_UNEXPECTED_SAFE_NAVIGATION);
12770 parse_write_name(parser, &call->
name);
12771 return UP(pm_call_target_node_create(parser, call));
12778 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
12779 return UP(pm_index_target_node_create(parser, call));
12787 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
12798 pm_node_t *result = parse_target(parser, target, multiple,
false);
12803 !match1(parser, PM_TOKEN_EQUAL) &&
12805 !(context_p(parser,
PM_CONTEXT_PARENS) && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
12807 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
12821 if (shareable_constant != PM_SCOPE_SHAREABLE_CONSTANT_NONE) {
12822 return UP(pm_shareable_constant_node_create(parser, write, shareable_constant));
12833 switch (PM_NODE_TYPE(target)) {
12834 case PM_MISSING_NODE:
12835 pm_node_destroy(parser, value);
12837 case PM_CLASS_VARIABLE_READ_NODE: {
12839 pm_node_destroy(parser, target);
12842 case PM_CONSTANT_PATH_NODE: {
12845 if (context_def_p(parser)) {
12846 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
12849 return parse_shareable_constant_write(parser, node);
12851 case PM_CONSTANT_READ_NODE: {
12854 if (context_def_p(parser)) {
12855 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
12858 pm_node_destroy(parser, target);
12859 return parse_shareable_constant_write(parser, node);
12861 case PM_BACK_REFERENCE_READ_NODE:
12862 case PM_NUMBERED_REFERENCE_READ_NODE:
12863 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
12865 case PM_GLOBAL_VARIABLE_READ_NODE: {
12867 pm_node_destroy(parser, target);
12870 case PM_LOCAL_VARIABLE_READ_NODE: {
12876 uint32_t depth = local_read->
depth;
12877 pm_scope_t *scope = pm_parser_scope_find(parser, depth);
12880 pm_diagnostic_id_t diag_id = (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND) ? PM_ERR_EXPRESSION_NOT_WRITABLE_NUMBERED : PM_ERR_PARAMETER_NUMBERED_RESERVED;
12882 pm_node_unreference(parser, target);
12885 pm_locals_unread(&scope->
locals, name);
12886 pm_node_destroy(parser, target);
12888 return UP(pm_local_variable_write_node_create(parser, name, depth, value, &name_loc,
operator));
12890 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
12892 pm_node_t *node = UP(pm_local_variable_write_node_create(parser, name, 0, value, &target->
location,
operator));
12894 pm_node_unreference(parser, target);
12895 pm_node_destroy(parser, target);
12899 case PM_INSTANCE_VARIABLE_READ_NODE: {
12901 pm_node_destroy(parser, target);
12904 case PM_MULTI_TARGET_NODE:
12906 case PM_SPLAT_NODE: {
12914 pm_multi_target_node_targets_append(parser, multi_target, UP(splat));
12916 return UP(pm_multi_write_node_create(parser, multi_target,
operator, value));
12918 case PM_CALL_NODE: {
12930 (call->
block == NULL)
12944 pm_parser_local_add_location(parser, message.
start, message.
end, 0);
12945 pm_node_destroy(parser, target);
12948 target = UP(pm_local_variable_write_node_create(parser, constant_id, 0, value, &message,
operator));
12950 pm_refute_numbered_parameter(parser, message.
start, message.
end);
12968 pm_arguments_node_arguments_append(arguments, value);
12970 call->
equal_loc = PM_LOCATION_TOKEN_VALUE(
operator);
12972 parse_write_name(parser, &call->
name);
12973 pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
12982 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
12984 call->
arguments = pm_arguments_node_create(parser);
12987 pm_arguments_node_arguments_append(call->
arguments, value);
12991 call->
name = pm_parser_constant_id_constant(parser,
"[]=", 3);
12992 call->
equal_loc = PM_LOCATION_TOKEN_VALUE(
operator);
12996 pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
13011 pm_node_unreference(parser, value);
13012 pm_node_destroy(parser, value);
13019 pm_parser_err_token(parser,
operator, PM_ERR_WRITE_TARGET_UNEXPECTED);
13032 switch (PM_NODE_TYPE(target)) {
13033 case PM_SOURCE_ENCODING_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13034 case PM_FALSE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13035 case PM_SOURCE_FILE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13036 case PM_SOURCE_LINE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13037 case PM_NIL_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13038 case PM_SELF_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13039 case PM_TRUE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13046 pm_node_destroy(parser, target);
13061parse_targets(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13062 bool has_rest = PM_NODE_TYPE_P(first_target, PM_SPLAT_NODE);
13065 pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target,
true,
false));
13067 while (accept1(parser, PM_TOKEN_COMMA)) {
13068 if (accept1(parser, PM_TOKEN_USTAR)) {
13073 pm_parser_err_previous(parser, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
13079 if (token_begins_expression_p(parser->
current.type)) {
13080 name = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13081 name = parse_target(parser, name,
true,
true);
13084 pm_node_t *splat = UP(pm_splat_node_create(parser, &star_operator, name));
13085 pm_multi_target_node_targets_append(parser, result, splat);
13087 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
13089 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13090 target = parse_target(parser, target,
true,
false);
13092 pm_multi_target_node_targets_append(parser, result, target);
13093 context_pop(parser);
13094 }
else if (token_begins_expression_p(parser->
current.type)) {
13095 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13096 target = parse_target(parser, target,
true,
false);
13098 pm_multi_target_node_targets_append(parser, result, target);
13099 }
else if (!match1(parser, PM_TOKEN_EOF)) {
13103 pm_multi_target_node_targets_append(parser, result, rest);
13116parse_targets_validate(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13117 pm_node_t *result = parse_targets(parser, first_target, binding_power, depth);
13118 accept1(parser, PM_TOKEN_NEWLINE);
13121 if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
13122 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13135 while (accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE));
13138 if (context_terminator(context, &parser->
current))
return NULL;
13144 context_push(parser, context);
13147 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
13148 pm_statements_node_body_append(parser, statements, node,
true);
13161 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
13164 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13165 if (context_terminator(context, &parser->
current))
break;
13175 if (context_terminator(context, &parser->
current))
break;
13187 if (PM_NODE_TYPE_P(node, PM_MISSING_NODE)) {
13188 parser_lex(parser);
13194 if (match1(parser, PM_TOKEN_EOF)) {
13199 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13200 if (context_terminator(context, &parser->
current))
break;
13201 }
else if (!accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_EOF)) {
13211 context_pop(parser);
13212 bool last_value =
true;
13216 last_value =
false;
13221 pm_void_statements_check(parser, statements, last_value);
13234 if (duplicated != NULL) {
13238 pm_diagnostic_list_append_format(
13242 PM_WARN_DUPLICATED_HASH_KEY,
13260 if ((previous = pm_static_literals_add(&parser->
newline_list, parser->
start_line, literals, node,
false)) != NULL) {
13261 pm_diagnostic_list_append_format(
13265 PM_WARN_DUPLICATED_WHEN_CLAUSE,
13277 assert(PM_NODE_TYPE_P(node, PM_HASH_NODE) || PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE));
13278 bool contains_keyword_splat =
false;
13283 switch (parser->
current.type) {
13284 case PM_TOKEN_USTAR_STAR: {
13285 parser_lex(parser);
13289 if (match1(parser, PM_TOKEN_BRACE_LEFT)) {
13295 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
13296 }
else if (token_begins_expression_p(parser->
current.type)) {
13297 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
13299 pm_parser_scope_forwarding_keywords_check(parser, &
operator);
13302 element = UP(pm_assoc_splat_node_create(parser, value, &
operator));
13303 contains_keyword_splat =
true;
13306 case PM_TOKEN_LABEL: {
13308 parser_lex(parser);
13310 pm_node_t *key = UP(pm_symbol_node_label_create(parser, &label));
13311 pm_hash_key_static_literals_add(parser, literals, key);
13316 if (token_begins_expression_p(parser->
current.type)) {
13317 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_EXPRESSION_AFTER_LABEL, (uint16_t) (depth + 1));
13320 pm_token_t constant = { .type = PM_TOKEN_CONSTANT, .start = label.
start, .end = label.
end - 1 };
13321 value = UP(pm_constant_read_node_create(parser, &constant));
13326 if (identifier.
end[-1] ==
'!' || identifier.
end[-1] ==
'?') {
13327 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, identifier, PM_ERR_INVALID_LOCAL_VARIABLE_READ);
13329 depth = pm_parser_local_depth(parser, &identifier);
13333 value = UP(pm_call_node_variable_call_create(parser, &identifier));
13335 value = UP(pm_local_variable_read_node_create(parser, &identifier, (uint32_t) depth));
13340 value = UP(pm_implicit_node_create(parser, value));
13343 element = UP(pm_assoc_node_create(parser, key, &
operator, value));
13347 pm_node_t *key = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_HASH_KEY, (uint16_t) (depth + 1));
13351 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
13352 pm_node_flag_set(key, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
13355 pm_hash_key_static_literals_add(parser, literals, key);
13358 if (pm_symbol_node_label_p(key)) {
13359 operator = not_provided(parser);
13361 expect1(parser, PM_TOKEN_EQUAL_GREATER, PM_ERR_HASH_ROCKET);
13365 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
13366 element = UP(pm_assoc_node_create(parser, key, &
operator, value));
13371 if (PM_NODE_TYPE_P(node, PM_HASH_NODE)) {
13378 if (!accept1(parser, PM_TOKEN_COMMA))
break;
13382 if (match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL))
continue;
13386 if (token_begins_expression_p(parser->
current.type))
continue;
13392 return contains_keyword_splat;
13401 arguments->
arguments = pm_arguments_node_create(parser);
13404 pm_arguments_node_arguments_append(arguments->
arguments, argument);
13411parse_arguments(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_forwarding, pm_token_type_t terminator, uint16_t depth) {
13412 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].
left;
13417 match2(parser, terminator, PM_TOKEN_EOF) ||
13418 (binding_power != PM_BINDING_POWER_UNSET && binding_power < PM_BINDING_POWER_RANGE) ||
13424 bool parsed_first_argument =
false;
13425 bool parsed_bare_hash =
false;
13426 bool parsed_block_argument =
false;
13427 bool parsed_forwarding_arguments =
false;
13429 while (!match1(parser, PM_TOKEN_EOF)) {
13430 if (parsed_forwarding_arguments) {
13431 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES);
13436 switch (parser->
current.type) {
13437 case PM_TOKEN_USTAR_STAR:
13438 case PM_TOKEN_LABEL: {
13439 if (parsed_bare_hash) {
13440 pm_parser_err_current(parser, PM_ERR_ARGUMENT_BARE_HASH);
13444 argument = UP(hash);
13447 bool contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(hash), (uint16_t) (depth + 1));
13449 parse_arguments_append(parser, arguments, argument);
13451 pm_node_flags_t flags = PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
13452 if (contains_keyword_splat) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
13453 pm_node_flag_set(UP(arguments->
arguments), flags);
13455 pm_static_literals_free(&hash_keys);
13456 parsed_bare_hash =
true;
13460 case PM_TOKEN_UAMPERSAND: {
13461 parser_lex(parser);
13465 if (token_begins_expression_p(parser->
current.type)) {
13466 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
13468 pm_parser_scope_forwarding_block_check(parser, &
operator);
13471 argument = UP(pm_block_argument_node_create(parser, &
operator, expression));
13472 if (parsed_block_argument) {
13473 parse_arguments_append(parser, arguments, argument);
13475 arguments->
block = argument;
13478 if (match1(parser, PM_TOKEN_COMMA)) {
13479 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK);
13482 parsed_block_argument =
true;
13485 case PM_TOKEN_USTAR: {
13486 parser_lex(parser);
13489 if (match4(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_SEMICOLON, PM_TOKEN_BRACKET_RIGHT)) {
13490 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
13491 argument = UP(pm_splat_node_create(parser, &
operator, NULL));
13492 if (parsed_bare_hash) {
13493 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
13496 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT, (uint16_t) (depth + 1));
13498 if (parsed_bare_hash) {
13499 pm_parser_err(parser,
operator.start, expression->
location.
end, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
13502 argument = UP(pm_splat_node_create(parser, &
operator, expression));
13505 parse_arguments_append(parser, arguments, argument);
13508 case PM_TOKEN_UDOT_DOT_DOT: {
13509 if (accepts_forwarding) {
13510 parser_lex(parser);
13512 if (token_begins_expression_p(parser->
current.type)) {
13517 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_RANGE,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
13522 if (PM_NODE_TYPE_P(right, PM_RANGE_NODE)) {
13524 pm_parser_err(parser, range->operator_loc.start, range->operator_loc.end, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
13527 argument = UP(pm_range_node_create(parser, NULL, &
operator, right));
13529 pm_parser_scope_forwarding_all_check(parser, &parser->
previous);
13530 if (parsed_first_argument && terminator == PM_TOKEN_EOF) {
13531 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORWARDING_UNBOUND);
13534 argument = UP(pm_forwarding_arguments_node_create(parser, &parser->
previous));
13535 parse_arguments_append(parser, arguments, argument);
13536 pm_node_flag_set(UP(arguments->
arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING);
13538 parsed_forwarding_arguments =
true;
13545 if (argument == NULL) {
13546 argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, !parsed_first_argument,
true, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
13549 bool contains_keywords =
false;
13550 bool contains_keyword_splat =
false;
13552 if (pm_symbol_node_label_p(argument) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
13553 if (parsed_bare_hash) {
13554 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
13558 if (parser->
previous.
type == PM_TOKEN_EQUAL_GREATER) {
13561 operator = not_provided(parser);
13565 contains_keywords =
true;
13569 pm_hash_key_static_literals_add(parser, &hash_keys, argument);
13572 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
13573 argument = UP(pm_assoc_node_create(parser, argument, &
operator, value));
13575 pm_keyword_hash_node_elements_append(bare_hash, argument);
13576 argument = UP(bare_hash);
13579 if (accept1(parser, PM_TOKEN_COMMA) && (
13580 token_begins_expression_p(parser->
current.type) ||
13581 match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL)
13583 contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(bare_hash), (uint16_t) (depth + 1));
13586 pm_static_literals_free(&hash_keys);
13587 parsed_bare_hash =
true;
13590 parse_arguments_append(parser, arguments, argument);
13592 pm_node_flags_t flags = 0;
13593 if (contains_keywords) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
13594 if (contains_keyword_splat) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
13595 pm_node_flag_set(UP(arguments->
arguments), flags);
13601 parsed_first_argument =
true;
13604 if (PM_NODE_TYPE_P(argument, PM_MISSING_NODE) || parser->
recovering)
break;
13609 bool accepted_newline =
false;
13610 if (terminator != PM_TOKEN_EOF) {
13611 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
13614 if (parser->
previous.
type == PM_TOKEN_COMMA && parsed_bare_hash) {
13618 }
else if (accept1(parser, PM_TOKEN_COMMA)) {
13621 if (accepted_newline) {
13622 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
13628 if (PM_NODE_TYPE_P(argument, PM_CALL_NODE)) {
13631 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
13643 if (match1(parser, terminator))
break;
13658parse_required_destructured_parameter(
pm_parser_t *parser) {
13659 expect1(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_ERR_EXPECT_LPAREN_REQ_PARAMETER);
13662 pm_multi_target_node_opening_set(node, &parser->
previous);
13671 if (node->
lefts.
size > 0 && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
13672 param = UP(pm_implicit_rest_node_create(parser, &parser->
previous));
13673 pm_multi_target_node_targets_append(parser, node, param);
13674 pm_parser_err_current(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
13678 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
13679 param = UP(parse_required_destructured_parameter(parser));
13680 }
else if (accept1(parser, PM_TOKEN_USTAR)) {
13684 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
13686 value = UP(pm_required_parameter_node_create(parser, &name));
13687 if (pm_parser_parameter_name_check(parser, &name)) {
13688 pm_node_flag_set_repeated_parameter(value);
13690 pm_parser_local_add_token(parser, &name, 1);
13693 param = UP(pm_splat_node_create(parser, &star, value));
13695 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EXPECT_IDENT_REQ_PARAMETER);
13698 param = UP(pm_required_parameter_node_create(parser, &name));
13699 if (pm_parser_parameter_name_check(parser, &name)) {
13700 pm_node_flag_set_repeated_parameter(param);
13702 pm_parser_local_add_token(parser, &name, 1);
13705 pm_multi_target_node_targets_append(parser, node, param);
13706 }
while (accept1(parser, PM_TOKEN_COMMA));
13708 accept1(parser, PM_TOKEN_NEWLINE);
13709 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN_REQ_PARAMETER);
13710 pm_multi_target_node_closing_set(node, &parser->
previous);
13720 PM_PARAMETERS_NO_CHANGE = 0,
13721 PM_PARAMETERS_ORDER_NOTHING_AFTER = 1,
13722 PM_PARAMETERS_ORDER_KEYWORDS_REST,
13723 PM_PARAMETERS_ORDER_KEYWORDS,
13724 PM_PARAMETERS_ORDER_REST,
13725 PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
13726 PM_PARAMETERS_ORDER_OPTIONAL,
13727 PM_PARAMETERS_ORDER_NAMED,
13728 PM_PARAMETERS_ORDER_NONE,
13729} pm_parameters_order_t;
13734static pm_parameters_order_t parameters_ordering[PM_TOKEN_MAXIMUM] = {
13735 [0] = PM_PARAMETERS_NO_CHANGE,
13736 [PM_TOKEN_UAMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
13737 [PM_TOKEN_AMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
13738 [PM_TOKEN_UDOT_DOT_DOT] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
13739 [PM_TOKEN_IDENTIFIER] = PM_PARAMETERS_ORDER_NAMED,
13740 [PM_TOKEN_PARENTHESIS_LEFT] = PM_PARAMETERS_ORDER_NAMED,
13741 [PM_TOKEN_EQUAL] = PM_PARAMETERS_ORDER_OPTIONAL,
13742 [PM_TOKEN_LABEL] = PM_PARAMETERS_ORDER_KEYWORDS,
13743 [PM_TOKEN_USTAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
13744 [PM_TOKEN_STAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
13745 [PM_TOKEN_USTAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST,
13746 [PM_TOKEN_STAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST
13758 pm_parameters_order_t state = parameters_ordering[token->type];
13759 if (state == PM_PARAMETERS_NO_CHANGE)
return true;
13763 if (*current == PM_PARAMETERS_ORDER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
13764 *current = PM_PARAMETERS_ORDER_AFTER_OPTIONAL;
13766 }
else if (*current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
13770 if (token->type == PM_TOKEN_USTAR && *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
13771 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_STAR);
13773 }
else if (token->type == PM_TOKEN_UDOT_DOT_DOT && (*current >= PM_PARAMETERS_ORDER_KEYWORDS_REST && *current <= PM_PARAMETERS_ORDER_AFTER_OPTIONAL)) {
13774 pm_parser_err_token(parser, token, *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL ? PM_ERR_PARAMETER_FORWARDING_AFTER_REST : PM_ERR_PARAMETER_ORDER);
13776 }
else if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
13778 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_ORDER);
13782 if (state < *current) *current = state;
13792 pm_binding_power_t binding_power,
13793 bool uses_parentheses,
13794 bool allows_trailing_comma,
13795 bool allows_forwarding_parameters,
13796 bool accepts_blocks_in_defaults,
13800 pm_do_loop_stack_push(parser,
false);
13803 pm_parameters_order_t order = PM_PARAMETERS_ORDER_NONE;
13806 bool parsing =
true;
13808 switch (parser->
current.type) {
13809 case PM_TOKEN_PARENTHESIS_LEFT: {
13810 update_parameter_state(parser, &parser->
current, &order);
13811 pm_node_t *param = UP(parse_required_destructured_parameter(parser));
13813 if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
13814 pm_parameters_node_requireds_append(params, param);
13816 pm_parameters_node_posts_append(params, param);
13820 case PM_TOKEN_UAMPERSAND:
13821 case PM_TOKEN_AMPERSAND: {
13822 update_parameter_state(parser, &parser->
current, &order);
13823 parser_lex(parser);
13828 bool repeated =
false;
13829 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
13831 repeated = pm_parser_parameter_name_check(parser, &name);
13832 pm_parser_local_add_token(parser, &name, 1);
13834 name = not_provided(parser);
13840 pm_node_flag_set_repeated_parameter(UP(param));
13842 if (params->
block == NULL) {
13843 pm_parameters_node_block_set(params, param);
13845 pm_parser_err_node(parser, UP(param), PM_ERR_PARAMETER_BLOCK_MULTI);
13846 pm_parameters_node_posts_append(params, UP(param));
13851 case PM_TOKEN_UDOT_DOT_DOT: {
13852 if (!allows_forwarding_parameters) {
13853 pm_parser_err_current(parser, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
13856 bool succeeded = update_parameter_state(parser, &parser->
current, &order);
13857 parser_lex(parser);
13866 pm_parameters_node_posts_append(params, keyword_rest);
13867 if (succeeded) pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD);
13871 pm_parameters_node_keyword_rest_set(params, UP(param));
13874 case PM_TOKEN_CLASS_VARIABLE:
13875 case PM_TOKEN_IDENTIFIER:
13876 case PM_TOKEN_CONSTANT:
13877 case PM_TOKEN_INSTANCE_VARIABLE:
13878 case PM_TOKEN_GLOBAL_VARIABLE:
13879 case PM_TOKEN_METHOD_NAME: {
13880 parser_lex(parser);
13882 case PM_TOKEN_CONSTANT:
13883 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
13885 case PM_TOKEN_INSTANCE_VARIABLE:
13886 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
13888 case PM_TOKEN_GLOBAL_VARIABLE:
13889 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
13891 case PM_TOKEN_CLASS_VARIABLE:
13892 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
13894 case PM_TOKEN_METHOD_NAME:
13895 pm_parser_err_previous(parser, PM_ERR_PARAMETER_METHOD_NAME);
13900 if (parser->
current.type == PM_TOKEN_EQUAL) {
13901 update_parameter_state(parser, &parser->
current, &order);
13903 update_parameter_state(parser, &parser->
previous, &order);
13907 bool repeated = pm_parser_parameter_name_check(parser, &name);
13908 pm_parser_local_add_token(parser, &name, 1);
13910 if (match1(parser, PM_TOKEN_EQUAL)) {
13913 parser_lex(parser);
13918 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
13919 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
13920 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
13925 pm_node_flag_set_repeated_parameter(UP(param));
13927 pm_parameters_node_optionals_append(params, param);
13933 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, name, PM_ERR_PARAMETER_CIRCULAR);
13936 context_pop(parser);
13945 }
else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
13948 pm_node_flag_set_repeated_parameter(UP(param));
13950 pm_parameters_node_requireds_append(params, UP(param));
13954 pm_node_flag_set_repeated_parameter(UP(param));
13956 pm_parameters_node_posts_append(params, UP(param));
13961 case PM_TOKEN_LABEL: {
13962 if (!uses_parentheses && !in_block) parser->
in_keyword_arg =
true;
13963 update_parameter_state(parser, &parser->
current, &order);
13966 parser_lex(parser);
13973 pm_parser_err(parser, local.
start, local.
end, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
13974 }
else if (local.
end[-1] ==
'!' || local.
end[-1] ==
'?') {
13975 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
13978 bool repeated = pm_parser_parameter_name_check(parser, &local);
13979 pm_parser_local_add_token(parser, &local, 1);
13981 switch (parser->
current.type) {
13982 case PM_TOKEN_COMMA:
13983 case PM_TOKEN_PARENTHESIS_RIGHT:
13984 case PM_TOKEN_PIPE: {
13985 context_pop(parser);
13987 pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
13989 pm_node_flag_set_repeated_parameter(param);
13992 pm_parameters_node_keywords_append(params, param);
13995 case PM_TOKEN_SEMICOLON:
13996 case PM_TOKEN_NEWLINE: {
13997 context_pop(parser);
13999 if (uses_parentheses) {
14004 pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14006 pm_node_flag_set_repeated_parameter(param);
14009 pm_parameters_node_keywords_append(params, param);
14015 if (token_begins_expression_p(parser->
current.type)) {
14019 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14020 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT_KW, (uint16_t) (depth + 1));
14021 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14024 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_PARAMETER_CIRCULAR);
14027 param = UP(pm_optional_keyword_parameter_node_create(parser, &name, value));
14030 param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14034 pm_node_flag_set_repeated_parameter(param);
14037 context_pop(parser);
14038 pm_parameters_node_keywords_append(params, param);
14053 case PM_TOKEN_USTAR:
14054 case PM_TOKEN_STAR: {
14055 update_parameter_state(parser, &parser->
current, &order);
14056 parser_lex(parser);
14060 bool repeated =
false;
14062 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14064 repeated = pm_parser_parameter_name_check(parser, &name);
14065 pm_parser_local_add_token(parser, &name, 1);
14067 name = not_provided(parser);
14071 pm_node_t *param = UP(pm_rest_parameter_node_create(parser, &
operator, &name));
14073 pm_node_flag_set_repeated_parameter(param);
14076 if (params->
rest == NULL) {
14077 pm_parameters_node_rest_set(params, param);
14079 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_SPLAT_MULTI);
14080 pm_parameters_node_posts_append(params, param);
14085 case PM_TOKEN_STAR_STAR:
14086 case PM_TOKEN_USTAR_STAR: {
14087 pm_parameters_order_t previous_order = order;
14088 update_parameter_state(parser, &parser->
current, &order);
14089 parser_lex(parser);
14094 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
14095 if (previous_order <= PM_PARAMETERS_ORDER_KEYWORDS) {
14096 pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_NO_KW);
14099 param = UP(pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous));
14103 bool repeated =
false;
14104 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14106 repeated = pm_parser_parameter_name_check(parser, &name);
14107 pm_parser_local_add_token(parser, &name, 1);
14109 name = not_provided(parser);
14113 param = UP(pm_keyword_rest_parameter_node_create(parser, &
operator, &name));
14115 pm_node_flag_set_repeated_parameter(param);
14120 pm_parameters_node_keyword_rest_set(params, param);
14122 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI);
14123 pm_parameters_node_posts_append(params, param);
14130 if (allows_trailing_comma && order >= PM_PARAMETERS_ORDER_NAMED) {
14133 pm_node_t *param = UP(pm_implicit_rest_node_create(parser, &parser->
previous));
14135 if (params->
rest == NULL) {
14136 pm_parameters_node_rest_set(params, param);
14138 pm_parser_err_node(parser, UP(param), PM_ERR_PARAMETER_SPLAT_MULTI);
14139 pm_parameters_node_posts_append(params, UP(param));
14142 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14153 if (!parsing)
break;
14155 bool accepted_newline =
false;
14156 if (uses_parentheses) {
14157 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
14160 if (accept1(parser, PM_TOKEN_COMMA)) {
14163 if (accepted_newline) {
14164 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14172 pm_do_loop_stack_pop(parser);
14176 pm_node_destroy(parser, UP(params));
14208token_column(
const pm_parser_t *parser,
size_t newline_index,
const pm_token_t *token,
bool break_on_non_space) {
14210 const uint8_t *end = token->start;
14214 newline_index == 0 &&
14215 parser->
start[0] == 0xef &&
14216 parser->
start[1] == 0xbb &&
14217 parser->
start[2] == 0xbf
14220 int64_t column = 0;
14221 for (; cursor < end; cursor++) {
14224 column = ((column / PM_TAB_WHITESPACE_SIZE) + 1) * PM_TAB_WHITESPACE_SIZE;
14231 if (break_on_non_space)
return -1;
14244parser_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) {
14249 size_t closing_newline_index = token_newline_index(parser);
14250 if (opening_newline_index == closing_newline_index)
return;
14255 int64_t opening_column = token_column(parser, opening_newline_index, opening_token, !if_after_else);
14256 if (!if_after_else && (opening_column == -1))
return;
14263 int64_t closing_column = token_column(parser, closing_newline_index, closing_token,
true);
14264 if ((closing_column == -1) || (opening_column == closing_column))
return;
14268 if (allow_indent && (closing_column > opening_column))
return;
14271 PM_PARSER_WARN_FORMAT(
14273 closing_token->
start,
14274 closing_token->
end,
14275 PM_WARN_INDENTATION_MISMATCH,
14276 (
int) (closing_token->
end - closing_token->
start),
14277 (
const char *) closing_token->
start,
14278 (
int) (opening_token->
end - opening_token->
start),
14279 (
const char *) opening_token->
start,
14280 ((int32_t) opening_newline_index) + parser->
start_line
14285 PM_RESCUES_BEGIN = 1,
14292} pm_rescues_type_t;
14302 while (match1(parser, PM_TOKEN_KEYWORD_RESCUE)) {
14303 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14304 parser_lex(parser);
14308 switch (parser->
current.type) {
14309 case PM_TOKEN_EQUAL_GREATER: {
14313 parser_lex(parser);
14314 pm_rescue_node_operator_set(rescue, &parser->
previous);
14316 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
14317 reference = parse_target(parser, reference,
false,
false);
14319 pm_rescue_node_reference_set(rescue, reference);
14322 case PM_TOKEN_NEWLINE:
14323 case PM_TOKEN_SEMICOLON:
14324 case PM_TOKEN_KEYWORD_THEN:
14329 if (token_begins_expression_p(parser->
current.type) || match1(parser, PM_TOKEN_USTAR)) {
14334 pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED,
false, PM_ERR_RESCUE_EXPRESSION, (uint16_t) (depth + 1));
14335 pm_rescue_node_exceptions_append(rescue, expression);
14339 if (match3(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_THEN))
break;
14343 if (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
14344 pm_rescue_node_operator_set(rescue, &parser->
previous);
14346 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
14347 reference = parse_target(parser, reference,
false,
false);
14349 pm_rescue_node_reference_set(rescue, reference);
14352 }
while (accept1(parser, PM_TOKEN_COMMA));
14357 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
14358 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
14362 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_RESCUE_TERM);
14366 if (!match3(parser, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_END)) {
14367 pm_accepts_block_stack_push(parser,
true);
14382 if (statements != NULL) pm_rescue_node_statements_set(rescue, statements);
14384 pm_accepts_block_stack_pop(parser);
14385 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14388 if (current == NULL) {
14389 pm_begin_node_rescue_clause_set(parent_node, rescue);
14391 pm_rescue_node_subsequent_set(current, rescue);
14400 if (current != NULL) {
14404 while (clause != NULL) {
14411 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
14412 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14413 opening_newline_index = token_newline_index(parser);
14415 else_keyword = parser->
current;
14416 opening = &else_keyword;
14418 parser_lex(parser);
14419 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14422 if (!match2(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_ENSURE)) {
14423 pm_accepts_block_stack_push(parser,
true);
14437 else_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
14438 pm_accepts_block_stack_pop(parser);
14440 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14443 pm_else_node_t *else_clause = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
current);
14444 pm_begin_node_else_clause_set(parent_node, else_clause);
14448 if (current == NULL) pm_parser_err_node(parser, UP(else_clause), PM_ERR_BEGIN_LONELY_ELSE);
14451 if (match1(parser, PM_TOKEN_KEYWORD_ENSURE)) {
14452 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14455 parser_lex(parser);
14456 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14459 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
14460 pm_accepts_block_stack_push(parser,
true);
14474 ensure_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
14475 pm_accepts_block_stack_pop(parser);
14477 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14480 pm_ensure_node_t *ensure_clause = pm_ensure_node_create(parser, &ensure_keyword, ensure_statements, &parser->
current);
14481 pm_begin_node_ensure_clause_set(parent_node, ensure_clause);
14484 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
14485 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14486 pm_begin_node_end_keyword_set(parent_node, &parser->
current);
14489 pm_begin_node_end_keyword_set(parent_node, &end_keyword);
14499 pm_token_t begin_keyword = not_provided(parser);
14500 pm_begin_node_t *node = pm_begin_node_create(parser, &begin_keyword, statements);
14502 parse_rescues(parser, opening_newline_index, opening, node,
type, (uint16_t) (depth + 1));
14512parse_block_parameters(
14514 bool allows_trailing_comma,
14516 bool is_lambda_literal,
14517 bool accepts_blocks_in_defaults,
14521 if (!match1(parser, PM_TOKEN_SEMICOLON)) {
14522 if (!is_lambda_literal) {
14525 parameters = parse_parameters(
14527 is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
14529 allows_trailing_comma,
14531 accepts_blocks_in_defaults,
14533 (uint16_t) (depth + 1)
14535 if (!is_lambda_literal) {
14536 context_pop(parser);
14541 if ((opening->
type != PM_TOKEN_NOT_PROVIDED)) {
14542 accept1(parser, PM_TOKEN_NEWLINE);
14544 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
14546 switch (parser->
current.type) {
14547 case PM_TOKEN_CONSTANT:
14548 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14549 parser_lex(parser);
14551 case PM_TOKEN_INSTANCE_VARIABLE:
14552 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
14553 parser_lex(parser);
14555 case PM_TOKEN_GLOBAL_VARIABLE:
14556 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
14557 parser_lex(parser);
14559 case PM_TOKEN_CLASS_VARIABLE:
14560 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
14561 parser_lex(parser);
14564 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_BLOCK_PARAM_LOCAL_VARIABLE);
14568 bool repeated = pm_parser_parameter_name_check(parser, &parser->
previous);
14569 pm_parser_local_add_token(parser, &parser->
previous, 1);
14572 if (repeated) pm_node_flag_set_repeated_parameter(UP(local));
14574 pm_block_parameters_node_append_local(block_parameters, local);
14575 }
while (accept1(parser, PM_TOKEN_COMMA));
14579 return block_parameters;
14587outer_scope_using_numbered_parameters_p(
pm_parser_t *parser) {
14589 if (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND)
return true;
14600static const char *
const pm_numbered_parameter_names[] = {
14601 "_1",
"_2",
"_3",
"_4",
"_5",
"_6",
"_7",
"_8",
"_9"
14615 if (parameters != NULL) {
14617 if (implicit_parameters->
size > 0) {
14620 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
14621 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_ORDINARY);
14622 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
14623 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_ORDINARY);
14625 assert(
false &&
"unreachable");
14634 if (implicit_parameters->
size == 0) {
14641 uint8_t numbered_parameter = 0;
14642 bool it_parameter =
false;
14644 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
14647 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
14648 if (it_parameter) {
14649 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_IT);
14650 }
else if (outer_scope_using_numbered_parameters_p(parser)) {
14651 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_OUTER_BLOCK);
14653 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK);
14655 numbered_parameter = MAX(numbered_parameter, (uint8_t) (node->
location.
start[1] -
'0'));
14657 assert(
false &&
"unreachable");
14659 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
14660 if (numbered_parameter > 0) {
14661 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_NUMBERED);
14663 it_parameter =
true;
14668 if (numbered_parameter > 0) {
14672 scope->
parameters |= PM_SCOPE_PARAMETERS_NUMBERED_INNER;
14676 return UP(pm_numbered_parameters_node_create(parser, &location, numbered_parameter));
14679 if (it_parameter) {
14680 return UP(pm_it_parameters_node_create(parser, opening, closing));
14690parse_block(
pm_parser_t *parser, uint16_t depth) {
14692 accept1(parser, PM_TOKEN_NEWLINE);
14694 pm_accepts_block_stack_push(parser,
true);
14695 pm_parser_scope_push(parser,
false);
14699 if (accept1(parser, PM_TOKEN_PIPE)) {
14701 if (match1(parser, PM_TOKEN_PIPE)) {
14702 block_parameters = pm_block_parameters_node_create(parser, NULL, &block_parameters_opening);
14704 parser_lex(parser);
14706 block_parameters = parse_block_parameters(parser,
true, &block_parameters_opening,
false,
true, (uint16_t) (depth + 1));
14707 accept1(parser, PM_TOKEN_NEWLINE);
14709 expect1(parser, PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM);
14712 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
14715 accept1(parser, PM_TOKEN_NEWLINE);
14718 if (opening.
type == PM_TOKEN_BRACE_LEFT) {
14719 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
14723 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE);
14725 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
14726 if (!match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE)) {
14727 pm_accepts_block_stack_push(parser,
true);
14729 pm_accepts_block_stack_pop(parser);
14732 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
14733 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
14734 statements = UP(parse_rescues_implicit_begin(parser, 0, NULL, opening.
start, (
pm_statements_node_t *) statements, PM_RESCUES_BLOCK, (uint16_t) (depth + 1)));
14738 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END);
14742 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
14743 pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &opening, &parser->
previous);
14745 pm_parser_scope_pop(parser);
14746 pm_accepts_block_stack_pop(parser);
14748 return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->
previous);
14757parse_arguments_list(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_block,
bool accepts_command_call, uint16_t depth) {
14758 bool found =
false;
14760 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
14764 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
14767 pm_accepts_block_stack_push(parser,
true);
14768 parse_arguments(parser, arguments, accepts_block, PM_TOKEN_PARENTHESIS_RIGHT, (uint16_t) (depth + 1));
14770 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
14776 pm_accepts_block_stack_pop(parser);
14779 }
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)) {
14781 pm_accepts_block_stack_push(parser,
false);
14786 parse_arguments(parser, arguments, accepts_block, PM_TOKEN_EOF, (uint16_t) (depth + 1));
14791 if (parser->
previous.
type == PM_TOKEN_COMMA && !match1(parser, PM_TOKEN_SEMICOLON)) {
14795 pm_accepts_block_stack_pop(parser);
14801 if (accepts_block) {
14804 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
14806 block = parse_block(parser, (uint16_t) (depth + 1));
14807 pm_arguments_validate_block(parser, arguments, block);
14808 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
14810 block = parse_block(parser, (uint16_t) (depth + 1));
14813 if (block != NULL) {
14815 arguments->
block = UP(block);
14817 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_BLOCK_MULTI);
14819 if (arguments->
block != NULL) {
14821 arguments->
arguments = pm_arguments_node_create(parser);
14823 pm_arguments_node_arguments_append(arguments->
arguments, arguments->
block);
14825 arguments->
block = UP(block);
14839 bool in_sclass =
false;
14841 switch (context_node->
context) {
14886 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
14909 assert(
false &&
"unreachable");
14914 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
14925 switch (context_node->
context) {
15000 assert(
false &&
"unreachable");
15014 return previous_block_exits;
15028 switch (PM_NODE_TYPE(block_exit)) {
15029 case PM_BREAK_NODE:
type =
"break";
break;
15030 case PM_NEXT_NODE:
type =
"next";
break;
15031 case PM_REDO_NODE:
type =
"redo";
break;
15032 default: assert(
false &&
"unreachable");
type =
"";
break;
15035 PM_PARSER_ERR_NODE_FORMAT(parser, block_exit, PM_ERR_INVALID_BLOCK_EXIT,
type);
15047 if (match2(parser, PM_TOKEN_KEYWORD_WHILE_MODIFIER, PM_TOKEN_KEYWORD_UNTIL_MODIFIER)) {
15052 }
else if (previous_block_exits != NULL) {
15064 flush_block_exits(parser, previous_block_exits);
15072 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, error_id, (uint16_t) (depth + 1));
15075 bool predicate_closed = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15077 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
15078 predicate_closed =
true;
15082 if (!predicate_closed) {
15083 pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
15086 context_pop(parser);
15091parse_conditional(
pm_parser_t *parser,
pm_context_t context,
size_t opening_newline_index,
bool if_after_else, uint16_t depth) {
15093 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
15096 pm_token_t then_keyword = not_provided(parser);
15098 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context, &then_keyword, (uint16_t) (depth + 1));
15101 if (!match3(parser, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
15102 pm_accepts_block_stack_push(parser,
true);
15103 statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15104 pm_accepts_block_stack_pop(parser);
15105 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15108 pm_token_t end_keyword = not_provided(parser);
15113 parent = UP(pm_if_node_create(parser, &keyword, predicate, &then_keyword, statements, NULL, &end_keyword));
15116 parent = UP(pm_unless_node_create(parser, &keyword, predicate, &then_keyword, statements));
15119 assert(
false &&
"unreachable");
15128 while (match1(parser, PM_TOKEN_KEYWORD_ELSIF)) {
15129 if (parser_end_of_line_p(parser)) {
15130 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
15133 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15135 parser_lex(parser);
15137 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER,
PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1));
15138 pm_accepts_block_stack_push(parser,
true);
15141 pm_accepts_block_stack_pop(parser);
15142 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15144 pm_node_t *elsif = UP(pm_if_node_create(parser, &elsif_keyword, predicate, &then_keyword, statements, NULL, &end_keyword));
15150 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
15151 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15152 opening_newline_index = token_newline_index(parser);
15154 parser_lex(parser);
15157 pm_accepts_block_stack_push(parser,
true);
15159 pm_accepts_block_stack_pop(parser);
15161 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15162 parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword,
false,
false);
15163 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE);
15165 pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
previous);
15169 ((
pm_if_node_t *) current)->subsequent = UP(else_node);
15175 assert(
false &&
"unreachable");
15179 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else,
false);
15180 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM);
15187 bool recursing =
true;
15189 while (recursing) {
15190 switch (PM_NODE_TYPE(current)) {
15194 recursing = current != NULL;
15212 assert(
false &&
"unreachable");
15216 pop_block_exits(parser, previous_block_exits);
15217 pm_node_list_free(¤t_block_exits);
15226#define PM_CASE_KEYWORD PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15227 case PM_TOKEN_KEYWORD_ALIAS: case PM_TOKEN_KEYWORD_AND: case PM_TOKEN_KEYWORD_BEGIN: case PM_TOKEN_KEYWORD_BEGIN_UPCASE: \
15228 case PM_TOKEN_KEYWORD_BREAK: case PM_TOKEN_KEYWORD_CASE: case PM_TOKEN_KEYWORD_CLASS: case PM_TOKEN_KEYWORD_DEF: \
15229 case PM_TOKEN_KEYWORD_DEFINED: case PM_TOKEN_KEYWORD_DO: case PM_TOKEN_KEYWORD_DO_LOOP: case PM_TOKEN_KEYWORD_ELSE: \
15230 case PM_TOKEN_KEYWORD_ELSIF: case PM_TOKEN_KEYWORD_END: case PM_TOKEN_KEYWORD_END_UPCASE: case PM_TOKEN_KEYWORD_ENSURE: \
15231 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD_FOR: case PM_TOKEN_KEYWORD_IF: case PM_TOKEN_KEYWORD_IN: \
15232 case PM_TOKEN_KEYWORD_MODULE: case PM_TOKEN_KEYWORD_NEXT: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_NOT: \
15233 case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_KEYWORD_REDO: case PM_TOKEN_KEYWORD_RESCUE: case PM_TOKEN_KEYWORD_RETRY: \
15234 case PM_TOKEN_KEYWORD_RETURN: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_SUPER: case PM_TOKEN_KEYWORD_THEN: \
15235 case PM_TOKEN_KEYWORD_TRUE: case PM_TOKEN_KEYWORD_UNDEF: case PM_TOKEN_KEYWORD_UNLESS: case PM_TOKEN_KEYWORD_UNTIL: \
15236 case PM_TOKEN_KEYWORD_WHEN: case PM_TOKEN_KEYWORD_WHILE: case PM_TOKEN_KEYWORD_YIELD
15242#define PM_CASE_OPERATOR PM_TOKEN_AMPERSAND: case PM_TOKEN_BACKTICK: case PM_TOKEN_BANG_EQUAL: \
15243 case PM_TOKEN_BANG_TILDE: case PM_TOKEN_BANG: case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL: \
15244 case PM_TOKEN_BRACKET_LEFT_RIGHT: case PM_TOKEN_CARET: case PM_TOKEN_EQUAL_EQUAL_EQUAL: case PM_TOKEN_EQUAL_EQUAL: \
15245 case PM_TOKEN_EQUAL_TILDE: case PM_TOKEN_GREATER_EQUAL: case PM_TOKEN_GREATER_GREATER: case PM_TOKEN_GREATER: \
15246 case PM_TOKEN_LESS_EQUAL_GREATER: case PM_TOKEN_LESS_EQUAL: case PM_TOKEN_LESS_LESS: case PM_TOKEN_LESS: \
15247 case PM_TOKEN_MINUS: case PM_TOKEN_PERCENT: case PM_TOKEN_PIPE: case PM_TOKEN_PLUS: case PM_TOKEN_SLASH: \
15248 case PM_TOKEN_STAR_STAR: case PM_TOKEN_STAR: case PM_TOKEN_TILDE: case PM_TOKEN_UAMPERSAND: case PM_TOKEN_UMINUS: \
15249 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_UPLUS: case PM_TOKEN_USTAR: case PM_TOKEN_USTAR_STAR
15256#define PM_CASE_PRIMITIVE PM_TOKEN_INTEGER: case PM_TOKEN_INTEGER_IMAGINARY: case PM_TOKEN_INTEGER_RATIONAL: \
15257 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: case PM_TOKEN_FLOAT: case PM_TOKEN_FLOAT_IMAGINARY: \
15258 case PM_TOKEN_FLOAT_RATIONAL: case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY: case PM_TOKEN_SYMBOL_BEGIN: \
15259 case PM_TOKEN_REGEXP_BEGIN: case PM_TOKEN_BACKTICK: case PM_TOKEN_PERCENT_LOWER_X: case PM_TOKEN_PERCENT_LOWER_I: \
15260 case PM_TOKEN_PERCENT_LOWER_W: case PM_TOKEN_PERCENT_UPPER_I: case PM_TOKEN_PERCENT_UPPER_W: \
15261 case PM_TOKEN_STRING_BEGIN: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_TRUE: \
15262 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15263 case PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_MINUS_GREATER: case PM_TOKEN_HEREDOC_START: \
15264 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_CHARACTER_LITERAL
15270#define PM_CASE_PARAMETER PM_TOKEN_UAMPERSAND: case PM_TOKEN_AMPERSAND: case PM_TOKEN_UDOT_DOT_DOT: \
15271 case PM_TOKEN_IDENTIFIER: case PM_TOKEN_LABEL: case PM_TOKEN_USTAR: case PM_TOKEN_STAR: case PM_TOKEN_STAR_STAR: \
15272 case PM_TOKEN_USTAR_STAR: case PM_TOKEN_CONSTANT: case PM_TOKEN_INSTANCE_VARIABLE: case PM_TOKEN_GLOBAL_VARIABLE: \
15273 case PM_TOKEN_CLASS_VARIABLE
15279#define PM_CASE_WRITABLE PM_CLASS_VARIABLE_READ_NODE: case PM_CONSTANT_PATH_NODE: \
15280 case PM_CONSTANT_READ_NODE: case PM_GLOBAL_VARIABLE_READ_NODE: case PM_LOCAL_VARIABLE_READ_NODE: \
15281 case PM_INSTANCE_VARIABLE_READ_NODE: case PM_MULTI_TARGET_NODE: case PM_BACK_REFERENCE_READ_NODE: \
15282 case PM_NUMBERED_REFERENCE_READ_NODE: case PM_IT_LOCAL_VARIABLE_READ_NODE
15286PM_STATIC_ASSERT(__LINE__, ((
int) PM_STRING_FLAGS_FORCED_UTF8_ENCODING) == ((
int) PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING),
"Expected the flags to match.");
15292static inline pm_node_flags_t
15293parse_unescaped_encoding(
const pm_parser_t *parser) {
15298 return PM_STRING_FLAGS_FORCED_UTF8_ENCODING;
15304 return PM_STRING_FLAGS_FORCED_BINARY_ENCODING;
15315parse_string_part(
pm_parser_t *parser, uint16_t depth) {
15316 switch (parser->
current.type) {
15323 case PM_TOKEN_STRING_CONTENT: {
15327 pm_node_t *node = UP(pm_string_node_create_current_string(parser, &opening, &parser->
current, &closing));
15328 pm_node_flag_set(node, parse_unescaped_encoding(parser));
15330 parser_lex(parser);
15339 case PM_TOKEN_EMBEXPR_BEGIN: {
15348 lex_state_set(parser, PM_LEX_STATE_BEG);
15349 parser_lex(parser);
15354 if (!match1(parser, PM_TOKEN_EMBEXPR_END)) {
15355 pm_accepts_block_stack_push(parser,
true);
15357 pm_accepts_block_stack_pop(parser);
15361 lex_state_set(parser, state);
15363 expect1(parser, PM_TOKEN_EMBEXPR_END, PM_ERR_EMBEXPR_END);
15369 if (statements != NULL && statements->
body.
size == 1) {
15370 pm_node_flag_unset(statements->
body.
nodes[0], PM_NODE_FLAG_NEWLINE);
15373 return UP(pm_embedded_statements_node_create(parser, &opening, statements, &closing));
15382 case PM_TOKEN_EMBVAR: {
15387 lex_state_set(parser, PM_LEX_STATE_BEG);
15388 parser_lex(parser);
15393 switch (parser->
current.type) {
15396 case PM_TOKEN_BACK_REFERENCE:
15397 parser_lex(parser);
15398 variable = UP(pm_back_reference_read_node_create(parser, &parser->
previous));
15402 case PM_TOKEN_NUMBERED_REFERENCE:
15403 parser_lex(parser);
15404 variable = UP(pm_numbered_reference_read_node_create(parser, &parser->
previous));
15408 case PM_TOKEN_GLOBAL_VARIABLE:
15409 parser_lex(parser);
15410 variable = UP(pm_global_variable_read_node_create(parser, &parser->
previous));
15414 case PM_TOKEN_INSTANCE_VARIABLE:
15415 parser_lex(parser);
15416 variable = UP(pm_instance_variable_read_node_create(parser, &parser->
previous));
15420 case PM_TOKEN_CLASS_VARIABLE:
15421 parser_lex(parser);
15422 variable = UP(pm_class_variable_read_node_create(parser, &parser->
previous));
15428 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EMBVAR_INVALID);
15429 variable = UP(pm_missing_node_create(parser, parser->
current.start, parser->
current.end));
15433 return UP(pm_embedded_variable_node_create(parser, &
operator, variable));
15436 parser_lex(parser);
15437 pm_parser_err_previous(parser, PM_ERR_CANNOT_PARSE_STRING_PART);
15447static const uint8_t *
15448parse_operator_symbol_name(
const pm_token_t *name) {
15449 switch (name->
type) {
15450 case PM_TOKEN_TILDE:
15451 case PM_TOKEN_BANG:
15452 if (name->
end[-1] ==
'@')
return name->
end - 1;
15464 const uint8_t *end = parse_operator_symbol_name(&parser->
current);
15466 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15467 parser_lex(parser);
15470 pm_node_flag_set(UP(symbol), PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING);
15484 if (lex_mode->
mode != PM_LEX_STRING) {
15485 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15487 switch (parser->
current.type) {
15488 case PM_CASE_OPERATOR:
15489 return parse_operator_symbol(parser, &opening, next_state == PM_LEX_STATE_NONE ? PM_LEX_STATE_ENDFN : next_state);
15490 case PM_TOKEN_IDENTIFIER:
15491 case PM_TOKEN_CONSTANT:
15492 case PM_TOKEN_INSTANCE_VARIABLE:
15493 case PM_TOKEN_METHOD_NAME:
15494 case PM_TOKEN_CLASS_VARIABLE:
15495 case PM_TOKEN_GLOBAL_VARIABLE:
15496 case PM_TOKEN_NUMBERED_REFERENCE:
15497 case PM_TOKEN_BACK_REFERENCE:
15498 case PM_CASE_KEYWORD:
15499 parser_lex(parser);
15502 expect2(parser, PM_TOKEN_IDENTIFIER, PM_TOKEN_METHOD_NAME, PM_ERR_SYMBOL_INVALID);
15510 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->
previous, &symbol->
unescaped,
false));
15517 if (match1(parser, PM_TOKEN_STRING_END)) {
15518 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15519 parser_lex(parser);
15523 return UP(pm_symbol_node_create(parser, &opening, &content, &closing));
15527 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
15531 if (part && PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
15532 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15533 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
15539 if (part) pm_interpolated_symbol_node_append(symbol, part);
15541 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
15542 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
15543 pm_interpolated_symbol_node_append(symbol, part);
15547 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15548 if (match1(parser, PM_TOKEN_EOF)) {
15549 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_INTERPOLATED);
15551 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
15554 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
15561 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
15564 parser_lex(parser);
15575 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
15579 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &unescaped));
15580 pm_interpolated_symbol_node_append(symbol, part);
15582 part = UP(pm_string_node_create_unescaped(parser, &bounds, &parser->
current, &bounds, &parser->
current_string));
15583 pm_interpolated_symbol_node_append(symbol, part);
15585 if (next_state != PM_LEX_STATE_NONE) {
15586 lex_state_set(parser, next_state);
15589 parser_lex(parser);
15590 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
15592 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
15597 pm_string_shared_init(&unescaped, content.
start, content.
end);
15600 if (next_state != PM_LEX_STATE_NONE) {
15601 lex_state_set(parser, next_state);
15604 if (match1(parser, PM_TOKEN_EOF)) {
15605 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_DYNAMIC);
15607 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
15610 return UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
false)));
15618parse_undef_argument(
pm_parser_t *parser, uint16_t depth) {
15619 switch (parser->
current.type) {
15620 case PM_CASE_OPERATOR: {
15621 const pm_token_t opening = not_provided(parser);
15622 return parse_operator_symbol(parser, &opening, PM_LEX_STATE_NONE);
15624 case PM_CASE_KEYWORD:
15625 case PM_TOKEN_CONSTANT:
15626 case PM_TOKEN_IDENTIFIER:
15627 case PM_TOKEN_METHOD_NAME: {
15628 parser_lex(parser);
15635 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->
previous, &symbol->
unescaped,
false));
15639 case PM_TOKEN_SYMBOL_BEGIN: {
15641 parser_lex(parser);
15643 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
15646 pm_parser_err_current(parser, PM_ERR_UNDEF_ARGUMENT);
15647 return UP(pm_missing_node_create(parser, parser->
current.start, parser->
current.end));
15658parse_alias_argument(
pm_parser_t *parser,
bool first, uint16_t depth) {
15659 switch (parser->
current.type) {
15660 case PM_CASE_OPERATOR: {
15661 const pm_token_t opening = not_provided(parser);
15662 return parse_operator_symbol(parser, &opening, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
15664 case PM_CASE_KEYWORD:
15665 case PM_TOKEN_CONSTANT:
15666 case PM_TOKEN_IDENTIFIER:
15667 case PM_TOKEN_METHOD_NAME: {
15668 if (first) lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
15669 parser_lex(parser);
15676 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->
previous, &symbol->
unescaped,
false));
15680 case PM_TOKEN_SYMBOL_BEGIN: {
15682 parser_lex(parser);
15684 return parse_symbol(parser, &lex_mode, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
15686 case PM_TOKEN_BACK_REFERENCE:
15687 parser_lex(parser);
15688 return UP(pm_back_reference_read_node_create(parser, &parser->
previous));
15689 case PM_TOKEN_NUMBERED_REFERENCE:
15690 parser_lex(parser);
15691 return UP(pm_numbered_reference_read_node_create(parser, &parser->
previous));
15692 case PM_TOKEN_GLOBAL_VARIABLE:
15693 parser_lex(parser);
15694 return UP(pm_global_variable_read_node_create(parser, &parser->
previous));
15696 pm_parser_err_current(parser, PM_ERR_ALIAS_ARGUMENT);
15697 return UP(pm_missing_node_create(parser, parser->
current.start, parser->
current.end));
15711 if (!is_numbered_param && ((depth = pm_parser_local_depth_constant_id(parser, name_id)) != -1)) {
15712 return UP(pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, (uint32_t) depth,
false));
15716 if (!current_scope->
closed && !(current_scope->
parameters & PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED)) {
15717 if (is_numbered_param) {
15722 uint8_t maximum = (uint8_t) (parser->
previous.
start[1] -
'0');
15723 for (uint8_t number = 1; number <= maximum; number++) {
15724 pm_parser_local_add_constant(parser, pm_numbered_parameter_names[number - 1], 2);
15727 if (!match1(parser, PM_TOKEN_EQUAL)) {
15731 pm_node_t *node = UP(pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, 0,
false));
15736 pm_node_t *node = UP(pm_it_local_variable_read_node_create(parser, &parser->
previous));
15751 pm_node_flags_t flags = 0;
15753 if (!match1(parser, PM_TOKEN_PARENTHESIS_LEFT) && (parser->
previous.
end[-1] !=
'!') && (parser->
previous.
end[-1] !=
'?')) {
15754 pm_node_t *node = parse_variable(parser);
15755 if (node != NULL)
return node;
15756 flags |= PM_CALL_NODE_FLAGS_VARIABLE_CALL;
15760 pm_node_flag_set(UP(node), flags);
15771parse_method_definition_name(
pm_parser_t *parser) {
15772 switch (parser->
current.type) {
15773 case PM_CASE_KEYWORD:
15774 case PM_TOKEN_CONSTANT:
15775 case PM_TOKEN_METHOD_NAME:
15776 parser_lex(parser);
15778 case PM_TOKEN_IDENTIFIER:
15779 pm_refute_numbered_parameter(parser, parser->
current.start, parser->
current.end);
15780 parser_lex(parser);
15782 case PM_CASE_OPERATOR:
15783 lex_state_set(parser, PM_LEX_STATE_ENDFN);
15784 parser_lex(parser);
15793parse_heredoc_dedent_string(
pm_string_t *
string,
size_t common_whitespace) {
15796 pm_string_ensure_owned(
string);
15802 const uint8_t *source_cursor = (uint8_t *) string->
source;
15803 const uint8_t *source_end = source_cursor + dest_length;
15808 size_t trimmed_whitespace = 0;
15814 while ((source_cursor < source_end) && pm_char_is_inline_whitespace(*source_cursor) && trimmed_whitespace < common_whitespace) {
15815 if (*source_cursor ==
'\t') {
15816 trimmed_whitespace = (trimmed_whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
15817 if (trimmed_whitespace > common_whitespace)
break;
15819 trimmed_whitespace++;
15826 memmove((uint8_t *) string->source, source_cursor, (
size_t) (source_end - source_cursor));
15827 string->length = dest_length;
15837 bool dedent_next =
true;
15842 size_t write_index = 0;
15849 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE)) {
15850 nodes->
nodes[write_index++] = node;
15851 dedent_next =
false;
15857 parse_heredoc_dedent_string(&string_node->
unescaped, common_whitespace);
15861 pm_node_destroy(parser, node);
15863 nodes->
nodes[write_index++] = node;
15867 dedent_next =
true;
15870 nodes->
size = write_index;
15877parse_strings_empty_content(
const uint8_t *location) {
15878 return (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = location, .end = location };
15886 assert(parser->
current.type == PM_TOKEN_STRING_BEGIN);
15887 bool concating =
false;
15889 while (match1(parser, PM_TOKEN_STRING_BEGIN)) {
15895 assert(lex_mode->
mode == PM_LEX_STRING);
15897 bool label_allowed = lex_mode->
as.string.
label_allowed && accepts_label;
15900 parser_lex(parser);
15902 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
15903 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
15912 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
15922 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
15923 }
else if (!lex_interpolation) {
15929 if (match1(parser, PM_TOKEN_EOF)) {
15931 content = not_provided(parser);
15934 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_EXPECT_STRING_CONTENT);
15949 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
15952 pm_token_t delimiters = not_provided(parser);
15953 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, &delimiters, &content, &delimiters, &unescaped));
15954 pm_node_list_append(&parts, part);
15957 part = UP(pm_string_node_create_current_string(parser, &delimiters, &parser->
current, &delimiters));
15958 pm_node_list_append(&parts, part);
15959 parser_lex(parser);
15960 }
while (match1(parser, PM_TOKEN_STRING_CONTENT));
15962 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
15963 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous));
15965 pm_node_list_free(&parts);
15966 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
15967 node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true)));
15968 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
15969 }
else if (match1(parser, PM_TOKEN_EOF)) {
15970 pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
15971 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped));
15972 }
else if (accept1(parser, PM_TOKEN_STRING_END)) {
15973 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped));
15978 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped));
15980 }
else if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
15987 parser_lex(parser);
15989 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
15990 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped));
15991 pm_node_flag_set(node, parse_unescaped_encoding(parser));
15997 if (!accept1(parser, PM_TOKEN_STRING_END)) {
15999 if (location > parser->
start && location[-1] ==
'\n') location--;
16000 pm_parser_err(parser, location, location, PM_ERR_STRING_LITERAL_EOF);
16005 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16006 node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true)));
16007 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16012 pm_token_t string_opening = not_provided(parser);
16013 pm_token_t string_closing = not_provided(parser);
16015 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, &string_opening, &parser->
previous, &string_closing, &unescaped));
16016 pm_node_flag_set(part, parse_unescaped_encoding(parser));
16017 pm_node_list_append(&parts, part);
16019 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16020 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16021 pm_node_list_append(&parts, part);
16025 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16026 node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous));
16027 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16028 }
else if (match1(parser, PM_TOKEN_EOF)) {
16029 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16030 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current));
16032 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16033 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous));
16036 pm_node_list_free(&parts);
16045 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16046 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16047 pm_node_list_append(&parts, part);
16051 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16052 node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous));
16053 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16054 }
else if (match1(parser, PM_TOKEN_EOF)) {
16055 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16056 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current));
16058 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16059 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous));
16062 pm_node_list_free(&parts);
16065 if (current == NULL) {
16069 if (PM_NODE_TYPE_P(node, PM_SYMBOL_NODE) || PM_NODE_TYPE_P(node, PM_INTERPOLATED_SYMBOL_NODE)) {
16080 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE) && !PM_NODE_TYPE_P(node, PM_INTERPOLATED_STRING_NODE)) {
16081 pm_parser_err_node(parser, node, PM_ERR_STRING_CONCATENATION);
16087 if (!PM_NODE_TYPE_P(current, PM_STRING_NODE) && !PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
16088 pm_parser_err_node(parser, current, PM_ERR_STRING_CONCATENATION);
16095 pm_interpolated_string_node_append(container, current);
16096 current = UP(container);
16106#define PM_PARSE_PATTERN_SINGLE 0
16107#define PM_PARSE_PATTERN_TOP 1
16108#define PM_PARSE_PATTERN_MULTI 2
16121 if (peek_at(parser, location->
start) ==
'_')
return;
16123 if (pm_constant_id_list_includes(captures, capture)) {
16124 pm_parser_err(parser, location->
start, location->
end, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
16126 pm_constant_id_list_append(captures, capture);
16137 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
16139 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
16140 node = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous));
16146 if (!match2(parser, PM_TOKEN_BRACKET_LEFT, PM_TOKEN_PARENTHESIS_LEFT)) {
16154 if (accept1(parser, PM_TOKEN_BRACKET_LEFT)) {
16156 accept1(parser, PM_TOKEN_NEWLINE);
16158 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
16159 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16160 accept1(parser, PM_TOKEN_NEWLINE);
16161 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET);
16166 parser_lex(parser);
16168 accept1(parser, PM_TOKEN_NEWLINE);
16170 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
16171 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
16172 accept1(parser, PM_TOKEN_NEWLINE);
16173 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
16182 return UP(pm_array_pattern_node_constant_create(parser, node, &opening, &closing));
16189 switch (PM_NODE_TYPE(inner)) {
16190 case PM_ARRAY_PATTERN_NODE: {
16198 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16199 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16201 return UP(pattern_node);
16206 case PM_FIND_PATTERN_NODE: {
16214 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16215 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16217 return UP(pattern_node);
16222 case PM_HASH_PATTERN_NODE: {
16230 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16231 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16233 return UP(pattern_node);
16245 pm_array_pattern_node_t *pattern_node = pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
16246 pm_array_pattern_node_requireds_append(pattern_node, inner);
16247 return UP(pattern_node);
16262 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
16264 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &identifier);
16267 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16268 pm_parser_local_add(parser, constant_id, identifier.
start, identifier.
end, 0);
16271 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&identifier));
16272 name = UP(pm_local_variable_target_node_create(
16274 &PM_LOCATION_TOKEN_VALUE(&identifier),
16276 (uint32_t) (depth == -1 ? 0 : depth)
16281 return pm_splat_node_create(parser, &
operator, name);
16289 assert(parser->
current.type == PM_TOKEN_USTAR_STAR);
16290 parser_lex(parser);
16295 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
16296 return UP(pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous));
16299 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
16303 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16307 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
16308 value = UP(pm_local_variable_target_node_create(
16310 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
16312 (uint32_t) (depth == -1 ? 0 : depth)
16316 return UP(pm_assoc_splat_node_create(parser, value, &
operator));
16324pm_slice_is_valid_local(
const pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
16325 ptrdiff_t length = end - start;
16326 if (length == 0)
return false;
16329 size_t width = char_is_identifier_start(parser, start, end - start);
16330 if (width == 0)
return false;
16336 if (pm_encoding_utf_8_isupper_char(start, length))
return false;
16341 const uint8_t *cursor = start + width;
16342 while ((width = char_is_identifier(parser, cursor, end - cursor))) cursor += width;
16343 return cursor == end;
16357 if (pm_slice_is_valid_local(parser, value_loc->
start, value_loc->
end)) {
16358 depth = pm_parser_local_depth_constant_id(parser, constant_id);
16360 pm_parser_err(parser, key->base.location.start, key->base.location.end, PM_ERR_PATTERN_HASH_KEY_LOCALS);
16362 if ((value_loc->
end > value_loc->
start) && ((value_loc->
end[-1] ==
'!') || (value_loc->
end[-1] ==
'?'))) {
16363 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);
16368 pm_parser_local_add(parser, constant_id, value_loc->
start, value_loc->
end, 0);
16371 parse_pattern_capture(parser, captures, constant_id, value_loc);
16376 (uint32_t) (depth == -1 ? 0 : depth)
16379 return UP(pm_implicit_node_create(parser, UP(target)));
16389 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
16402 switch (PM_NODE_TYPE(first_node)) {
16403 case PM_ASSOC_SPLAT_NODE:
16404 case PM_NO_KEYWORDS_PARAMETER_NODE:
16407 case PM_SYMBOL_NODE: {
16408 if (pm_symbol_node_label_p(first_node)) {
16409 parse_pattern_hash_key(parser, &keys, first_node);
16412 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)) {
16415 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) first_node);
16419 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
16423 pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, &
operator, value));
16425 pm_node_list_append(&assocs, assoc);
16434 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;
16435 pm_parser_err_node(parser, first_node, diag_id);
16439 pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, &
operator, value));
16441 pm_node_list_append(&assocs, assoc);
16447 while (accept1(parser, PM_TOKEN_COMMA)) {
16449 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)) {
16451 if (rest != NULL) {
16452 pm_parser_err_token(parser, &parser->
current, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
16458 if (match1(parser, PM_TOKEN_USTAR_STAR)) {
16459 pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures);
16461 if (rest == NULL) {
16464 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
16465 pm_node_list_append(&assocs, assoc);
16470 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
16471 key = parse_strings(parser, NULL,
true, (uint16_t) (depth + 1));
16473 if (PM_NODE_TYPE_P(key, PM_INTERPOLATED_SYMBOL_NODE)) {
16474 pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
16475 }
else if (!pm_symbol_node_label_p(key)) {
16476 pm_parser_err_node(parser, key, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
16479 expect1(parser, PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
16480 key = UP(pm_symbol_node_label_create(parser, &parser->
previous));
16483 parse_pattern_hash_key(parser, &keys, key);
16486 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)) {
16487 if (PM_NODE_TYPE_P(key, PM_SYMBOL_NODE)) {
16488 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) key);
16490 value = UP(pm_missing_node_create(parser, key->location.end, key->location.end));
16493 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
16497 pm_node_t *assoc = UP(pm_assoc_node_create(parser, key, &
operator, value));
16499 if (rest != NULL) {
16500 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
16503 pm_node_list_append(&assocs, assoc);
16510 pm_static_literals_free(&keys);
16519 switch (parser->
current.type) {
16520 case PM_TOKEN_IDENTIFIER:
16521 case PM_TOKEN_METHOD_NAME: {
16522 parser_lex(parser);
16526 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16530 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
16531 return UP(pm_local_variable_target_node_create(
16533 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
16535 (uint32_t) (depth == -1 ? 0 : depth)
16538 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
16540 parser_lex(parser);
16542 if (accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
16545 return UP(pm_array_pattern_node_empty_create(parser, &opening, &parser->
previous));
16550 pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16552 accept1(parser, PM_TOKEN_NEWLINE);
16553 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET);
16556 switch (PM_NODE_TYPE(inner)) {
16557 case PM_ARRAY_PATTERN_NODE: {
16563 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16564 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16566 return UP(pattern_node);
16571 case PM_FIND_PATTERN_NODE: {
16577 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16578 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16580 return UP(pattern_node);
16590 pm_array_pattern_node_requireds_append(node, inner);
16593 case PM_TOKEN_BRACE_LEFT: {
16599 parser_lex(parser);
16601 if (accept1(parser, PM_TOKEN_BRACE_RIGHT)) {
16604 node = pm_hash_pattern_node_empty_create(parser, &opening, &parser->
previous);
16608 switch (parser->
current.type) {
16609 case PM_TOKEN_LABEL:
16610 parser_lex(parser);
16611 first_node = UP(pm_symbol_node_label_create(parser, &parser->
previous));
16613 case PM_TOKEN_USTAR_STAR:
16614 first_node = parse_pattern_keyword_rest(parser, captures);
16616 case PM_TOKEN_STRING_BEGIN:
16617 first_node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, PM_ERR_PATTERN_HASH_KEY_LABEL, (uint16_t) (depth + 1));
16621 parser_lex(parser);
16628 node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
16630 accept1(parser, PM_TOKEN_NEWLINE);
16631 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE);
16637 node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16638 node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16644 case PM_TOKEN_UDOT_DOT:
16645 case PM_TOKEN_UDOT_DOT_DOT: {
16647 parser_lex(parser);
16651 switch (parser->
current.type) {
16652 case PM_CASE_PRIMITIVE: {
16653 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
16654 return UP(pm_range_node_create(parser, NULL, &
operator, right));
16657 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
16658 pm_node_t *right = UP(pm_missing_node_create(parser,
operator.start,
operator.end));
16659 return UP(pm_range_node_create(parser, NULL, &
operator, right));
16663 case PM_CASE_PRIMITIVE: {
16664 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, diag_id, (uint16_t) (depth + 1));
16667 if (pm_symbol_node_label_p(node))
return node;
16670 if (PM_NODE_TYPE(node) == PM_CALL_NODE) {
16671 pm_parser_err_node(parser, node, diag_id);
16673 pm_node_destroy(parser, node);
16674 return UP(missing_node);
16678 if (accept2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
16684 switch (parser->
current.type) {
16685 case PM_CASE_PRIMITIVE: {
16686 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
16687 return UP(pm_range_node_create(parser, node, &
operator, right));
16690 return UP(pm_range_node_create(parser, node, &
operator, NULL));
16696 case PM_TOKEN_CARET: {
16697 parser_lex(parser);
16702 switch (parser->
current.type) {
16703 case PM_TOKEN_IDENTIFIER: {
16704 parser_lex(parser);
16705 pm_node_t *variable = UP(parse_variable(parser));
16707 if (variable == NULL) {
16708 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
previous, PM_ERR_NO_LOCAL_VARIABLE);
16709 variable = UP(pm_local_variable_read_node_missing_create(parser, &parser->
previous, 0));
16712 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16714 case PM_TOKEN_INSTANCE_VARIABLE: {
16715 parser_lex(parser);
16716 pm_node_t *variable = UP(pm_instance_variable_read_node_create(parser, &parser->
previous));
16718 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16720 case PM_TOKEN_CLASS_VARIABLE: {
16721 parser_lex(parser);
16722 pm_node_t *variable = UP(pm_class_variable_read_node_create(parser, &parser->
previous));
16724 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16726 case PM_TOKEN_GLOBAL_VARIABLE: {
16727 parser_lex(parser);
16728 pm_node_t *variable = UP(pm_global_variable_read_node_create(parser, &parser->
previous));
16730 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16732 case PM_TOKEN_NUMBERED_REFERENCE: {
16733 parser_lex(parser);
16734 pm_node_t *variable = UP(pm_numbered_reference_read_node_create(parser, &parser->
previous));
16736 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16738 case PM_TOKEN_BACK_REFERENCE: {
16739 parser_lex(parser);
16740 pm_node_t *variable = UP(pm_back_reference_read_node_create(parser, &parser->
previous));
16742 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16744 case PM_TOKEN_PARENTHESIS_LEFT: {
16749 parser_lex(parser);
16751 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN, (uint16_t) (depth + 1));
16754 accept1(parser, PM_TOKEN_NEWLINE);
16755 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
16756 return UP(pm_pinned_expression_node_create(parser, expression, &
operator, &lparen, &parser->
previous));
16761 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
16762 pm_node_t *variable = UP(pm_missing_node_create(parser,
operator.start,
operator.end));
16763 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16767 case PM_TOKEN_UCOLON_COLON: {
16769 parser_lex(parser);
16771 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
16774 return parse_pattern_constant_path(parser, captures, UP(node), (uint16_t) (depth + 1));
16776 case PM_TOKEN_CONSTANT: {
16778 parser_lex(parser);
16780 pm_node_t *node = UP(pm_constant_read_node_create(parser, &constant));
16781 return parse_pattern_constant_path(parser, captures, node, (uint16_t) (depth + 1));
16784 pm_parser_err_current(parser, diag_id);
16785 return UP(pm_missing_node_create(parser, parser->
current.start, parser->
current.end));
16790parse_pattern_alternation_error_each(
const pm_node_t *node,
void *data) {
16791 switch (PM_NODE_TYPE(node)) {
16792 case PM_LOCAL_VARIABLE_TARGET_NODE:
16806 pm_visit_node(node, parse_pattern_alternation_error_each, parser);
16816 bool alternation =
false;
16818 while ((node == NULL) || (alternation = accept1(parser, PM_TOKEN_PIPE))) {
16819 if (alternation && !PM_NODE_TYPE_P(node, PM_ALTERNATION_PATTERN_NODE) && captures->
size) {
16820 parse_pattern_alternation_error(parser, node);
16823 switch (parser->
current.type) {
16824 case PM_TOKEN_IDENTIFIER:
16825 case PM_TOKEN_BRACKET_LEFT_ARRAY:
16826 case PM_TOKEN_BRACE_LEFT:
16827 case PM_TOKEN_CARET:
16828 case PM_TOKEN_CONSTANT:
16829 case PM_TOKEN_UCOLON_COLON:
16830 case PM_TOKEN_UDOT_DOT:
16831 case PM_TOKEN_UDOT_DOT_DOT:
16832 case PM_CASE_PRIMITIVE: {
16833 if (!alternation) {
16834 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
16837 pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
16839 if (captures->
size) parse_pattern_alternation_error(parser, right);
16840 node = UP(pm_alternation_pattern_node_create(parser, node, right, &
operator));
16845 case PM_TOKEN_PARENTHESIS_LEFT:
16846 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
16849 parser_lex(parser);
16851 pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
16852 accept1(parser, PM_TOKEN_NEWLINE);
16853 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
16854 pm_node_t *right = UP(pm_parentheses_node_create(parser, &opening, body, &parser->
previous, 0));
16856 if (!alternation) {
16859 if (captures->
size) parse_pattern_alternation_error(parser, right);
16860 node = UP(pm_alternation_pattern_node_create(parser, node, right, &
operator));
16866 pm_parser_err_current(parser, diag_id);
16869 if (!alternation) {
16872 if (captures->
size) parse_pattern_alternation_error(parser, right);
16873 node = UP(pm_alternation_pattern_node_create(parser, node, right, &parser->
previous));
16883 while (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
16885 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_PATTERN_IDENT_AFTER_HROCKET);
16890 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16894 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
16897 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
16899 (uint32_t) (depth == -1 ? 0 : depth)
16902 node = UP(pm_capture_pattern_node_create(parser, node, target, &
operator));
16915 bool leading_rest =
false;
16916 bool trailing_rest =
false;
16918 switch (parser->
current.type) {
16919 case PM_TOKEN_LABEL: {
16920 parser_lex(parser);
16922 node = UP(parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1)));
16924 if (!(flags & PM_PARSE_PATTERN_TOP)) {
16925 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
16930 case PM_TOKEN_USTAR_STAR: {
16931 node = parse_pattern_keyword_rest(parser, captures);
16932 node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
16934 if (!(flags & PM_PARSE_PATTERN_TOP)) {
16935 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
16940 case PM_TOKEN_STRING_BEGIN: {
16943 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
16945 if (pm_symbol_node_label_p(node)) {
16946 node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
16948 if (!(flags & PM_PARSE_PATTERN_TOP)) {
16949 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
16955 node = parse_pattern_primitives(parser, captures, node, diag_id, (uint16_t) (depth + 1));
16958 case PM_TOKEN_USTAR: {
16959 if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
16960 parser_lex(parser);
16961 node = UP(parse_pattern_rest(parser, captures));
16962 leading_rest =
true;
16968 node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1));
16974 if (pm_symbol_node_label_p(node)) {
16975 return UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
16978 if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser, PM_TOKEN_COMMA)) {
16983 pm_node_list_append(&nodes, node);
16986 while (accept1(parser, PM_TOKEN_COMMA)) {
16988 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)) {
16989 node = UP(pm_implicit_rest_node_create(parser, &parser->
previous));
16990 pm_node_list_append(&nodes, node);
16991 trailing_rest =
true;
16995 if (accept1(parser, PM_TOKEN_USTAR)) {
16996 node = UP(parse_pattern_rest(parser, captures));
17001 if (trailing_rest) {
17002 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
17005 trailing_rest =
true;
17007 node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
17010 pm_node_list_append(&nodes, node);
17017 if (leading_rest && PM_NODE_TYPE_P(nodes.
nodes[nodes.
size - 1], PM_SPLAT_NODE)) {
17018 node = UP(pm_find_pattern_node_create(parser, &nodes));
17020 if (nodes.
size == 2) {
17021 pm_parser_err_node(parser, node, PM_ERR_PATTERN_FIND_MISSING_INNER);
17024 node = UP(pm_array_pattern_node_node_list_create(parser, &nodes));
17026 if (leading_rest && trailing_rest) {
17027 pm_parser_err_node(parser, node, PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS);
17032 }
else if (leading_rest) {
17035 node = UP(pm_array_pattern_node_rest_create(parser, node));
17047parse_negative_numeric(
pm_node_t *node) {
17048 switch (PM_NODE_TYPE(node)) {
17049 case PM_INTEGER_NODE: {
17055 case PM_FLOAT_NODE: {
17061 case PM_RATIONAL_NODE: {
17067 case PM_IMAGINARY_NODE:
17072 assert(
false &&
"unreachable");
17085 case PM_ERR_HASH_KEY: {
17089 case PM_ERR_HASH_VALUE:
17090 case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: {
17094 case PM_ERR_UNARY_RECEIVER: {
17099 case PM_ERR_UNARY_DISALLOWED:
17100 case PM_ERR_EXPECT_ARGUMENT: {
17105 pm_parser_err_previous(parser, diag_id);
17115#define CONTEXT_NONE 0
17116#define CONTEXT_THROUGH_ENSURE 1
17117#define CONTEXT_THROUGH_ELSE 2
17120 int context = CONTEXT_NONE;
17122 while (context_node != NULL) {
17123 switch (context_node->
context) {
17144 if (context == CONTEXT_NONE) {
17145 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_WITHOUT_RESCUE);
17146 }
else if (context == CONTEXT_THROUGH_ENSURE) {
17147 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ENSURE);
17148 }
else if (context == CONTEXT_THROUGH_ELSE) {
17149 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ELSE);
17161 context = CONTEXT_THROUGH_ELSE;
17172 context = CONTEXT_THROUGH_ENSURE;
17176 assert(
false &&
"unreachable");
17207 context_node = context_node->
prev;
17211#undef CONTEXT_ENSURE
17222 while (context_node != NULL) {
17223 switch (context_node->
context) {
17248 pm_parser_err_node(parser, node, PM_ERR_INVALID_YIELD);
17252 assert(
false &&
"unreachable");
17294 context_node = context_node->
prev;
17326parse_regular_expression_error(
const uint8_t *start,
const uint8_t *end,
const char *message,
void *data) {
17330 if (callback_data->
shared) {
17336 PM_PARSER_ERR_FORMAT(callback_data->
parser, location.
start, location.
end, PM_ERR_REGEXP_PARSE_ERROR, message);
17349 .shared = unescaped->
type == PM_STRING_SHARED
17352 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);
17359parse_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) {
17360 switch (parser->
current.type) {
17361 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
17362 parser_lex(parser);
17365 pm_accepts_block_stack_push(parser,
true);
17366 bool parsed_bare_hash =
false;
17368 while (!match2(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_EOF)) {
17369 bool accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
17373 if (accepted_newline && match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17379 if (accept1(parser, PM_TOKEN_COMMA)) {
17382 if (accepted_newline) {
17383 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
17399 if (match1(parser, PM_TOKEN_BRACKET_RIGHT))
break;
17403 if (accept1(parser, PM_TOKEN_USTAR)) {
17407 if (match3(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_EOF)) {
17408 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
17410 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
17413 element = UP(pm_splat_node_create(parser, &
operator, expression));
17414 }
else if (match2(parser, PM_TOKEN_LABEL, PM_TOKEN_USTAR_STAR)) {
17415 if (parsed_bare_hash) {
17416 pm_parser_err_current(parser, PM_ERR_EXPRESSION_BARE_HASH);
17419 element = UP(pm_keyword_hash_node_create(parser));
17422 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)) {
17423 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
17426 pm_static_literals_free(&hash_keys);
17427 parsed_bare_hash =
true;
17429 element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_ARRAY_EXPRESSION, (uint16_t) (depth + 1));
17431 if (pm_symbol_node_label_p(element) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
17432 if (parsed_bare_hash) {
17433 pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
17438 pm_hash_key_static_literals_add(parser, &hash_keys, element);
17441 if (parser->
previous.
type == PM_TOKEN_EQUAL_GREATER) {
17444 operator = not_provided(parser);
17447 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
17448 pm_node_t *assoc = UP(pm_assoc_node_create(parser, element, &
operator, value));
17449 pm_keyword_hash_node_elements_append(hash, assoc);
17451 element = UP(hash);
17452 if (accept1(parser, PM_TOKEN_COMMA) && !match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17453 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
17456 pm_static_literals_free(&hash_keys);
17457 parsed_bare_hash =
true;
17461 pm_array_node_elements_append(array, element);
17462 if (PM_NODE_TYPE_P(element, PM_MISSING_NODE))
break;
17465 accept1(parser, PM_TOKEN_NEWLINE);
17467 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17473 pm_array_node_close_set(array, &parser->
previous);
17474 pm_accepts_block_stack_pop(parser);
17478 case PM_TOKEN_PARENTHESIS_LEFT:
17479 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
17481 pm_node_flags_t flags = 0;
17484 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
17486 parser_lex(parser);
17488 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
17489 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
17490 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
17497 if (match2(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_EOF)) {
17498 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
17500 pop_block_exits(parser, previous_block_exits);
17501 pm_node_list_free(¤t_block_exits);
17503 return UP(pm_parentheses_node_create(parser, &opening, NULL, &parser->
previous, flags));
17508 pm_accepts_block_stack_push(parser,
true);
17510 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
17511 context_pop(parser);
17516 bool terminator_found =
false;
17518 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
17519 terminator_found =
true;
17520 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
17521 }
else if (accept1(parser, PM_TOKEN_NEWLINE)) {
17522 terminator_found =
true;
17525 if (terminator_found) {
17527 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
17528 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
17529 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
17538 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
17539 if (opening.
type == PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
17540 lex_state_set(parser, PM_LEX_STATE_ENDARG);
17543 parser_lex(parser);
17544 pm_accepts_block_stack_pop(parser);
17546 pop_block_exits(parser, previous_block_exits);
17547 pm_node_list_free(¤t_block_exits);
17549 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) || PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
17555 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) && ((
pm_multi_target_node_t *) statement)->lparen_loc.start == NULL) {
17558 multi_target = pm_multi_target_node_create(parser);
17559 pm_multi_target_node_targets_append(parser, multi_target, statement);
17562 pm_location_t lparen_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17571 if (match1(parser, PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
17572 result = parse_targets(parser, UP(multi_target), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17573 accept1(parser, PM_TOKEN_NEWLINE);
17575 result = UP(multi_target);
17584 }
else if (binding_power != PM_BINDING_POWER_STATEMENT) {
17587 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
17588 }
else if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
17592 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
17602 pm_statements_node_body_append(parser, statements, statement,
true);
17604 return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->
previous, flags));
17611 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
17614 pm_statements_node_body_append(parser, statements, statement,
true);
17618 if (!terminator_found && !match1(parser, PM_TOKEN_EOF)) {
17624 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
17625 pm_statements_node_body_append(parser, statements, node,
true);
17632 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) parser->
recovering =
false;
17638 if (PM_NODE_TYPE_P(node, PM_MISSING_NODE))
break;
17642 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
17643 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
17644 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
break;
17645 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
17647 }
else if (!match1(parser, PM_TOKEN_EOF)) {
17654 context_pop(parser);
17655 pm_accepts_block_stack_pop(parser);
17656 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
17665 if (PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
17667 pm_multi_target_node_targets_append(parser, multi_target, statement);
17669 statement = UP(multi_target);
17673 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE)) {
17675 pm_token_t operator = { .
type = PM_TOKEN_EQUAL, .start = offset, .end = offset };
17676 pm_node_t *value = UP(pm_missing_node_create(parser, offset, offset));
17678 statement = UP(pm_multi_write_node_create(parser, (
pm_multi_target_node_t *) statement, &
operator, value));
17681 pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
17685 pop_block_exits(parser, previous_block_exits);
17686 pm_node_list_free(¤t_block_exits);
17688 pm_void_statements_check(parser, statements,
true);
17689 return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->
previous, flags));
17691 case PM_TOKEN_BRACE_LEFT: {
17702 pm_accepts_block_stack_push(parser,
true);
17703 parser_lex(parser);
17707 if (!match2(parser, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_EOF)) {
17708 if (current_hash_keys != NULL) {
17709 parse_assocs(parser, current_hash_keys, UP(node), (uint16_t) (depth + 1));
17712 parse_assocs(parser, &hash_keys, UP(node), (uint16_t) (depth + 1));
17713 pm_static_literals_free(&hash_keys);
17716 accept1(parser, PM_TOKEN_NEWLINE);
17719 pm_accepts_block_stack_pop(parser);
17720 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM);
17721 pm_hash_node_closing_loc_set(node, &parser->
previous);
17725 case PM_TOKEN_CHARACTER_LITERAL: {
17727 pm_node_t *node = UP(pm_string_node_create_current_string(
17730 .type = PM_TOKEN_STRING_BEGIN,
17731 .start = parser->
current.start,
17732 .end = parser->
current.start + 1
17735 .type = PM_TOKEN_STRING_CONTENT,
17736 .start = parser->
current.start + 1,
17742 pm_node_flag_set(node, parse_unescaped_encoding(parser));
17746 parser_lex(parser);
17750 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
17751 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
17756 case PM_TOKEN_CLASS_VARIABLE: {
17757 parser_lex(parser);
17758 pm_node_t *node = UP(pm_class_variable_read_node_create(parser, &parser->
previous));
17760 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
17761 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17766 case PM_TOKEN_CONSTANT: {
17767 parser_lex(parser);
17773 match1(parser, PM_TOKEN_PARENTHESIS_LEFT) ||
17774 (accepts_command_call && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
17775 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
17776 match1(parser, PM_TOKEN_BRACE_LEFT)
17779 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
17780 return UP(pm_call_node_fcall_create(parser, &constant, &arguments));
17785 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
17788 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17793 case PM_TOKEN_UCOLON_COLON: {
17794 parser_lex(parser);
17797 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
17798 pm_node_t *node = UP(pm_constant_path_node_create(parser, NULL, &delimiter, &parser->
previous));
17800 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
17801 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17806 case PM_TOKEN_UDOT_DOT:
17807 case PM_TOKEN_UDOT_DOT_DOT: {
17809 parser_lex(parser);
17811 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));
17817 if (match2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
17818 pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
17821 return UP(pm_range_node_create(parser, NULL, &
operator, right));
17823 case PM_TOKEN_FLOAT:
17824 parser_lex(parser);
17825 return UP(pm_float_node_create(parser, &parser->
previous));
17826 case PM_TOKEN_FLOAT_IMAGINARY:
17827 parser_lex(parser);
17828 return UP(pm_float_node_imaginary_create(parser, &parser->
previous));
17829 case PM_TOKEN_FLOAT_RATIONAL:
17830 parser_lex(parser);
17831 return UP(pm_float_node_rational_create(parser, &parser->
previous));
17832 case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY:
17833 parser_lex(parser);
17834 return UP(pm_float_node_rational_imaginary_create(parser, &parser->
previous));
17835 case PM_TOKEN_NUMBERED_REFERENCE: {
17836 parser_lex(parser);
17837 pm_node_t *node = UP(pm_numbered_reference_read_node_create(parser, &parser->
previous));
17839 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
17840 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17845 case PM_TOKEN_GLOBAL_VARIABLE: {
17846 parser_lex(parser);
17847 pm_node_t *node = UP(pm_global_variable_read_node_create(parser, &parser->
previous));
17849 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
17850 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17855 case PM_TOKEN_BACK_REFERENCE: {
17856 parser_lex(parser);
17857 pm_node_t *node = UP(pm_back_reference_read_node_create(parser, &parser->
previous));
17859 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
17860 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17865 case PM_TOKEN_IDENTIFIER:
17866 case PM_TOKEN_METHOD_NAME: {
17867 parser_lex(parser);
17869 pm_node_t *node = parse_variable_call(parser);
17871 if (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
17879 if (parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1))) {
17882 pm_node_flag_unset(UP(call), PM_CALL_NODE_FLAGS_VARIABLE_CALL);
17889 const uint8_t *end = pm_arguments_end(&arguments);
17900 (accepts_command_call && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
17901 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
17902 match1(parser, PM_TOKEN_BRACE_LEFT)
17905 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
17906 pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
17908 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
17912 pm_node_unreference(parser, node);
17918 assert(PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE));
17920 if (pm_token_is_numbered_parameter(identifier.
start, identifier.
end)) {
17921 pm_node_unreference(parser, node);
17924 pm_locals_unread(&pm_parser_scope_find(parser, cast->
depth)->
locals, cast->
name);
17928 pm_node_destroy(parser, node);
17933 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
17934 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17939 case PM_TOKEN_HEREDOC_START: {
17945 size_t common_whitespace = (size_t) -1;
17948 parser_lex(parser);
17954 if (match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
17960 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
17961 node = UP(pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->
previous, &
PM_STRING_EMPTY));
17967 }
else if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) == NULL) {
17975 }
else if (PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
17980 pm_node_flag_set(part, parse_unescaped_encoding(parser));
17983 cast->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17987 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
17989 cast->
base.
type = PM_X_STRING_NODE;
17992 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
17993 parse_heredoc_dedent_string(&cast->
unescaped, common_whitespace);
18003 pm_node_list_append(&parts, part);
18005 while (!match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18006 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
18007 pm_node_list_append(&parts, part);
18013 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18015 cast->
parts = parts;
18018 pm_interpolated_xstring_node_closing_set(cast, &parser->
previous);
18024 pm_node_list_free(&parts);
18027 pm_interpolated_string_node_closing_set(cast, &parser->
previous);
18035 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18037 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18043 parse_heredoc_dedent(parser, nodes, common_whitespace);
18047 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
18048 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18053 case PM_TOKEN_INSTANCE_VARIABLE: {
18054 parser_lex(parser);
18055 pm_node_t *node = UP(pm_instance_variable_read_node_create(parser, &parser->
previous));
18057 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18058 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18063 case PM_TOKEN_INTEGER: {
18065 parser_lex(parser);
18066 return UP(pm_integer_node_create(parser, base, &parser->
previous));
18068 case PM_TOKEN_INTEGER_IMAGINARY: {
18070 parser_lex(parser);
18071 return UP(pm_integer_node_imaginary_create(parser, base, &parser->
previous));
18073 case PM_TOKEN_INTEGER_RATIONAL: {
18075 parser_lex(parser);
18076 return UP(pm_integer_node_rational_create(parser, base, &parser->
previous));
18078 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: {
18080 parser_lex(parser);
18081 return UP(pm_integer_node_rational_imaginary_create(parser, base, &parser->
previous));
18083 case PM_TOKEN_KEYWORD___ENCODING__:
18084 parser_lex(parser);
18085 return UP(pm_source_encoding_node_create(parser, &parser->
previous));
18086 case PM_TOKEN_KEYWORD___FILE__:
18087 parser_lex(parser);
18088 return UP(pm_source_file_node_create(parser, &parser->
previous));
18089 case PM_TOKEN_KEYWORD___LINE__:
18090 parser_lex(parser);
18091 return UP(pm_source_line_node_create(parser, &parser->
previous));
18092 case PM_TOKEN_KEYWORD_ALIAS: {
18093 if (binding_power != PM_BINDING_POWER_STATEMENT) {
18094 pm_parser_err_current(parser, PM_ERR_STATEMENT_ALIAS);
18097 parser_lex(parser);
18100 pm_node_t *new_name = parse_alias_argument(parser,
true, (uint16_t) (depth + 1));
18101 pm_node_t *old_name = parse_alias_argument(parser,
false, (uint16_t) (depth + 1));
18103 switch (PM_NODE_TYPE(new_name)) {
18104 case PM_BACK_REFERENCE_READ_NODE:
18105 case PM_NUMBERED_REFERENCE_READ_NODE:
18106 case PM_GLOBAL_VARIABLE_READ_NODE: {
18107 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)) {
18108 if (PM_NODE_TYPE_P(old_name, PM_NUMBERED_REFERENCE_READ_NODE)) {
18109 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE);
18112 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18115 return UP(pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name));
18117 case PM_SYMBOL_NODE:
18118 case PM_INTERPOLATED_SYMBOL_NODE: {
18119 if (!PM_NODE_TYPE_P(old_name, PM_SYMBOL_NODE) && !PM_NODE_TYPE_P(old_name, PM_INTERPOLATED_SYMBOL_NODE)) {
18120 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18125 return UP(pm_alias_method_node_create(parser, &keyword, new_name, old_name));
18128 case PM_TOKEN_KEYWORD_CASE: {
18129 size_t opening_newline_index = token_newline_index(parser);
18130 parser_lex(parser);
18136 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18138 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18139 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18141 }
else if (match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_END)) {
18143 }
else if (!token_begins_expression_p(parser->
current.type)) {
18146 predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CASE_EXPRESSION_AFTER_CASE, (uint16_t) (depth + 1));
18147 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18150 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
18151 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18152 parser_lex(parser);
18154 pop_block_exits(parser, previous_block_exits);
18155 pm_node_list_free(¤t_block_exits);
18157 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18158 return UP(pm_case_node_create(parser, &case_keyword, predicate, &parser->
previous));
18163 pm_token_t end_keyword = not_provided(parser);
18166 if (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18167 pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, &end_keyword);
18173 while (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18174 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18175 parser_lex(parser);
18178 pm_when_node_t *when_node = pm_when_node_create(parser, &when_keyword);
18181 if (accept1(parser, PM_TOKEN_USTAR)) {
18183 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
18185 pm_splat_node_t *splat_node = pm_splat_node_create(parser, &
operator, expression);
18186 pm_when_node_conditions_append(when_node, UP(splat_node));
18188 if (PM_NODE_TYPE_P(expression, PM_MISSING_NODE))
break;
18190 pm_node_t *condition = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_CASE_EXPRESSION_AFTER_WHEN, (uint16_t) (depth + 1));
18191 pm_when_node_conditions_append(when_node, condition);
18195 if (PM_NODE_TYPE_P(condition, PM_MISSING_NODE))
break;
18199 if (PM_NODE_TYPE_P(condition, PM_STRING_NODE)) {
18200 pm_node_flag_set(condition, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
18201 }
else if (PM_NODE_TYPE_P(condition, PM_SOURCE_FILE_NODE)) {
18202 pm_node_flag_set(condition, PM_NODE_FLAG_STATIC_LITERAL);
18205 pm_when_clause_static_literals_add(parser, &literals, condition);
18207 }
while (accept1(parser, PM_TOKEN_COMMA));
18209 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18210 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
18211 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
18214 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_WHEN_DELIMITER);
18215 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
18218 if (!match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18220 if (statements != NULL) {
18221 pm_when_node_statements_set(when_node, statements);
18225 pm_case_node_condition_append(case_node, UP(when_node));
18231 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18234 pm_static_literals_free(&literals);
18235 node = UP(case_node);
18237 pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate, &end_keyword);
18241 if (predicate == NULL) {
18242 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MATCH_MISSING_PREDICATE);
18248 while (match1(parser, PM_TOKEN_KEYWORD_IN)) {
18249 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18254 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
18256 parser_lex(parser);
18261 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));
18264 pm_constant_id_list_free(&captures);
18269 if (accept1(parser, PM_TOKEN_KEYWORD_IF_MODIFIER)) {
18271 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
18272 pattern = UP(pm_if_node_modifier_create(parser, pattern, &keyword, predicate));
18273 }
else if (accept1(parser, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) {
18275 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
18276 pattern = UP(pm_unless_node_modifier_create(parser, pattern, &keyword, predicate));
18283 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18284 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
18287 then_keyword = not_provided(parser);
18290 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_IN_DELIMITER);
18297 if (match3(parser, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18305 pm_node_t *condition = UP(pm_in_node_create(parser, pattern, statements, &in_keyword, &then_keyword));
18306 pm_case_match_node_condition_append(case_node, condition);
18312 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18315 node = UP(case_node);
18318 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18319 if (accept1(parser, PM_TOKEN_KEYWORD_ELSE)) {
18323 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
18324 else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser,
PM_CONTEXT_ELSE, (uint16_t) (depth + 1)), &parser->
current);
18326 else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->
current);
18329 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
18330 pm_case_node_else_clause_set((
pm_case_node_t *) node, else_node);
18336 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18337 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM);
18339 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
18345 pop_block_exits(parser, previous_block_exits);
18346 pm_node_list_free(¤t_block_exits);
18350 case PM_TOKEN_KEYWORD_BEGIN: {
18351 size_t opening_newline_index = token_newline_index(parser);
18352 parser_lex(parser);
18355 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18358 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18361 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18362 pm_accepts_block_stack_push(parser,
true);
18363 begin_statements = parse_statements(parser,
PM_CONTEXT_BEGIN, (uint16_t) (depth + 1));
18364 pm_accepts_block_stack_pop(parser);
18365 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18368 pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
18369 parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
18370 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM);
18373 pm_begin_node_end_keyword_set(begin_node, &parser->
previous);
18375 pop_block_exits(parser, previous_block_exits);
18376 pm_node_list_free(¤t_block_exits);
18378 return UP(begin_node);
18380 case PM_TOKEN_KEYWORD_BEGIN_UPCASE: {
18382 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18384 if (binding_power != PM_BINDING_POWER_STATEMENT) {
18385 pm_parser_err_current(parser, PM_ERR_STATEMENT_PREEXE_BEGIN);
18388 parser_lex(parser);
18391 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_BEGIN_UPCASE_BRACE);
18395 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM);
18398 pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
18401 flush_block_exits(parser, previous_block_exits);
18402 pm_node_list_free(¤t_block_exits);
18404 return UP(pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous));
18406 case PM_TOKEN_KEYWORD_BREAK:
18407 case PM_TOKEN_KEYWORD_NEXT:
18408 case PM_TOKEN_KEYWORD_RETURN: {
18409 parser_lex(parser);
18415 token_begins_expression_p(parser->
current.type) ||
18416 match2(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)
18418 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].
left;
18420 if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
18422 parse_arguments(parser, &arguments,
false, PM_TOKEN_EOF, (uint16_t) (depth + 1));
18425 if (!accepts_command_call && arguments.
arguments != NULL) {
18431 switch (keyword.
type) {
18432 case PM_TOKEN_KEYWORD_BREAK: {
18437 case PM_TOKEN_KEYWORD_NEXT: {
18442 case PM_TOKEN_KEYWORD_RETURN: {
18444 parse_return(parser, node);
18448 assert(
false &&
"unreachable");
18452 case PM_TOKEN_KEYWORD_SUPER: {
18453 parser_lex(parser);
18457 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18462 ((arguments.
block == NULL) || PM_NODE_TYPE_P(arguments.
block, PM_BLOCK_NODE))
18464 return UP(pm_forwarding_super_node_create(parser, &keyword, &arguments));
18467 return UP(pm_super_node_create(parser, &keyword, &arguments));
18469 case PM_TOKEN_KEYWORD_YIELD: {
18470 parser_lex(parser);
18474 parse_arguments_list(parser, &arguments,
false, accepts_command_call, (uint16_t) (depth + 1));
18480 if (arguments.
block != NULL) {
18481 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
18482 pm_node_destroy(parser, arguments.
block);
18483 arguments.
block = NULL;
18491 case PM_TOKEN_KEYWORD_CLASS: {
18492 size_t opening_newline_index = token_newline_index(parser);
18493 parser_lex(parser);
18496 pm_do_loop_stack_push(parser,
false);
18499 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18501 if (accept1(parser, PM_TOKEN_LESS_LESS)) {
18503 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));
18505 pm_parser_scope_push(parser,
true);
18506 if (!match2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18511 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18512 pm_accepts_block_stack_push(parser,
true);
18513 statements = UP(parse_statements(parser,
PM_CONTEXT_SCLASS, (uint16_t) (depth + 1)));
18514 pm_accepts_block_stack_pop(parser);
18517 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
18518 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18519 statements = UP(parse_rescues_implicit_begin(parser, opening_newline_index, &class_keyword, class_keyword.
start, (
pm_statements_node_t *) statements, PM_RESCUES_SCLASS, (uint16_t) (depth + 1)));
18521 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
18524 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
18529 pm_parser_scope_pop(parser);
18530 pm_do_loop_stack_pop(parser);
18532 flush_block_exits(parser, previous_block_exits);
18533 pm_node_list_free(¤t_block_exits);
18535 return UP(pm_singleton_class_node_create(parser, &locals, &class_keyword, &
operator, expression, statements, &parser->
previous));
18538 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_CLASS_NAME, (uint16_t) (depth + 1));
18540 if (name.
type != PM_TOKEN_CONSTANT) {
18541 pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME);
18547 if (match1(parser, PM_TOKEN_LESS)) {
18548 inheritance_operator = parser->
current;
18549 lex_state_set(parser, PM_LEX_STATE_BEG);
18552 parser_lex(parser);
18554 superclass = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CLASS_SUPERCLASS, (uint16_t) (depth + 1));
18556 inheritance_operator = not_provided(parser);
18560 pm_parser_scope_push(parser,
true);
18562 if (inheritance_operator.
type != PM_TOKEN_NOT_PROVIDED) {
18563 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CLASS_UNEXPECTED_END);
18565 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18569 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18570 pm_accepts_block_stack_push(parser,
true);
18571 statements = UP(parse_statements(parser,
PM_CONTEXT_CLASS, (uint16_t) (depth + 1)));
18572 pm_accepts_block_stack_pop(parser);
18575 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
18576 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18577 statements = UP(parse_rescues_implicit_begin(parser, opening_newline_index, &class_keyword, class_keyword.
start, (
pm_statements_node_t *) statements, PM_RESCUES_CLASS, (uint16_t) (depth + 1)));
18579 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
18582 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
18584 if (context_def_p(parser)) {
18585 pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
18591 pm_parser_scope_pop(parser);
18592 pm_do_loop_stack_pop(parser);
18594 if (!PM_NODE_TYPE_P(constant_path, PM_CONSTANT_PATH_NODE) && !(PM_NODE_TYPE_P(constant_path, PM_CONSTANT_READ_NODE))) {
18595 pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
18598 pop_block_exits(parser, previous_block_exits);
18599 pm_node_list_free(¤t_block_exits);
18601 return UP(pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, &inheritance_operator, superclass, statements, &parser->
previous));
18603 case PM_TOKEN_KEYWORD_DEF: {
18605 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18608 size_t opening_newline_index = token_newline_index(parser);
18618 parser_lex(parser);
18622 bool valid_name =
true;
18624 switch (parser->
current.type) {
18625 case PM_CASE_OPERATOR:
18626 pm_parser_scope_push(parser,
true);
18627 lex_state_set(parser, PM_LEX_STATE_ENDFN);
18628 parser_lex(parser);
18632 case PM_TOKEN_IDENTIFIER: {
18633 parser_lex(parser);
18635 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
18636 receiver = parse_variable_call(parser);
18638 pm_parser_scope_push(parser,
true);
18639 lex_state_set(parser, PM_LEX_STATE_FNAME);
18640 parser_lex(parser);
18643 name = parse_method_definition_name(parser);
18646 pm_parser_scope_push(parser,
true);
18653 case PM_TOKEN_INSTANCE_VARIABLE:
18654 case PM_TOKEN_CLASS_VARIABLE:
18655 case PM_TOKEN_GLOBAL_VARIABLE:
18656 valid_name =
false;
18658 case PM_TOKEN_CONSTANT:
18659 case PM_TOKEN_KEYWORD_NIL:
18660 case PM_TOKEN_KEYWORD_SELF:
18661 case PM_TOKEN_KEYWORD_TRUE:
18662 case PM_TOKEN_KEYWORD_FALSE:
18663 case PM_TOKEN_KEYWORD___FILE__:
18664 case PM_TOKEN_KEYWORD___LINE__:
18665 case PM_TOKEN_KEYWORD___ENCODING__: {
18666 pm_parser_scope_push(parser,
true);
18667 parser_lex(parser);
18671 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
18672 lex_state_set(parser, PM_LEX_STATE_FNAME);
18673 parser_lex(parser);
18676 switch (identifier.
type) {
18677 case PM_TOKEN_CONSTANT:
18678 receiver = UP(pm_constant_read_node_create(parser, &identifier));
18680 case PM_TOKEN_INSTANCE_VARIABLE:
18681 receiver = UP(pm_instance_variable_read_node_create(parser, &identifier));
18683 case PM_TOKEN_CLASS_VARIABLE:
18684 receiver = UP(pm_class_variable_read_node_create(parser, &identifier));
18686 case PM_TOKEN_GLOBAL_VARIABLE:
18687 receiver = UP(pm_global_variable_read_node_create(parser, &identifier));
18689 case PM_TOKEN_KEYWORD_NIL:
18690 receiver = UP(pm_nil_node_create(parser, &identifier));
18692 case PM_TOKEN_KEYWORD_SELF:
18693 receiver = UP(pm_self_node_create(parser, &identifier));
18695 case PM_TOKEN_KEYWORD_TRUE:
18696 receiver = UP(pm_true_node_create(parser, &identifier));
18698 case PM_TOKEN_KEYWORD_FALSE:
18699 receiver = UP(pm_false_node_create(parser, &identifier));
18701 case PM_TOKEN_KEYWORD___FILE__:
18702 receiver = UP(pm_source_file_node_create(parser, &identifier));
18704 case PM_TOKEN_KEYWORD___LINE__:
18705 receiver = UP(pm_source_line_node_create(parser, &identifier));
18707 case PM_TOKEN_KEYWORD___ENCODING__:
18708 receiver = UP(pm_source_encoding_node_create(parser, &identifier));
18714 name = parse_method_definition_name(parser);
18724 case PM_TOKEN_PARENTHESIS_LEFT: {
18729 context_pop(parser);
18730 parser_lex(parser);
18733 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEF_RECEIVER, (uint16_t) (depth + 1));
18735 accept1(parser, PM_TOKEN_NEWLINE);
18736 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
18739 lex_state_set(parser, PM_LEX_STATE_FNAME);
18740 expect2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON, PM_ERR_DEF_RECEIVER_TERM);
18743 receiver = UP(pm_parentheses_node_create(parser, &lparen, expression, &rparen, 0));
18747 pm_parser_scope_push(parser,
true);
18749 name = parse_method_definition_name(parser);
18753 pm_parser_scope_push(parser,
true);
18754 name = parse_method_definition_name(parser);
18762 bool accept_endless_def =
true;
18763 switch (parser->
current.type) {
18764 case PM_TOKEN_PARENTHESIS_LEFT: {
18765 parser_lex(parser);
18768 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18771 params = parse_parameters(parser, PM_BINDING_POWER_DEFINED,
true,
false,
true,
true,
false, (uint16_t) (depth + 1));
18774 lex_state_set(parser, PM_LEX_STATE_BEG);
18777 context_pop(parser);
18778 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18787 case PM_CASE_PARAMETER: {
18790 if (parser->
current.type == PM_TOKEN_LABEL) {
18791 lex_state_set(parser, parser->
lex_state | PM_LEX_STATE_LABEL);
18794 lparen = not_provided(parser);
18795 rparen = not_provided(parser);
18796 params = parse_parameters(parser, PM_BINDING_POWER_DEFINED,
false,
false,
true,
true,
false, (uint16_t) (depth + 1));
18800 accept_endless_def =
false;
18802 context_pop(parser);
18806 lparen = not_provided(parser);
18807 rparen = not_provided(parser);
18810 context_pop(parser);
18819 if (accept1(parser, PM_TOKEN_EQUAL)) {
18820 if (token_is_setter_name(&name)) {
18821 pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
18823 if (!accept_endless_def) {
18824 pm_parser_err_previous(parser, PM_ERR_DEF_ENDLESS_PARAMETERS);
18830 PM_PARSER_ERR_FORMAT(parser, def_keyword.
start, parser->
previous.
end, PM_ERR_UNEXPECTED_PARAMETER_DEFAULT_VALUE,
"endless method definition");
18835 pm_do_loop_stack_push(parser,
false);
18836 statements = UP(pm_statements_node_create(parser));
18838 bool allow_command_call;
18840 allow_command_call = accepts_command_call;
18843 allow_command_call = binding_power == PM_BINDING_POWER_ASSIGNMENT || binding_power < PM_BINDING_POWER_COMPOSITION;
18846 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_DEFINED + 1, allow_command_call,
false, PM_ERR_DEF_ENDLESS, (uint16_t) (depth + 1));
18848 if (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
18852 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));
18853 context_pop(parser);
18855 statement = UP(pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value));
18858 pm_statements_node_body_append(parser, (
pm_statements_node_t *) statements, statement,
false);
18859 pm_do_loop_stack_pop(parser);
18860 context_pop(parser);
18861 end_keyword = not_provided(parser);
18863 equal = not_provided(parser);
18865 if (lparen.
type == PM_TOKEN_NOT_PROVIDED) {
18866 lex_state_set(parser, PM_LEX_STATE_BEG);
18868 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_DEF_PARAMS_TERM);
18870 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18873 pm_accepts_block_stack_push(parser,
true);
18874 pm_do_loop_stack_push(parser,
false);
18876 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18877 pm_accepts_block_stack_push(parser,
true);
18878 statements = UP(parse_statements(parser,
PM_CONTEXT_DEF, (uint16_t) (depth + 1)));
18879 pm_accepts_block_stack_pop(parser);
18882 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
18883 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18884 statements = UP(parse_rescues_implicit_begin(parser, opening_newline_index, &def_keyword, def_keyword.
start, (
pm_statements_node_t *) statements, PM_RESCUES_DEF, (uint16_t) (depth + 1)));
18886 parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword,
false,
false);
18889 pm_accepts_block_stack_pop(parser);
18890 pm_do_loop_stack_pop(parser);
18892 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_DEF_TERM);
18898 pm_parser_scope_pop(parser);
18905 pm_constant_id_t name_id = pm_parser_constant_id_location(parser, name.
start, parse_operator_symbol_name(&name));
18907 flush_block_exits(parser, previous_block_exits);
18908 pm_node_list_free(¤t_block_exits);
18910 return UP(pm_def_node_create(
18926 case PM_TOKEN_KEYWORD_DEFINED: {
18927 parser_lex(parser);
18935 bool newline = accept1(parser, PM_TOKEN_NEWLINE);
18937 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
18940 if (newline && accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18941 expression = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->
previous, 0));
18942 lparen = not_provided(parser);
18943 rparen = not_provided(parser);
18945 expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
18948 rparen = not_provided(parser);
18950 accept1(parser, PM_TOKEN_NEWLINE);
18951 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
18956 lparen = not_provided(parser);
18957 rparen = not_provided(parser);
18958 expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
18961 context_pop(parser);
18962 return UP(pm_defined_node_create(
18970 case PM_TOKEN_KEYWORD_END_UPCASE: {
18971 if (binding_power != PM_BINDING_POWER_STATEMENT) {
18972 pm_parser_err_current(parser, PM_ERR_STATEMENT_POSTEXE_END);
18975 parser_lex(parser);
18978 if (context_def_p(parser)) {
18979 pm_parser_warn_token(parser, &keyword, PM_WARN_END_IN_METHOD);
18982 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_END_UPCASE_BRACE);
18986 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM);
18987 return UP(pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous));
18989 case PM_TOKEN_KEYWORD_FALSE:
18990 parser_lex(parser);
18991 return UP(pm_false_node_create(parser, &parser->
previous));
18992 case PM_TOKEN_KEYWORD_FOR: {
18993 size_t opening_newline_index = token_newline_index(parser);
18994 parser_lex(parser);
19002 if (accept1(parser, PM_TOKEN_USTAR)) {
19006 if (token_begins_expression_p(parser->
current.type)) {
19007 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19010 index = UP(pm_splat_node_create(parser, &star_operator, name));
19011 }
else if (token_begins_expression_p(parser->
current.type)) {
19012 index = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
19014 pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX);
19015 index = UP(pm_missing_node_create(parser, for_keyword.
start, for_keyword.
end));
19019 if (match1(parser, PM_TOKEN_COMMA)) {
19020 index = parse_targets(parser, index, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19022 index = parse_target(parser, index,
false,
false);
19025 context_pop(parser);
19026 pm_do_loop_stack_push(parser,
true);
19028 expect1(parser, PM_TOKEN_KEYWORD_IN, PM_ERR_FOR_IN);
19031 pm_node_t *collection = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_FOR_COLLECTION, (uint16_t) (depth + 1));
19032 pm_do_loop_stack_pop(parser);
19035 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19038 do_keyword = not_provided(parser);
19039 if (!match2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE)) {
19045 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19046 statements = parse_statements(parser,
PM_CONTEXT_FOR, (uint16_t) (depth + 1));
19049 parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword,
false,
false);
19050 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM);
19052 return UP(pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, &do_keyword, &parser->
previous));
19054 case PM_TOKEN_KEYWORD_IF:
19055 if (parser_end_of_line_p(parser)) {
19056 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
19059 size_t opening_newline_index = token_newline_index(parser);
19060 bool if_after_else = parser->
previous.
type == PM_TOKEN_KEYWORD_ELSE;
19061 parser_lex(parser);
19063 return parse_conditional(parser,
PM_CONTEXT_IF, opening_newline_index, if_after_else, (uint16_t) (depth + 1));
19064 case PM_TOKEN_KEYWORD_UNDEF: {
19065 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19066 pm_parser_err_current(parser, PM_ERR_STATEMENT_UNDEF);
19069 parser_lex(parser);
19071 pm_node_t *name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19073 if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) {
19074 pm_node_destroy(parser, name);
19076 pm_undef_node_append(undef, name);
19078 while (match1(parser, PM_TOKEN_COMMA)) {
19079 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
19080 parser_lex(parser);
19081 name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19083 if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) {
19084 pm_node_destroy(parser, name);
19088 pm_undef_node_append(undef, name);
19094 case PM_TOKEN_KEYWORD_NOT: {
19095 parser_lex(parser);
19104 if (!accepts_command_call && !match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19105 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES)) {
19106 pm_parser_err(parser, parser->
previous.
end, parser->
previous.
end + 1, PM_ERR_EXPECT_LPAREN_AFTER_NOT_LPAREN);
19108 accept1(parser, PM_TOKEN_NEWLINE);
19109 pm_parser_err_current(parser, PM_ERR_EXPECT_LPAREN_AFTER_NOT_OTHER);
19112 return UP(pm_missing_node_create(parser, parser->
current.start, parser->
current.end));
19115 accept1(parser, PM_TOKEN_NEWLINE);
19117 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19120 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19121 receiver = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->
previous, 0));
19123 arguments.
opening_loc = PM_LOCATION_TOKEN_VALUE(&lparen);
19124 receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19127 accept1(parser, PM_TOKEN_NEWLINE);
19128 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19133 receiver = parse_expression(parser, PM_BINDING_POWER_NOT,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19136 return UP(pm_call_node_not_create(parser, receiver, &message, &arguments));
19138 case PM_TOKEN_KEYWORD_UNLESS: {
19139 size_t opening_newline_index = token_newline_index(parser);
19140 parser_lex(parser);
19142 return parse_conditional(parser,
PM_CONTEXT_UNLESS, opening_newline_index,
false, (uint16_t) (depth + 1));
19144 case PM_TOKEN_KEYWORD_MODULE: {
19146 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19148 size_t opening_newline_index = token_newline_index(parser);
19149 parser_lex(parser);
19152 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_MODULE_NAME, (uint16_t) (depth + 1));
19157 if (PM_NODE_TYPE_P(constant_path, PM_MISSING_NODE)) {
19158 pop_block_exits(parser, previous_block_exits);
19159 pm_node_list_free(¤t_block_exits);
19162 return UP(pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing));
19165 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
19168 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
19169 constant_path = UP(pm_constant_path_node_create(parser, constant_path, &double_colon, &parser->
previous));
19176 if (name.
type != PM_TOKEN_CONSTANT) {
19177 pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
19180 pm_parser_scope_push(parser,
true);
19181 accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE);
19184 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19185 pm_accepts_block_stack_push(parser,
true);
19186 statements = UP(parse_statements(parser,
PM_CONTEXT_MODULE, (uint16_t) (depth + 1)));
19187 pm_accepts_block_stack_pop(parser);
19190 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
19191 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
19192 statements = UP(parse_rescues_implicit_begin(parser, opening_newline_index, &module_keyword, module_keyword.
start, (
pm_statements_node_t *) statements, PM_RESCUES_MODULE, (uint16_t) (depth + 1)));
19194 parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword,
false,
false);
19200 pm_parser_scope_pop(parser);
19201 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM);
19203 if (context_def_p(parser)) {
19204 pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
19207 pop_block_exits(parser, previous_block_exits);
19208 pm_node_list_free(¤t_block_exits);
19210 return UP(pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->
previous));
19212 case PM_TOKEN_KEYWORD_NIL:
19213 parser_lex(parser);
19214 return UP(pm_nil_node_create(parser, &parser->
previous));
19215 case PM_TOKEN_KEYWORD_REDO: {
19216 parser_lex(parser);
19223 case PM_TOKEN_KEYWORD_RETRY: {
19224 parser_lex(parser);
19227 parse_retry(parser, node);
19231 case PM_TOKEN_KEYWORD_SELF:
19232 parser_lex(parser);
19233 return UP(pm_self_node_create(parser, &parser->
previous));
19234 case PM_TOKEN_KEYWORD_TRUE:
19235 parser_lex(parser);
19236 return UP(pm_true_node_create(parser, &parser->
previous));
19237 case PM_TOKEN_KEYWORD_UNTIL: {
19238 size_t opening_newline_index = token_newline_index(parser);
19241 pm_do_loop_stack_push(parser,
true);
19243 parser_lex(parser);
19245 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
19247 pm_do_loop_stack_pop(parser);
19248 context_pop(parser);
19251 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19254 do_keyword = not_provided(parser);
19255 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
19259 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19260 pm_accepts_block_stack_push(parser,
true);
19261 statements = parse_statements(parser,
PM_CONTEXT_UNTIL, (uint16_t) (depth + 1));
19262 pm_accepts_block_stack_pop(parser);
19263 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19266 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19267 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM);
19269 return UP(pm_until_node_create(parser, &keyword, &do_keyword, &parser->
previous, predicate, statements, 0));
19271 case PM_TOKEN_KEYWORD_WHILE: {
19272 size_t opening_newline_index = token_newline_index(parser);
19275 pm_do_loop_stack_push(parser,
true);
19277 parser_lex(parser);
19279 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
19281 pm_do_loop_stack_pop(parser);
19282 context_pop(parser);
19285 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19288 do_keyword = not_provided(parser);
19289 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
19293 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19294 pm_accepts_block_stack_push(parser,
true);
19295 statements = parse_statements(parser,
PM_CONTEXT_WHILE, (uint16_t) (depth + 1));
19296 pm_accepts_block_stack_pop(parser);
19297 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19300 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19301 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM);
19303 return UP(pm_while_node_create(parser, &keyword, &do_keyword, &parser->
previous, predicate, statements, 0));
19305 case PM_TOKEN_PERCENT_LOWER_I: {
19306 parser_lex(parser);
19311 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19312 accept1(parser, PM_TOKEN_WORDS_SEP);
19313 if (match1(parser, PM_TOKEN_STRING_END))
break;
19317 while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19322 if (current == NULL) {
19323 current = UP(pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing));
19324 parser_lex(parser);
19325 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
19326 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, &opening, &parser->
current, &closing));
19327 parser_lex(parser);
19329 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19334 pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &cast->
unescaped));
19335 pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, &opening, &parser->
previous, &closing));
19336 parser_lex(parser);
19339 pm_interpolated_symbol_node_append(interpolated, first_string);
19340 pm_interpolated_symbol_node_append(interpolated, second_string);
19343 current = UP(interpolated);
19345 assert(
false &&
"unreachable");
19350 pm_array_node_elements_append(array, current);
19353 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_LOWER_ELEMENT);
19358 if (match1(parser, PM_TOKEN_EOF)) {
19359 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
19362 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_LOWER_TERM);
19364 pm_array_node_close_set(array, &closing);
19368 case PM_TOKEN_PERCENT_UPPER_I: {
19369 parser_lex(parser);
19377 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19378 switch (parser->
current.type) {
19379 case PM_TOKEN_WORDS_SEP: {
19380 if (current == NULL) {
19386 pm_array_node_elements_append(array, current);
19390 parser_lex(parser);
19393 case PM_TOKEN_STRING_CONTENT: {
19397 if (current == NULL) {
19401 current = UP(pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing));
19402 parser_lex(parser);
19403 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
19407 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, &opening, &parser->
current, &closing));
19408 parser_lex(parser);
19411 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19419 pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &cast->
unescaped));
19420 pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, &opening, &parser->
previous, &closing));
19421 parser_lex(parser);
19424 pm_interpolated_symbol_node_append(interpolated, first_string);
19425 pm_interpolated_symbol_node_append(interpolated, second_string);
19428 current = UP(interpolated);
19430 assert(
false &&
"unreachable");
19435 case PM_TOKEN_EMBVAR: {
19436 bool start_location_set =
false;
19437 if (current == NULL) {
19443 current = UP(pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing));
19444 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19452 current = UP(pm_symbol_node_to_string_node(parser, (
pm_symbol_node_t *) current));
19453 pm_interpolated_symbol_node_append(interpolated, current);
19455 start_location_set =
true;
19456 current = UP(interpolated);
19462 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19464 if (!start_location_set) {
19469 case PM_TOKEN_EMBEXPR_BEGIN: {
19470 bool start_location_set =
false;
19471 if (current == NULL) {
19477 current = UP(pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing));
19478 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19487 current = UP(pm_symbol_node_to_string_node(parser, (
pm_symbol_node_t *) current));
19488 pm_interpolated_symbol_node_append(interpolated, current);
19490 start_location_set =
true;
19491 current = UP(interpolated);
19492 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
19496 assert(
false &&
"unreachable");
19499 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19501 if (!start_location_set) {
19507 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_UPPER_ELEMENT);
19508 parser_lex(parser);
19515 pm_array_node_elements_append(array, current);
19519 if (match1(parser, PM_TOKEN_EOF)) {
19520 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_UPPER_TERM);
19523 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_UPPER_TERM);
19525 pm_array_node_close_set(array, &closing);
19529 case PM_TOKEN_PERCENT_LOWER_W: {
19530 parser_lex(parser);
19535 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19536 accept1(parser, PM_TOKEN_WORDS_SEP);
19537 if (match1(parser, PM_TOKEN_STRING_END))
break;
19541 while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19545 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, &opening, &parser->
current, &closing));
19548 if (current == NULL) {
19550 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
19552 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19554 pm_interpolated_string_node_append(interpolated, current);
19555 pm_interpolated_string_node_append(interpolated,
string);
19556 current = UP(interpolated);
19558 assert(
false &&
"unreachable");
19560 parser_lex(parser);
19564 pm_array_node_elements_append(array, current);
19567 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_LOWER_ELEMENT);
19572 if (match1(parser, PM_TOKEN_EOF)) {
19573 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_LOWER_TERM);
19576 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_LOWER_TERM);
19579 pm_array_node_close_set(array, &closing);
19582 case PM_TOKEN_PERCENT_UPPER_W: {
19583 parser_lex(parser);
19591 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19592 switch (parser->
current.type) {
19593 case PM_TOKEN_WORDS_SEP: {
19598 if (current == NULL) {
19605 pm_array_node_elements_append(array, current);
19609 parser_lex(parser);
19612 case PM_TOKEN_STRING_CONTENT: {
19616 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, &opening, &parser->
current, &closing));
19617 pm_node_flag_set(
string, parse_unescaped_encoding(parser));
19618 parser_lex(parser);
19620 if (current == NULL) {
19626 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
19631 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19637 pm_interpolated_string_node_append(interpolated, current);
19638 pm_interpolated_string_node_append(interpolated,
string);
19639 current = UP(interpolated);
19641 assert(
false &&
"unreachable");
19646 case PM_TOKEN_EMBVAR: {
19647 if (current == NULL) {
19654 current = UP(pm_interpolated_string_node_create(parser, &opening, NULL, &closing));
19655 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19663 pm_interpolated_string_node_append(interpolated, current);
19664 current = UP(interpolated);
19671 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19675 case PM_TOKEN_EMBEXPR_BEGIN: {
19676 if (current == NULL) {
19683 current = UP(pm_interpolated_string_node_create(parser, &opening, NULL, &closing));
19684 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19692 pm_interpolated_string_node_append(interpolated, current);
19693 current = UP(interpolated);
19694 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
19699 assert(
false &&
"unreachable");
19702 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19707 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_UPPER_ELEMENT);
19708 parser_lex(parser);
19715 pm_array_node_elements_append(array, current);
19719 if (match1(parser, PM_TOKEN_EOF)) {
19720 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_UPPER_TERM);
19723 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_UPPER_TERM);
19726 pm_array_node_close_set(array, &closing);
19729 case PM_TOKEN_REGEXP_BEGIN: {
19731 parser_lex(parser);
19733 if (match1(parser, PM_TOKEN_REGEXP_END)) {
19738 .
type = PM_TOKEN_STRING_CONTENT,
19743 parser_lex(parser);
19745 pm_node_t *node = UP(pm_regular_expression_node_create(parser, &opening, &content, &parser->
previous));
19746 pm_node_flag_set(node, PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING);
19753 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19761 parser_lex(parser);
19766 if (accept1(parser, PM_TOKEN_REGEXP_END)) {
19773 if (!match1(parser, PM_TOKEN_EQUAL_TILDE)) {
19774 parse_regular_expression_errors(parser, node);
19777 pm_node_flag_set(UP(node), parse_and_validate_regular_expression_encoding(parser, &unescaped, ascii_only, FL(node)));
19783 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
19787 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, &opening, &parser->
previous, &closing, &unescaped));
19793 pm_node_flag_set(part, PM_STRING_FLAGS_FORCED_BINARY_ENCODING);
19796 pm_interpolated_regular_expression_node_append(interpolated, part);
19801 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
19807 while (!match2(parser, PM_TOKEN_REGEXP_END, PM_TOKEN_EOF)) {
19808 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
19809 pm_interpolated_regular_expression_node_append(interpolated, part);
19814 if (match1(parser, PM_TOKEN_EOF)) {
19815 pm_parser_err_token(parser, &opening, PM_ERR_REGEXP_TERM);
19818 expect1(parser, PM_TOKEN_REGEXP_END, PM_ERR_REGEXP_TERM);
19821 pm_interpolated_regular_expression_node_closing_set(parser, interpolated, &closing);
19822 return UP(interpolated);
19824 case PM_TOKEN_BACKTICK:
19825 case PM_TOKEN_PERCENT_LOWER_X: {
19826 parser_lex(parser);
19833 if (match1(parser, PM_TOKEN_STRING_END)) {
19838 .
type = PM_TOKEN_STRING_CONTENT,
19843 parser_lex(parser);
19844 return UP(pm_xstring_node_create(parser, &opening, &content, &parser->
previous));
19849 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19856 parser_lex(parser);
19858 if (match1(parser, PM_TOKEN_STRING_END)) {
19859 pm_node_t *node = UP(pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped));
19860 pm_node_flag_set(node, parse_unescaped_encoding(parser));
19861 parser_lex(parser);
19867 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
19872 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, &opening, &parser->
previous, &closing, &unescaped));
19873 pm_node_flag_set(part, parse_unescaped_encoding(parser));
19875 pm_interpolated_xstring_node_append(node, part);
19880 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
19884 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19885 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
19886 pm_interpolated_xstring_node_append(node, part);
19891 if (match1(parser, PM_TOKEN_EOF)) {
19892 pm_parser_err_token(parser, &opening, PM_ERR_XSTRING_TERM);
19895 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_XSTRING_TERM);
19897 pm_interpolated_xstring_node_closing_set(node, &closing);
19901 case PM_TOKEN_USTAR: {
19902 parser_lex(parser);
19907 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19908 pm_parser_err_prefix(parser, diag_id);
19915 if (token_begins_expression_p(parser->
current.type)) {
19916 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19919 pm_node_t *splat = UP(pm_splat_node_create(parser, &
operator, name));
19921 if (match1(parser, PM_TOKEN_COMMA)) {
19922 return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19924 return parse_target_validate(parser, splat,
true);
19927 case PM_TOKEN_BANG: {
19928 if (binding_power > PM_BINDING_POWER_UNARY) {
19929 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
19932 parser_lex(parser);
19935 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));
19936 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"!");
19938 pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
19941 case PM_TOKEN_TILDE: {
19942 if (binding_power > PM_BINDING_POWER_UNARY) {
19943 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
19945 parser_lex(parser);
19948 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
19949 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"~");
19953 case PM_TOKEN_UMINUS: {
19954 if (binding_power > PM_BINDING_POWER_UNARY) {
19955 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
19957 parser_lex(parser);
19960 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
19961 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"-@");
19965 case PM_TOKEN_UMINUS_NUM: {
19966 parser_lex(parser);
19969 pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
19971 if (accept1(parser, PM_TOKEN_STAR_STAR)) {
19973 pm_node_t *exponent = parse_expression(parser, pm_binding_powers[exponent_operator.
type].right,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
19974 node = UP(pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0));
19975 node = UP(pm_call_node_unary_create(parser, &
operator, node,
"-@"));
19977 switch (PM_NODE_TYPE(node)) {
19978 case PM_INTEGER_NODE:
19979 case PM_FLOAT_NODE:
19980 case PM_RATIONAL_NODE:
19981 case PM_IMAGINARY_NODE:
19982 parse_negative_numeric(node);
19985 node = UP(pm_call_node_unary_create(parser, &
operator, node,
"-@"));
19992 case PM_TOKEN_MINUS_GREATER: {
19996 size_t opening_newline_index = token_newline_index(parser);
19997 pm_accepts_block_stack_push(parser,
true);
19998 parser_lex(parser);
20001 pm_parser_scope_push(parser,
false);
20005 switch (parser->
current.type) {
20006 case PM_TOKEN_PARENTHESIS_LEFT: {
20008 parser_lex(parser);
20010 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
20011 block_parameters = pm_block_parameters_node_create(parser, NULL, &opening);
20013 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
true, (uint16_t) (depth + 1));
20016 accept1(parser, PM_TOKEN_NEWLINE);
20017 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
20019 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
20022 case PM_CASE_PARAMETER: {
20023 pm_accepts_block_stack_push(parser,
false);
20025 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
false, (uint16_t) (depth + 1));
20026 pm_accepts_block_stack_pop(parser);
20030 block_parameters = NULL;
20039 if (accept1(parser, PM_TOKEN_LAMBDA_BEGIN)) {
20042 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
20046 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20047 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE);
20049 expect1(parser, PM_TOKEN_KEYWORD_DO, PM_ERR_LAMBDA_OPEN);
20052 if (!match3(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20053 pm_accepts_block_stack_push(parser,
true);
20055 pm_accepts_block_stack_pop(parser);
20058 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20059 assert(body == NULL || PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE));
20060 body = UP(parse_rescues_implicit_begin(parser, opening_newline_index, &
operator, opening.
start, (
pm_statements_node_t *) body, PM_RESCUES_LAMBDA, (uint16_t) (depth + 1)));
20062 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20065 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END);
20069 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
20070 pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &
operator, &parser->
previous);
20072 pm_parser_scope_pop(parser);
20073 pm_accepts_block_stack_pop(parser);
20075 return UP(pm_lambda_node_create(parser, &locals, &
operator, &opening, &parser->
previous, parameters, body));
20077 case PM_TOKEN_UPLUS: {
20078 if (binding_power > PM_BINDING_POWER_UNARY) {
20079 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20081 parser_lex(parser);
20084 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20085 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"+@");
20089 case PM_TOKEN_STRING_BEGIN:
20090 return parse_strings(parser, NULL, accepts_label, (uint16_t) (depth + 1));
20091 case PM_TOKEN_SYMBOL_BEGIN: {
20093 parser_lex(parser);
20095 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_END, (uint16_t) (depth + 1));
20106 if (diag_id != PM_ERR_CANNOT_PARSE_EXPRESSION) {
20107 pm_parser_err_prefix(parser, diag_id);
20113 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT,
pm_token_type_human(parser->
current.type), context_human(recoverable));
20114 }
else if (diag_id == PM_ERR_CANNOT_PARSE_EXPRESSION) {
20120 pm_parser_err_prefix(parser, diag_id);
20138parse_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) {
20139 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));
20143 if (match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
20147 parser_lex(parser);
20149 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));
20150 context_pop(parser);
20152 return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
20164 switch (PM_NODE_TYPE(node)) {
20165 case PM_BEGIN_NODE: {
20170 case PM_LOCAL_VARIABLE_WRITE_NODE: {
20172 pm_locals_read(&pm_parser_scope_find(parser, cast->
depth)->
locals, cast->
name);
20175 case PM_PARENTHESES_NODE: {
20177 if (cast->
body != NULL) parse_assignment_value_local(parser, cast->
body);
20180 case PM_STATEMENTS_NODE: {
20185 parse_assignment_value_local(parser, statement);
20207parse_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) {
20208 bool permitted =
true;
20209 if (previous_binding_power != PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_USTAR)) permitted =
false;
20211 pm_node_t *value = parse_starred_expression(parser, binding_power, previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? accepts_command_call : previous_binding_power < PM_BINDING_POWER_MODIFIER, diag_id, (uint16_t) (depth + 1));
20212 if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE);
20214 parse_assignment_value_local(parser, value);
20215 bool single_value =
true;
20217 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && (PM_NODE_TYPE_P(value, PM_SPLAT_NODE) || match1(parser, PM_TOKEN_COMMA))) {
20218 single_value =
false;
20223 pm_array_node_elements_append(array, value);
20226 while (accept1(parser, PM_TOKEN_COMMA)) {
20227 pm_node_t *element = parse_starred_expression(parser, binding_power,
false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1));
20229 pm_array_node_elements_append(array, element);
20230 if (PM_NODE_TYPE_P(element, PM_MISSING_NODE))
break;
20232 parse_assignment_value_local(parser, element);
20238 if ((single_value || (binding_power == (PM_BINDING_POWER_MULTI_ASSIGNMENT + 1))) && match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
20242 parser_lex(parser);
20244 bool accepts_command_call_inner =
false;
20248 if (PM_NODE_TYPE_P(value, PM_CALL_NODE)) {
20251 accepts_command_call_inner =
true;
20255 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));
20256 context_pop(parser);
20258 return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
20274 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_ARGUMENTS);
20275 pm_node_unreference(parser, UP(call_node->
arguments));
20276 pm_node_destroy(parser, UP(call_node->
arguments));
20280 if (call_node->
block != NULL) {
20281 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_BLOCK);
20282 pm_node_unreference(parser, UP(call_node->
block));
20283 pm_node_destroy(parser, UP(call_node->
block));
20284 call_node->
block = NULL;
20313static inline const uint8_t *
20314pm_named_capture_escape_hex(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
20317 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
20318 uint8_t value = escape_hexadecimal_digit(*cursor);
20321 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
20322 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(*cursor));
20326 pm_buffer_append_byte(unescaped, value);
20328 pm_buffer_append_string(unescaped,
"\\x", 2);
20334static inline const uint8_t *
20335pm_named_capture_escape_octal(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
20336 uint8_t value = (uint8_t) (*cursor -
'0');
20339 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
20340 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
20343 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
20344 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
20349 pm_buffer_append_byte(unescaped, value);
20353static inline const uint8_t *
20354pm_named_capture_escape_unicode(
pm_parser_t *parser,
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
20355 const uint8_t *start = cursor - 1;
20358 if (cursor >= end) {
20359 pm_buffer_append_string(unescaped,
"\\u", 2);
20363 if (*cursor !=
'{') {
20364 size_t length = pm_strspn_hexadecimal_digit(cursor, MIN(end - cursor, 4));
20365 uint32_t value = escape_unicode(parser, cursor, length);
20367 if (!pm_buffer_append_unicode_codepoint(unescaped, value)) {
20368 pm_buffer_append_string(unescaped, (
const char *) start, (
size_t) ((cursor + length) - start));
20371 return cursor + length;
20376 while (cursor < end && *cursor ==
' ') cursor++;
20378 if (cursor >= end)
break;
20379 if (*cursor ==
'}') {
20384 size_t length = pm_strspn_hexadecimal_digit(cursor, end - cursor);
20385 uint32_t value = escape_unicode(parser, cursor, length);
20387 (void) pm_buffer_append_unicode_codepoint(unescaped, value);
20395pm_named_capture_escape(
pm_parser_t *parser,
pm_buffer_t *unescaped,
const uint8_t *source,
const size_t length,
const uint8_t *cursor) {
20396 const uint8_t *end = source + length;
20397 pm_buffer_append_string(unescaped, (
const char *) source, (
size_t) (cursor - source));
20400 if (++cursor >= end) {
20401 pm_buffer_append_byte(unescaped,
'\\');
20407 cursor = pm_named_capture_escape_hex(unescaped, cursor, end);
20409 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
20410 cursor = pm_named_capture_escape_octal(unescaped, cursor, end);
20413 cursor = pm_named_capture_escape_unicode(parser, unescaped, cursor, end);
20416 pm_buffer_append_byte(unescaped,
'\\');
20420 const uint8_t *next_cursor = pm_memchr(cursor,
'\\', (
size_t) (end - cursor), parser->
encoding_changed, parser->
encoding);
20421 if (next_cursor == NULL)
break;
20423 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (next_cursor - cursor));
20424 cursor = next_cursor;
20427 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (end - cursor));
20435parse_regular_expression_named_capture(
const pm_string_t *capture,
void *data) {
20456 pm_named_capture_escape(parser, &unescaped, source, length, cursor);
20466 if (!pm_slice_is_valid_local(parser, source, source + length)) {
20471 if (callback_data->
shared) {
20475 name = pm_parser_constant_id_location(parser, location.
start, location.
end);
20481 void *memory =
xmalloc(length);
20482 if (memory == NULL) abort();
20484 memcpy(memory, source, length);
20485 name = pm_parser_constant_id_owned(parser, (uint8_t *) memory, length);
20490 if (name != 0 && !pm_constant_id_list_includes(names, name)) {
20491 pm_constant_id_list_append(names, name);
20494 if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
20497 if (pm_local_is_keyword((
const char *) source, length)) {
20504 pm_parser_local_add(parser, name, location.
start, location.
end, 0);
20509 if (callback_data->
match == NULL) {
20510 callback_data->
match = pm_match_write_node_create(parser, call);
20515 pm_node_t *target = UP(pm_local_variable_target_node_create(parser, &location, name, depth == -1 ? 0 : (uint32_t) depth));
20516 pm_node_list_append(&callback_data->
match->
targets, target);
20532 .shared = content->
type == PM_STRING_SHARED
20539 .shared = content->
type == PM_STRING_SHARED
20542 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);
20543 pm_constant_id_list_free(&callback_data.
names);
20545 if (callback_data.
match != NULL) {
20546 return UP(callback_data.
match);
20553parse_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) {
20556 switch (token.type) {
20557 case PM_TOKEN_EQUAL: {
20558 switch (PM_NODE_TYPE(node)) {
20559 case PM_CALL_NODE: {
20565 if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
20570 case PM_CASE_WRITABLE: {
20574 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
20578 parser_lex(parser);
20579 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));
20581 if (PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) && previous_binding_power != PM_BINDING_POWER_STATEMENT) {
20582 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_MULTI_WRITE);
20585 return parse_write(parser, node, &token, value);
20587 case PM_SPLAT_NODE: {
20589 pm_multi_target_node_targets_append(parser, multi_target, node);
20591 parser_lex(parser);
20592 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));
20593 return parse_write(parser, UP(multi_target), &token, value);
20595 case PM_SOURCE_ENCODING_NODE:
20596 case PM_FALSE_NODE:
20597 case PM_SOURCE_FILE_NODE:
20598 case PM_SOURCE_LINE_NODE:
20601 case PM_TRUE_NODE: {
20604 parser_lex(parser);
20605 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));
20606 return parse_unwriteable_write(parser, node, &token, value);
20612 parser_lex(parser);
20613 pm_parser_err_token(parser, &token, PM_ERR_EXPRESSION_NOT_WRITABLE);
20617 case PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL: {
20618 switch (PM_NODE_TYPE(node)) {
20619 case PM_BACK_REFERENCE_READ_NODE:
20620 case PM_NUMBERED_REFERENCE_READ_NODE:
20621 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
20623 case PM_GLOBAL_VARIABLE_READ_NODE: {
20624 parser_lex(parser);
20626 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));
20627 pm_node_t *result = UP(pm_global_variable_and_write_node_create(parser, node, &token, value));
20629 pm_node_destroy(parser, node);
20632 case PM_CLASS_VARIABLE_READ_NODE: {
20633 parser_lex(parser);
20635 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));
20638 pm_node_destroy(parser, node);
20641 case PM_CONSTANT_PATH_NODE: {
20642 parser_lex(parser);
20644 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));
20647 return parse_shareable_constant_write(parser, write);
20649 case PM_CONSTANT_READ_NODE: {
20650 parser_lex(parser);
20652 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));
20655 pm_node_destroy(parser, node);
20656 return parse_shareable_constant_write(parser, write);
20658 case PM_INSTANCE_VARIABLE_READ_NODE: {
20659 parser_lex(parser);
20661 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));
20664 pm_node_destroy(parser, node);
20667 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
20669 parser_lex(parser);
20671 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));
20672 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &token, value, name, 0));
20674 pm_node_unreference(parser, node);
20675 pm_node_destroy(parser, node);
20678 case PM_LOCAL_VARIABLE_READ_NODE: {
20681 pm_node_unreference(parser, node);
20685 parser_lex(parser);
20687 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));
20688 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
20690 pm_node_destroy(parser, node);
20693 case PM_CALL_NODE: {
20699 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
20701 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
20704 parser_lex(parser);
20706 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));
20707 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
20709 pm_node_destroy(parser, UP(cast));
20715 parser_lex(parser);
20720 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
20721 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20722 return UP(pm_index_and_write_node_create(parser, cast, &token, value));
20726 if (pm_call_node_writable_p(parser, cast)) {
20727 parse_write_name(parser, &cast->
name);
20729 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
20732 parse_call_operator_write(parser, cast, &token);
20733 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));
20734 return UP(pm_call_and_write_node_create(parser, cast, &token, value));
20736 case PM_MULTI_WRITE_NODE: {
20737 parser_lex(parser);
20738 pm_parser_err_token(parser, &token, PM_ERR_AMPAMPEQ_MULTI_ASSIGN);
20742 parser_lex(parser);
20747 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
20751 case PM_TOKEN_PIPE_PIPE_EQUAL: {
20752 switch (PM_NODE_TYPE(node)) {
20753 case PM_BACK_REFERENCE_READ_NODE:
20754 case PM_NUMBERED_REFERENCE_READ_NODE:
20755 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
20757 case PM_GLOBAL_VARIABLE_READ_NODE: {
20758 parser_lex(parser);
20760 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));
20761 pm_node_t *result = UP(pm_global_variable_or_write_node_create(parser, node, &token, value));
20763 pm_node_destroy(parser, node);
20766 case PM_CLASS_VARIABLE_READ_NODE: {
20767 parser_lex(parser);
20769 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));
20772 pm_node_destroy(parser, node);
20775 case PM_CONSTANT_PATH_NODE: {
20776 parser_lex(parser);
20778 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));
20781 return parse_shareable_constant_write(parser, write);
20783 case PM_CONSTANT_READ_NODE: {
20784 parser_lex(parser);
20786 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));
20789 pm_node_destroy(parser, node);
20790 return parse_shareable_constant_write(parser, write);
20792 case PM_INSTANCE_VARIABLE_READ_NODE: {
20793 parser_lex(parser);
20795 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));
20798 pm_node_destroy(parser, node);
20801 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
20803 parser_lex(parser);
20805 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));
20806 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &token, value, name, 0));
20808 pm_node_unreference(parser, node);
20809 pm_node_destroy(parser, node);
20812 case PM_LOCAL_VARIABLE_READ_NODE: {
20815 pm_node_unreference(parser, node);
20819 parser_lex(parser);
20821 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));
20822 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
20824 pm_node_destroy(parser, node);
20827 case PM_CALL_NODE: {
20833 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
20835 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
20838 parser_lex(parser);
20840 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));
20841 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
20843 pm_node_destroy(parser, UP(cast));
20849 parser_lex(parser);
20854 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
20855 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20856 return UP(pm_index_or_write_node_create(parser, cast, &token, value));
20860 if (pm_call_node_writable_p(parser, cast)) {
20861 parse_write_name(parser, &cast->
name);
20863 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
20866 parse_call_operator_write(parser, cast, &token);
20867 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));
20868 return UP(pm_call_or_write_node_create(parser, cast, &token, value));
20870 case PM_MULTI_WRITE_NODE: {
20871 parser_lex(parser);
20872 pm_parser_err_token(parser, &token, PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN);
20876 parser_lex(parser);
20881 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
20885 case PM_TOKEN_AMPERSAND_EQUAL:
20886 case PM_TOKEN_CARET_EQUAL:
20887 case PM_TOKEN_GREATER_GREATER_EQUAL:
20888 case PM_TOKEN_LESS_LESS_EQUAL:
20889 case PM_TOKEN_MINUS_EQUAL:
20890 case PM_TOKEN_PERCENT_EQUAL:
20891 case PM_TOKEN_PIPE_EQUAL:
20892 case PM_TOKEN_PLUS_EQUAL:
20893 case PM_TOKEN_SLASH_EQUAL:
20894 case PM_TOKEN_STAR_EQUAL:
20895 case PM_TOKEN_STAR_STAR_EQUAL: {
20896 switch (PM_NODE_TYPE(node)) {
20897 case PM_BACK_REFERENCE_READ_NODE:
20898 case PM_NUMBERED_REFERENCE_READ_NODE:
20899 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
20901 case PM_GLOBAL_VARIABLE_READ_NODE: {
20902 parser_lex(parser);
20904 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));
20905 pm_node_t *result = UP(pm_global_variable_operator_write_node_create(parser, node, &token, value));
20907 pm_node_destroy(parser, node);
20910 case PM_CLASS_VARIABLE_READ_NODE: {
20911 parser_lex(parser);
20913 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));
20916 pm_node_destroy(parser, node);
20919 case PM_CONSTANT_PATH_NODE: {
20920 parser_lex(parser);
20922 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));
20925 return parse_shareable_constant_write(parser, write);
20927 case PM_CONSTANT_READ_NODE: {
20928 parser_lex(parser);
20930 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));
20933 pm_node_destroy(parser, node);
20934 return parse_shareable_constant_write(parser, write);
20936 case PM_INSTANCE_VARIABLE_READ_NODE: {
20937 parser_lex(parser);
20939 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));
20942 pm_node_destroy(parser, node);
20945 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
20947 parser_lex(parser);
20949 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));
20950 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &token, value, name, 0));
20952 pm_node_unreference(parser, node);
20953 pm_node_destroy(parser, node);
20956 case PM_LOCAL_VARIABLE_READ_NODE: {
20959 pm_node_unreference(parser, node);
20963 parser_lex(parser);
20965 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));
20966 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
20968 pm_node_destroy(parser, node);
20971 case PM_CALL_NODE: {
20972 parser_lex(parser);
20978 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
20980 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
20983 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));
20984 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
20986 pm_node_destroy(parser, UP(cast));
20993 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
20994 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));
20995 return UP(pm_index_operator_write_node_create(parser, cast, &token, value));
20999 if (pm_call_node_writable_p(parser, cast)) {
21000 parse_write_name(parser, &cast->
name);
21002 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21005 parse_call_operator_write(parser, cast, &token);
21006 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21007 return UP(pm_call_operator_write_node_create(parser, cast, &token, value));
21009 case PM_MULTI_WRITE_NODE: {
21010 parser_lex(parser);
21011 pm_parser_err_token(parser, &token, PM_ERR_OPERATOR_MULTI_ASSIGN);
21015 parser_lex(parser);
21024 case PM_TOKEN_AMPERSAND_AMPERSAND:
21025 case PM_TOKEN_KEYWORD_AND: {
21026 parser_lex(parser);
21028 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));
21029 return UP(pm_and_node_create(parser, node, &token, right));
21031 case PM_TOKEN_KEYWORD_OR:
21032 case PM_TOKEN_PIPE_PIPE: {
21033 parser_lex(parser);
21035 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));
21036 return UP(pm_or_node_create(parser, node, &token, right));
21038 case PM_TOKEN_EQUAL_TILDE: {
21046 parser_lex(parser);
21047 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21050 pm_call_node_t *call = pm_call_node_binary_create(parser, node, &token, argument, 0);
21056 if (PM_NODE_TYPE_P(node, PM_INTERPOLATED_REGULAR_EXPRESSION_NODE)) {
21063 bool interpolated =
false;
21064 size_t total_length = 0;
21068 if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
21071 interpolated =
true;
21076 if (!interpolated && total_length > 0) {
21077 void *memory =
xmalloc(total_length);
21078 if (!memory) abort();
21080 uint8_t *cursor = memory;
21090 pm_string_owned_init(&owned, (uint8_t *) memory, total_length);
21092 result = parse_regular_expression_named_captures(parser, &owned, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
21095 }
else if (PM_NODE_TYPE_P(node, PM_REGULAR_EXPRESSION_NODE)) {
21099 result = parse_regular_expression_named_captures(parser, content, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
21104 case PM_TOKEN_UAMPERSAND:
21105 case PM_TOKEN_USTAR:
21106 case PM_TOKEN_USTAR_STAR:
21109 case PM_TOKEN_BANG_EQUAL:
21110 case PM_TOKEN_BANG_TILDE:
21111 case PM_TOKEN_EQUAL_EQUAL:
21112 case PM_TOKEN_EQUAL_EQUAL_EQUAL:
21113 case PM_TOKEN_LESS_EQUAL_GREATER:
21114 case PM_TOKEN_CARET:
21115 case PM_TOKEN_PIPE:
21116 case PM_TOKEN_AMPERSAND:
21117 case PM_TOKEN_GREATER_GREATER:
21118 case PM_TOKEN_LESS_LESS:
21119 case PM_TOKEN_MINUS:
21120 case PM_TOKEN_PLUS:
21121 case PM_TOKEN_PERCENT:
21122 case PM_TOKEN_SLASH:
21123 case PM_TOKEN_STAR:
21124 case PM_TOKEN_STAR_STAR: {
21125 parser_lex(parser);
21127 switch (PM_NODE_TYPE(node)) {
21128 case PM_RESCUE_MODIFIER_NODE: {
21131 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21135 case PM_AND_NODE: {
21137 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21138 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21144 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21145 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21153 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21154 return UP(pm_call_node_binary_create(parser, node, &token, argument, 0));
21156 case PM_TOKEN_GREATER:
21157 case PM_TOKEN_GREATER_EQUAL:
21158 case PM_TOKEN_LESS:
21159 case PM_TOKEN_LESS_EQUAL: {
21160 if (PM_NODE_TYPE_P(node, PM_CALL_NODE) && PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_COMPARISON)) {
21161 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_COMPARISON_AFTER_COMPARISON);
21164 parser_lex(parser);
21165 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21166 return UP(pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON));
21168 case PM_TOKEN_AMPERSAND_DOT:
21169 case PM_TOKEN_DOT: {
21170 parser_lex(parser);
21175 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
21176 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21177 return UP(pm_call_node_shorthand_create(parser, node, &
operator, &arguments));
21180 switch (PM_NODE_TYPE(node)) {
21181 case PM_RESCUE_MODIFIER_NODE: {
21184 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21188 case PM_AND_NODE: {
21190 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21191 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21197 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21198 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21208 switch (parser->
current.type) {
21209 case PM_CASE_OPERATOR:
21210 case PM_CASE_KEYWORD:
21211 case PM_TOKEN_CONSTANT:
21212 case PM_TOKEN_IDENTIFIER:
21213 case PM_TOKEN_METHOD_NAME: {
21214 parser_lex(parser);
21224 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21225 pm_call_node_t *call = pm_call_node_call_create(parser, node, &
operator, &message, &arguments);
21228 (previous_binding_power == PM_BINDING_POWER_STATEMENT) &&
21231 match1(parser, PM_TOKEN_COMMA)
21233 return parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21238 case PM_TOKEN_DOT_DOT:
21239 case PM_TOKEN_DOT_DOT_DOT: {
21240 parser_lex(parser);
21243 if (token_begins_expression_p(parser->
current.type)) {
21244 right = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21247 return UP(pm_range_node_create(parser, node, &token, right));
21249 case PM_TOKEN_KEYWORD_IF_MODIFIER: {
21251 parser_lex(parser);
21253 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
21254 return UP(pm_if_node_modifier_create(parser, node, &keyword, predicate));
21256 case PM_TOKEN_KEYWORD_UNLESS_MODIFIER: {
21258 parser_lex(parser);
21260 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
21261 return UP(pm_unless_node_modifier_create(parser, node, &keyword, predicate));
21263 case PM_TOKEN_KEYWORD_UNTIL_MODIFIER: {
21264 parser_lex(parser);
21266 pm_statements_node_body_append(parser, statements, node,
true);
21268 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
21269 return UP(pm_until_node_modifier_create(parser, &token, predicate, statements, PM_NODE_TYPE_P(node, PM_BEGIN_NODE) ? PM_LOOP_FLAGS_BEGIN_MODIFIER : 0));
21271 case PM_TOKEN_KEYWORD_WHILE_MODIFIER: {
21272 parser_lex(parser);
21274 pm_statements_node_body_append(parser, statements, node,
true);
21276 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
21277 return UP(pm_while_node_modifier_create(parser, &token, predicate, statements, PM_NODE_TYPE_P(node, PM_BEGIN_NODE) ? PM_LOOP_FLAGS_BEGIN_MODIFIER : 0));
21279 case PM_TOKEN_QUESTION_MARK: {
21282 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
21285 parser_lex(parser);
21287 pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_TRUE, (uint16_t) (depth + 1));
21297 pm_node_t *false_expression = UP(pm_missing_node_create(parser, colon.
start, colon.
end));
21299 context_pop(parser);
21300 pop_block_exits(parser, previous_block_exits);
21301 pm_node_list_free(¤t_block_exits);
21303 return UP(pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression));
21306 accept1(parser, PM_TOKEN_NEWLINE);
21307 expect1(parser, PM_TOKEN_COLON, PM_ERR_TERNARY_COLON);
21310 pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_FALSE, (uint16_t) (depth + 1));
21312 context_pop(parser);
21313 pop_block_exits(parser, previous_block_exits);
21314 pm_node_list_free(¤t_block_exits);
21316 return UP(pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression));
21318 case PM_TOKEN_COLON_COLON: {
21319 parser_lex(parser);
21322 switch (parser->
current.type) {
21323 case PM_TOKEN_CONSTANT: {
21324 parser_lex(parser);
21328 (parser->
current.type == PM_TOKEN_PARENTHESIS_LEFT) ||
21329 (accepts_command_call && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)))
21340 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21341 path = UP(pm_call_node_call_create(parser, node, &delimiter, &message, &arguments));
21344 path = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous));
21348 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
21349 return parse_targets_validate(parser, path, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21354 case PM_CASE_OPERATOR:
21355 case PM_CASE_KEYWORD:
21356 case PM_TOKEN_IDENTIFIER:
21357 case PM_TOKEN_METHOD_NAME: {
21358 parser_lex(parser);
21364 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21365 pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
21368 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
21369 return parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21374 case PM_TOKEN_PARENTHESIS_LEFT: {
21378 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21380 return UP(pm_call_node_shorthand_create(parser, node, &delimiter, &arguments));
21383 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
21384 return UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous));
21388 case PM_TOKEN_KEYWORD_RESCUE_MODIFIER: {
21390 parser_lex(parser);
21391 accept1(parser, PM_TOKEN_NEWLINE);
21393 pm_node_t *value = parse_expression(parser, binding_power,
true,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
21394 context_pop(parser);
21396 return UP(pm_rescue_modifier_node_create(parser, node, &token, value));
21398 case PM_TOKEN_BRACKET_LEFT: {
21399 parser_lex(parser);
21404 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
21405 pm_accepts_block_stack_push(parser,
true);
21406 parse_arguments(parser, &arguments,
false, PM_TOKEN_BRACKET_RIGHT, (uint16_t) (depth + 1));
21407 pm_accepts_block_stack_pop(parser);
21408 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_EXPECT_RBRACKET);
21415 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
21416 pm_call_node_t *aref = pm_call_node_aref_create(parser, node, &arguments);
21417 return parse_targets_validate(parser, UP(aref), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21424 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
21425 block = parse_block(parser, (uint16_t) (depth + 1));
21426 pm_arguments_validate_block(parser, &arguments, block);
21427 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
21428 block = parse_block(parser, (uint16_t) (depth + 1));
21431 if (block != NULL) {
21432 if (arguments.
block != NULL) {
21433 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_AFTER_BLOCK);
21435 arguments.
arguments = pm_arguments_node_create(parser);
21437 pm_arguments_node_arguments_append(arguments.
arguments, arguments.
block);
21440 arguments.
block = UP(block);
21443 return UP(pm_call_node_aref_create(parser, node, &arguments));
21445 case PM_TOKEN_KEYWORD_IN: {
21451 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
21452 parser_lex(parser);
21455 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));
21458 pm_constant_id_list_free(&captures);
21460 return UP(pm_match_predicate_node_create(parser, node, pattern, &
operator));
21462 case PM_TOKEN_EQUAL_GREATER: {
21468 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
21469 parser_lex(parser);
21472 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));
21475 pm_constant_id_list_free(&captures);
21477 return UP(pm_match_required_node_create(parser, node, pattern, &
operator));
21480 assert(
false &&
"unreachable");
21485#undef PM_PARSE_PATTERN_SINGLE
21486#undef PM_PARSE_PATTERN_TOP
21487#undef PM_PARSE_PATTERN_MULTI
21497 (node->
block == NULL || PM_NODE_TYPE_P(node->
block, PM_BLOCK_ARGUMENT_NODE)) &&
21511parse_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) {
21513 pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
21514 return UP(pm_missing_node_create(parser, parser->
current.start, parser->
current.end));
21517 pm_node_t *node = parse_expression_prefix(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
21519 switch (PM_NODE_TYPE(node)) {
21520 case PM_MISSING_NODE:
21524 case PM_PRE_EXECUTION_NODE:
21525 case PM_POST_EXECUTION_NODE:
21526 case PM_ALIAS_GLOBAL_VARIABLE_NODE:
21527 case PM_ALIAS_METHOD_NODE:
21528 case PM_MULTI_WRITE_NODE:
21529 case PM_UNDEF_NODE:
21532 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21542 if ((pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_COMPOSITION) && pm_call_node_command_p((
pm_call_node_t *) node)) {
21546 case PM_SYMBOL_NODE:
21550 if (pm_symbol_node_label_p(node)) {
21561 pm_token_type_t current_token_type;
21564 current_token_type = parser->
current.type,
21565 current_binding_powers = pm_binding_powers[current_token_type],
21566 binding_power <= current_binding_powers.
left &&
21567 current_binding_powers.
binary
21569 node = parse_expression_infix(parser, node, binding_power, current_binding_powers.
right, accepts_command_call, (uint16_t) (depth + 1));
21577 switch (PM_NODE_TYPE(node)) {
21578 case PM_MULTI_WRITE_NODE:
21581 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21585 case PM_CLASS_VARIABLE_WRITE_NODE:
21586 case PM_CONSTANT_PATH_WRITE_NODE:
21587 case PM_CONSTANT_WRITE_NODE:
21588 case PM_GLOBAL_VARIABLE_WRITE_NODE:
21589 case PM_INSTANCE_VARIABLE_WRITE_NODE:
21590 case PM_LOCAL_VARIABLE_WRITE_NODE:
21593 if (PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21601 if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21611 if (current_binding_powers.
nonassoc) {
21614 if (match1(parser, current_token_type)) {
21626 if (PM_NODE_TYPE_P(node, PM_RANGE_NODE) && ((
pm_range_node_t *) node)->right == NULL) {
21627 if (match4(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_DOT, PM_TOKEN_AMPERSAND_DOT)) {
21632 if (PM_BINDING_POWER_TERM <= pm_binding_powers[parser->
current.type].left) {
21635 }
else if (current_binding_powers.
left <= pm_binding_powers[parser->
current.type].left) {
21640 if (accepts_command_call) {
21649 switch (node->
type) {
21650 case PM_CALL_NODE: {
21664 cast->
block == NULL &&
21674 cast->
block != NULL && PM_NODE_TYPE_P(cast->
block, PM_BLOCK_NODE)
21677 accepts_command_call =
false;
21682 case PM_CONSTANT_PATH_NODE:
21685 accepts_command_call =
false;
21700 if (PM_PARSER_COMMAND_LINE_OPTION_P(parser)) {
21701 if (statements == NULL) {
21702 statements = pm_statements_node_create(parser);
21706 pm_arguments_node_arguments_append(
21708 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2)))
21711 pm_statements_node_body_append(parser, statements, UP(pm_call_node_fcall_synthesized_create(
21714 pm_parser_constant_id_constant(parser,
"print", 5)
21718 if (PM_PARSER_COMMAND_LINE_OPTION_N(parser)) {
21719 if (PM_PARSER_COMMAND_LINE_OPTION_A(parser)) {
21720 if (statements == NULL) {
21721 statements = pm_statements_node_create(parser);
21725 pm_arguments_node_arguments_append(
21727 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$;", 2)))
21730 pm_global_variable_read_node_t *receiver = pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2));
21731 pm_call_node_t *call = pm_call_node_call_synthesized_create(parser, UP(receiver),
"split", arguments);
21735 pm_parser_constant_id_constant(parser,
"$F", 2),
21739 pm_statements_node_body_prepend(statements, UP(write));
21743 pm_arguments_node_arguments_append(
21745 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$/", 2)))
21748 if (PM_PARSER_COMMAND_LINE_OPTION_L(parser)) {
21750 pm_keyword_hash_node_elements_append(keywords, UP(pm_assoc_node_create(
21752 UP(pm_symbol_node_synthesized_create(parser,
"chomp")),
21753 &(
pm_token_t) { .type = PM_TOKEN_NOT_PROVIDED, .start = parser->
start, .end = parser->
start },
21754 UP(pm_true_node_synthesized_create(parser))
21757 pm_arguments_node_arguments_append(arguments, UP(keywords));
21758 pm_node_flag_set(UP(arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS);
21762 pm_statements_node_body_append(parser, wrapped_statements, UP(pm_while_node_synthesized_create(
21764 UP(pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser,
"gets", 4))),
21768 statements = wrapped_statements;
21783 pm_parser_scope_push(parser,
true);
21787 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
21789 parser_lex(parser);
21796 assert(statements->
body.
size > 0);
21797 pm_void_statement_check(parser, statements->
body.
nodes[statements->
body.
size - 1]);
21802 pm_parser_scope_pop(parser);
21807 statements = wrap_statements(parser, statements);
21809 flush_block_exits(parser, previous_block_exits);
21812 pm_node_list_free(¤t_block_exits);
21817 if (statements == NULL) {
21818 statements = pm_statements_node_create(parser);
21819 pm_statements_node_location_set(statements, parser->
start, parser->
start);
21822 return UP(pm_program_node_create(parser, &locals, statements));
21839pm_strnstr(
const char *big,
const char *little,
size_t big_length) {
21840 size_t little_length = strlen(little);
21842 for (
const char *max = big + big_length - little_length; big <= max; big++) {
21843 if (*big == *little && memcmp(big, little, little_length) == 0)
return big;
21850#define pm_parser_warn_shebang_carriage_return(parser, start, length) ((void) 0)
21858pm_parser_warn_shebang_carriage_return(
pm_parser_t *parser,
const uint8_t *start,
size_t length) {
21859 if (length > 2 && start[length - 2] ==
'\r' && start[length - 1] ==
'\n') {
21860 pm_parser_warn(parser, start, start + length, PM_WARN_SHEBANG_CARRIAGE_RETURN);
21871 const char *switches = pm_strnstr(engine,
" -", length);
21872 if (switches == NULL)
return;
21877 (
const uint8_t *) (switches + 1),
21878 length - ((
size_t) (switches - engine)) - 1,
21882 size_t encoding_length;
21885 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
21897 assert(source != NULL);
21901 .lex_state = PM_LEX_STATE_BEG,
21902 .enclosure_nesting = 0,
21903 .lambda_enclosure_nesting = -1,
21904 .brace_nesting = 0,
21905 .do_loop_stack = 0,
21906 .accepts_block_stack = 0,
21909 .stack = {{ .mode = PM_LEX_DEFAULT }},
21913 .end = source + size,
21914 .previous = { .type = PM_TOKEN_EOF, .start = source, .end = source },
21915 .current = { .type = PM_TOKEN_EOF, .start = source, .end = source },
21916 .next_start = NULL,
21917 .heredoc_end = NULL,
21918 .data_loc = { .start = NULL, .end = NULL },
21919 .comment_list = { 0 },
21920 .magic_comment_list = { 0 },
21921 .warning_list = { 0 },
21922 .error_list = { 0 },
21923 .current_scope = NULL,
21924 .current_context = NULL,
21926 .encoding_changed_callback = NULL,
21927 .encoding_comment_start = source,
21928 .lex_callback = NULL,
21930 .constant_pool = { 0 },
21931 .newline_list = { 0 },
21935 .explicit_encoding = NULL,
21937 .parsing_eval =
false,
21938 .partial_script =
false,
21939 .command_start =
true,
21940 .recovering =
false,
21941 .encoding_locked =
false,
21942 .encoding_changed =
false,
21943 .pattern_matching_newlines =
false,
21944 .in_keyword_arg =
false,
21945 .current_block_exits = NULL,
21946 .semantic_token_seen =
false,
21948 .current_regular_expression_ascii_only =
false,
21949 .warn_mismatched_indentation =
true
21966 uint32_t constant_size = ((uint32_t) size) / 95;
21967 pm_constant_pool_init(&parser->
constant_pool, constant_size < 4 ? 4 : constant_size);
21972 size_t newline_size = size / 22;
21973 pm_newline_list_init(&parser->
newline_list, source, newline_size < 4 ? 4 : newline_size);
21976 if (options != NULL) {
21985 if (encoding_length > 0) {
21987 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22009 for (
size_t scope_index = 0; scope_index < options->
scopes_count; scope_index++) {
22011 pm_parser_scope_push(parser, scope_index == 0);
22017 for (
size_t local_index = 0; local_index < scope->
locals_count; local_index++) {
22023 void *allocated =
xmalloc(length);
22024 if (allocated == NULL)
continue;
22026 memcpy(allocated, source, length);
22027 pm_parser_local_add_owned(parser, (uint8_t *) allocated, length);
22038 pm_accepts_block_stack_push(parser,
true);
22041 if (size >= 3 && source[0] == 0xef && source[1] == 0xbb && source[2] == 0xbf) {
22054 bool search_shebang = PM_PARSER_COMMAND_LINE_OPTION_X(parser);
22071 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
22072 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - parser->
current.end);
22074 if (length > 2 && parser->
current.end[0] ==
'#' && parser->
current.end[1] ==
'!') {
22075 const char *engine;
22077 if ((engine = pm_strnstr((
const char *) parser->
start,
"ruby", length)) != NULL) {
22078 if (newline != NULL) {
22082 pm_parser_warn_shebang_carriage_return(parser, parser->
start, length + 1);
22087 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) parser->
start)));
22090 search_shebang =
false;
22092 search_shebang =
true;
22098 if (search_shebang) {
22101 bool found_shebang =
false;
22105 const uint8_t *cursor = parser->
start;
22109 const uint8_t *newline = next_newline(cursor, parser->
end - cursor);
22111 while (newline != NULL) {
22112 pm_newline_list_append(&parser->
newline_list, newline);
22114 cursor = newline + 1;
22115 newline = next_newline(cursor, parser->
end - cursor);
22117 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - cursor);
22118 if (length > 2 && cursor[0] ==
'#' && cursor[1] ==
'!') {
22119 const char *engine;
22120 if ((engine = pm_strnstr((
const char *) cursor,
"ruby", length)) != NULL) {
22121 found_shebang =
true;
22123 if (newline != NULL) {
22124 pm_parser_warn_shebang_carriage_return(parser, cursor, length + 1);
22129 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) cursor)));
22137 if (found_shebang) {
22139 parser->
current = (
pm_token_t) { .type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
22141 pm_parser_err(parser, parser->
start, parser->
start, PM_ERR_SCRIPT_NOT_FOUND);
22168 for (node = list->
head; node != NULL; node = next) {
22180pm_magic_comment_list_free(
pm_list_t *list) {
22183 for (node = list->
head; node != NULL; node = next) {
22197 pm_diagnostic_list_free(&parser->
error_list);
22209 pm_parser_scope_pop(parser);
22213 lex_mode_pop(parser);
22222 return parse_program(parser);
22232#define LINE_SIZE 4096
22233 char line[LINE_SIZE];
22235 while (memset(line,
'\n', LINE_SIZE), stream_fgets(line, LINE_SIZE, stream) != NULL) {
22236 size_t length = LINE_SIZE;
22237 while (length > 0 && line[length - 1] ==
'\n') length--;
22239 if (length == LINE_SIZE) {
22244 pm_buffer_append_string(buffer, line, length);
22250 pm_buffer_append_string(buffer, line, length);
22258 if (strncmp(line,
"__END__", 7) == 0)
return false;
22261 if (strncmp(line,
"__END__\n", 8) == 0)
return false;
22264 if (strncmp(line,
"__END__\r\n", 9) == 0)
return false;
22270 if (stream_feof(stream)) {
22289pm_parse_stream_unterminated_heredoc_p(
pm_parser_t *parser) {
22292 for (; diagnostic != NULL; diagnostic = (
pm_diagnostic_t *) diagnostic->node.next) {
22293 if (diagnostic->diag_id == PM_ERR_HEREDOC_TERM) {
22311 bool eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof);
22317 pm_node_destroy(parser, node);
22318 eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof);
22332pm_parse_success_p(
const uint8_t *source,
size_t size,
const char *data) {
22334 pm_options_read(&options, data);
22340 pm_node_destroy(&parser, node);
22349#undef PM_CASE_KEYWORD
22350#undef PM_CASE_OPERATOR
22351#undef PM_CASE_WRITABLE
22352#undef PM_STRING_EMPTY
22357#ifndef PRISM_EXCLUDE_SERIALIZATION
22361 pm_buffer_append_string(buffer,
"PRISM", 5);
22365 pm_buffer_append_byte(buffer, PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS ? 1 : 0);
22373 pm_serialize_header(buffer);
22375 pm_buffer_append_byte(buffer,
'\0');
22383pm_serialize_parse(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
22385 pm_options_read(&options, data);
22392 pm_serialize_header(buffer);
22394 pm_buffer_append_byte(buffer,
'\0');
22396 pm_node_destroy(&parser, node);
22409 pm_options_read(&options, data);
22413 pm_serialize_header(buffer);
22415 pm_buffer_append_byte(buffer,
'\0');
22417 pm_node_destroy(&parser, node);
22427pm_serialize_parse_comments(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
22429 pm_options_read(&options, data);
22435 pm_serialize_header(buffer);
22437 pm_buffer_append_varsint(buffer, parser.
start_line);
22440 pm_node_destroy(&parser, node);
22454 PM_SLICE_TYPE_ERROR = -1,
22457 PM_SLICE_TYPE_NONE,
22460 PM_SLICE_TYPE_LOCAL,
22463 PM_SLICE_TYPE_CONSTANT,
22466 PM_SLICE_TYPE_METHOD_NAME
22473pm_slice_type(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22475 const pm_encoding_t *encoding = pm_encoding_find((
const uint8_t *) encoding_name, (
const uint8_t *) (encoding_name + strlen(encoding_name)));
22476 if (encoding == NULL)
return PM_SLICE_TYPE_ERROR;
22479 if (length == 0)
return PM_SLICE_TYPE_NONE;
22482 if ((width = encoding->
alpha_char(source, (ptrdiff_t) length)) != 0) {
22484 }
else if (*source ==
'_') {
22487 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, (ptrdiff_t) length)) > 0)) {
22491 return PM_SLICE_TYPE_NONE;
22495 const uint8_t *end = source + length;
22496 pm_slice_type_t result = encoding->
isupper_char(source, end - source) ? PM_SLICE_TYPE_CONSTANT : PM_SLICE_TYPE_LOCAL;
22502 while (source < end) {
22503 if ((width = encoding->
alnum_char(source, end - source)) != 0) {
22506 }
else if (*source ==
'_') {
22509 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, end - source)) > 0)) {
22519 if (*source ==
'!' || *source ==
'?' || *source ==
'=') {
22521 result = PM_SLICE_TYPE_METHOD_NAME;
22525 return source == end ? result : PM_SLICE_TYPE_NONE;
22532pm_string_query_local(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22533 switch (pm_slice_type(source, length, encoding_name)) {
22534 case PM_SLICE_TYPE_ERROR:
22536 case PM_SLICE_TYPE_NONE:
22537 case PM_SLICE_TYPE_CONSTANT:
22538 case PM_SLICE_TYPE_METHOD_NAME:
22540 case PM_SLICE_TYPE_LOCAL:
22544 assert(
false &&
"unreachable");
22552pm_string_query_constant(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22553 switch (pm_slice_type(source, length, encoding_name)) {
22554 case PM_SLICE_TYPE_ERROR:
22556 case PM_SLICE_TYPE_NONE:
22557 case PM_SLICE_TYPE_LOCAL:
22558 case PM_SLICE_TYPE_METHOD_NAME:
22560 case PM_SLICE_TYPE_CONSTANT:
22564 assert(
false &&
"unreachable");
22572pm_string_query_method_name(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22573#define B(p) ((p) ? PM_STRING_QUERY_TRUE : PM_STRING_QUERY_FALSE)
22574#define C1(c) (*source == c)
22575#define C2(s) (memcmp(source, s, 2) == 0)
22576#define C3(s) (memcmp(source, s, 3) == 0)
22578 switch (pm_slice_type(source, length, encoding_name)) {
22579 case PM_SLICE_TYPE_ERROR:
22581 case PM_SLICE_TYPE_NONE:
22583 case PM_SLICE_TYPE_LOCAL:
22585 return B((length != 2) || (source[0] !=
'_') || (source[1] ==
'0') || !pm_char_is_decimal_digit(source[1]));
22586 case PM_SLICE_TYPE_CONSTANT:
22588 case PM_SLICE_TYPE_METHOD_NAME:
22595 return B(C1(
'&') || C1(
'`') || C1(
'!') || C1(
'^') || C1(
'>') || C1(
'<') || C1(
'-') || C1(
'%') || C1(
'|') || C1(
'+') || C1(
'/') || C1(
'*') || C1(
'~'));
22597 return B(C2(
"!=") || C2(
"!~") || C2(
"[]") || C2(
"==") || C2(
"=~") || C2(
">=") || C2(
">>") || C2(
"<=") || C2(
"<<") || C2(
"**"));
22599 return B(C3(
"===") || C3(
"<=>") || C3(
"[]="));
pm_diagnostic_id_t
The diagnostic IDs of all of the diagnostics, used to communicate the types of errors between the par...
#define xfree
Old name of ruby_xfree.
#define xmalloc
Old name of ruby_xmalloc.
#define xcalloc
Old name of ruby_xcalloc.
VALUE type(ANYARGS)
ANYARGS-ed function type.
PRISM_EXPORTED_FUNCTION void pm_options_free(pm_options_t *options)
Free the internal memory associated with the options.
PRISM_EXPORTED_FUNCTION const pm_string_t * pm_options_scope_local_get(const pm_options_scope_t *scope, size_t index)
Return a pointer to the local at the given index within the given scope.
PRISM_EXPORTED_FUNCTION const pm_options_scope_t * pm_options_scope_get(const pm_options_t *options, size_t index)
Return a pointer to the scope at the given index within the given options.
static const uint8_t PM_OPTIONS_COMMAND_LINE_N
A bit representing whether or not the command line -n option was set.
#define PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED
String literals should be made frozen.
#define PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED
String literals should be made mutable.
#define PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET
String literals may be frozen or mutable depending on the implementation default.
static const uint8_t PM_OPTIONS_COMMAND_LINE_P
A bit representing whether or not the command line -p option was set.
@ PM_OPTIONS_VERSION_CRUBY_3_3
The vendored version of prism in CRuby 3.3.x.
@ PM_OPTIONS_VERSION_LATEST
The current version of prism.
@ PM_OPTIONS_VERSION_UNSET
If an explicit version is not provided, the current version of prism will be used.
@ PM_OPTIONS_VERSION_CRUBY_3_4
The vendored version of prism in CRuby 3.4.x.
@ PM_OPTIONS_VERSION_CRUBY_4_0
The vendored version of prism in CRuby 4.0.x.
pm_heredoc_indent_t
The type of indentation that a heredoc uses.
struct pm_context_node pm_context_node_t
This is a node in a linked list of contexts.
#define PM_LEX_STACK_SIZE
We pre-allocate a certain number of lex states in order to avoid having to call malloc too many times...
struct pm_parser pm_parser_t
The parser used to parse Ruby source.
struct pm_comment pm_comment_t
This is a node in the linked list of comments that we've found while parsing.
pm_lex_state_t
This enum combines the various bits from the above enum into individual values that represent the var...
struct pm_scope pm_scope_t
This struct represents a node in a linked list of scopes.
pm_heredoc_quote_t
The type of quote that a heredoc uses.
void(* pm_encoding_changed_callback_t)(pm_parser_t *parser)
When the encoding that is being used to parse the source is changed by prism, we provide the ability ...
pm_context_t
While parsing, we keep track of a stack of contexts.
@ PM_CONTEXT_CLASS_RESCUE
a rescue statement within a class statement
@ PM_CONTEXT_ELSIF
an elsif clause
@ PM_CONTEXT_DEF_RESCUE
a rescue statement within a method definition
@ PM_CONTEXT_ELSE
an else clause
@ PM_CONTEXT_FOR_INDEX
a for loop's index
@ PM_CONTEXT_CASE_WHEN
a case when statements
@ PM_CONTEXT_BLOCK_RESCUE
a rescue statement within a do..end block
@ PM_CONTEXT_MODULE
a module declaration
@ PM_CONTEXT_DEF_PARAMS
a method definition's parameters
@ PM_CONTEXT_CASE_IN
a case in statements
@ PM_CONTEXT_BLOCK_ELSE
a rescue else statement within a do..end block
@ PM_CONTEXT_LOOP_PREDICATE
the predicate clause of a loop statement
@ PM_CONTEXT_SCLASS
a singleton class definition
@ PM_CONTEXT_UNLESS
an unless statement
@ PM_CONTEXT_POSTEXE
an END block
@ PM_CONTEXT_IF
an if statement
@ PM_CONTEXT_MULTI_TARGET
a multiple target expression
@ PM_CONTEXT_LAMBDA_RESCUE
a rescue statement within a lambda expression
@ PM_CONTEXT_BEGIN_ELSE
a rescue else statement with an explicit begin
@ PM_CONTEXT_NONE
a null context, used for returning a value from a function
@ PM_CONTEXT_CLASS_ELSE
a rescue else statement within a class statement
@ PM_CONTEXT_LAMBDA_ENSURE
an ensure statement within a lambda expression
@ PM_CONTEXT_BLOCK_ENSURE
an ensure statement within a do..end block
@ PM_CONTEXT_CLASS_ENSURE
an ensure statement within a class statement
@ PM_CONTEXT_LAMBDA_BRACES
a lambda expression with braces
@ PM_CONTEXT_MODULE_ELSE
a rescue else statement within a module statement
@ PM_CONTEXT_PARENS
a parenthesized expression
@ PM_CONTEXT_BLOCK_BRACES
expressions in block arguments using braces
@ PM_CONTEXT_BLOCK_PARAMETERS
expressions in block parameters foo do |...| end
@ PM_CONTEXT_DEF_ENSURE
an ensure statement within a method definition
@ PM_CONTEXT_SCLASS_RESCUE
a rescue statement with a singleton class
@ PM_CONTEXT_PREEXE
a BEGIN block
@ PM_CONTEXT_DEFINED
a defined? expression
@ PM_CONTEXT_MODULE_ENSURE
an ensure statement within a module statement
@ PM_CONTEXT_BEGIN_RESCUE
a rescue statement with an explicit begin
@ PM_CONTEXT_UNTIL
an until statement
@ PM_CONTEXT_DEF_ELSE
a rescue else statement within a method definition
@ PM_CONTEXT_FOR
a for loop
@ PM_CONTEXT_PREDICATE
a predicate inside an if/elsif/unless statement
@ PM_CONTEXT_BEGIN_ENSURE
an ensure statement with an explicit begin
@ PM_CONTEXT_SCLASS_ENSURE
an ensure statement with a singleton class
@ PM_CONTEXT_DEFAULT_PARAMS
a method definition's default parameter
@ PM_CONTEXT_LAMBDA_ELSE
a rescue else statement within a lambda expression
@ PM_CONTEXT_CLASS
a class declaration
@ PM_CONTEXT_MAIN
the top level context
@ PM_CONTEXT_LAMBDA_DO_END
a lambda expression with do..end
@ PM_CONTEXT_BEGIN
a begin statement
@ PM_CONTEXT_RESCUE_MODIFIER
a modifier rescue clause
@ PM_CONTEXT_EMBEXPR
an interpolated expression
@ PM_CONTEXT_TERNARY
a ternary expression
@ PM_CONTEXT_DEF
a method definition
@ PM_CONTEXT_SCLASS_ELSE
a rescue else statement with a singleton class
@ PM_CONTEXT_MODULE_RESCUE
a rescue statement within a module statement
@ PM_CONTEXT_BLOCK_KEYWORDS
expressions in block arguments using do..end
@ PM_CONTEXT_WHILE
a while statement
uint8_t pm_scope_parameters_t
The flags about scope parameters that can be set.
uint8_t pm_shareable_constant_value_t
The type of shareable constant value that can be set.
pm_comment_type_t
This is the type of a comment that we've found while parsing.
void pm_buffer_free(pm_buffer_t *buffer)
Free the memory associated with the buffer.
bool pm_buffer_init(pm_buffer_t *buffer)
Initialize a pm_buffer_t with its default values.
size_t pm_buffer_length(const pm_buffer_t *buffer)
Return the length of the buffer.
char * pm_buffer_value(const pm_buffer_t *buffer)
Return the value of the buffer.
#define PM_CONSTANT_ID_UNSET
When we allocate constants into the pool, we reserve 0 to mean that the slot is not yet filled.
uint32_t pm_constant_id_t
A constant id is a unique identifier for a constant in the constant pool.
PRISM_EXPORTED_FUNCTION size_t pm_string_length(const pm_string_t *string)
Returns the length associated with the string.
PRISM_EXPORTED_FUNCTION const uint8_t * pm_string_source(const pm_string_t *string)
Returns the start pointer associated with the string.
PRISM_EXPORTED_FUNCTION void pm_string_free(pm_string_t *string)
Free the associated memory of the given string.
#define PM_STRING_EMPTY
Defines an empty string.
#define PRISM_FALLTHROUGH
We use -Wimplicit-fallthrough to guard potentially unintended fall-through between cases of a switch.
#define PRISM_UNLIKELY(x)
The compiler should predicate that this branch will not be taken.
#define PRISM_ATTRIBUTE_UNUSED
GCC will warn if you specify a function or parameter that is unused at runtime.
#define PRISM_DEPTH_MAXIMUM
When we are parsing using recursive descent, we want to protect against malicious payloads that could...
#define PM_STATIC_ASSERT(line, condition, message)
We want to be able to use static assertions, but they weren't standardized until C11.
#define PRISM_EXPORTED_FUNCTION
By default, we compile with -fvisibility=hidden.
#define PM_ENCODING_US_ASCII_ENTRY
This is the US-ASCII encoding.
#define PM_ENCODING_UTF_8_ENTRY
This is the default UTF-8 encoding.
#define PRISM_ENCODING_ALPHABETIC_BIT
All of the lookup tables use the first bit of each embedded byte to indicate whether the codepoint is...
#define PRISM_ENCODING_ALPHANUMERIC_BIT
All of the lookup tables use the second bit of each embedded byte to indicate whether the codepoint i...
#define PM_NODE_LIST_FOREACH(list, index, node)
Loop through each node in the node list, writing each node to the given pm_node_t pointer.
#define PRISM_VERSION
The version of the Prism library as a constant string.
#define PRISM_VERSION_PATCH
The patch version of the Prism library as an int.
#define PRISM_VERSION_MINOR
The minor version of the Prism library as an int.
#define PRISM_VERSION_MAJOR
The major version of the Prism library as an int.
PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse(pm_parser_t *parser)
Parse the Ruby source associated with the given parser and return the tree.
PRISM_EXPORTED_FUNCTION void pm_parser_register_encoding_changed_callback(pm_parser_t *parser, pm_encoding_changed_callback_t callback)
Register a callback that will be called whenever prism changes the encoding it is using to parse base...
PRISM_EXPORTED_FUNCTION void pm_parser_free(pm_parser_t *parser)
Free any memory associated with the given parser.
PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse_stream(pm_parser_t *parser, pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *stream_fgets, pm_parse_stream_feof_t *stream_feof, const pm_options_t *options)
Parse a stream of Ruby source and return the tree.
PRISM_EXPORTED_FUNCTION void pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm_options_t *options)
Initialize a parser with the given start and end pointers.
The main header file for the prism parser.
pm_string_query_t
Represents the results of a slice query.
@ PM_STRING_QUERY_TRUE
Returned if the result of the slice query is true.
@ PM_STRING_QUERY_ERROR
Returned if the encoding given to a slice query was invalid.
@ PM_STRING_QUERY_FALSE
Returned if the result of the slice query is false.
void pm_serialize_content(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer)
Serialize the encoding, metadata, nodes, and constant pool.
char *() pm_parse_stream_fgets_t(char *string, int size, void *stream)
This function is used in pm_parse_stream() to retrieve a line of input from a stream.
void pm_serialize_encoding(const pm_encoding_t *encoding, pm_buffer_t *buffer)
Serialize the name of the encoding to the buffer.
int() pm_parse_stream_feof_t(void *stream)
This function is used in pm_parse_stream to check whether a stream is EOF.
void pm_serialize_comment_list(pm_parser_t *parser, pm_list_t *list, pm_buffer_t *buffer)
Serialize the given list of comments to the given buffer.
const char * pm_token_type_human(pm_token_type_t token_type)
Returns the human name of the given token type.
This struct is used to pass information between the regular expression parser and the error callback.
pm_parser_t * parser
The parser that we are parsing the regular expression for.
const uint8_t * start
The start of the regular expression.
bool shared
Whether or not the source of the regular expression is shared.
const uint8_t * end
The end of the regular expression.
This struct is used to pass information between the regular expression parser and the named capture c...
pm_constant_id_list_t names
The list of names that have been parsed.
pm_parser_t * parser
The parser that is parsing the regular expression.
pm_match_write_node_t * match
The match write node that is being created.
pm_call_node_t * call
The call node wrapping the regular expression node.
bool shared
Whether the content of the regular expression is shared.
struct pm_node * left
AndNode::left.
struct pm_node * right
AndNode::right.
pm_node_t base
The embedded base node.
struct pm_node_list arguments
ArgumentsNode::arguments.
This is a special out parameter to the parse_arguments_list function that includes opening and closin...
pm_node_t * block
The optional block attached to the call.
bool has_forwarding
The flag indicating whether this arguments list has forwarding argument.
pm_location_t opening_loc
The optional location of the opening parenthesis or bracket.
pm_arguments_node_t * arguments
The lazily-allocated optional arguments node.
pm_location_t closing_loc
The optional location of the closing parenthesis or bracket.
struct pm_node_list elements
ArrayNode::elements.
struct pm_node * constant
ArrayPatternNode::constant.
pm_location_t opening_loc
ArrayPatternNode::opening_loc.
pm_node_t base
The embedded base node.
pm_location_t closing_loc
ArrayPatternNode::closing_loc.
struct pm_node * value
AssocNode::value.
struct pm_node * key
AssocNode::key.
struct pm_ensure_node * ensure_clause
BeginNode::ensure_clause.
struct pm_rescue_node * rescue_clause
BeginNode::rescue_clause.
struct pm_statements_node * statements
BeginNode::statements.
pm_node_t base
The embedded base node.
struct pm_else_node * else_clause
BeginNode::else_clause.
This struct represents a set of binding powers used for a given token.
bool binary
Whether or not this token can be used as a binary operator.
pm_binding_power_t left
The left binding power.
bool nonassoc
Whether or not this token can be used as non-associative binary operator.
pm_binding_power_t right
The right binding power.
A pm_buffer_t is a simple memory buffer that stores data in a contiguous block of memory.
size_t length
The length of the buffer in bytes.
char * value
A pointer to the start of the buffer.
pm_location_t opening_loc
CallNode::opening_loc.
pm_location_t closing_loc
CallNode::closing_loc.
struct pm_node * receiver
CallNode::receiver.
pm_constant_id_t name
CallNode::name.
pm_node_t base
The embedded base node.
pm_location_t equal_loc
CallNode::equal_loc.
pm_location_t call_operator_loc
CallNode::call_operator_loc.
pm_location_t message_loc
CallNode::message_loc.
struct pm_arguments_node * arguments
CallNode::arguments.
struct pm_node * block
CallNode::block.
struct pm_node_list conditions
CaseMatchNode::conditions.
struct pm_node_list conditions
CaseNode::conditions.
size_t size
The number of constant ids in the list.
A constant in the pool which effectively stores a string.
size_t length
The length of the string.
const uint8_t * start
A pointer to the start of the string.
This is a node in a linked list of contexts.
pm_context_t context
The context that this node represents.
struct pm_context_node * prev
A pointer to the previous context in the linked list.
This struct represents a diagnostic generated during parsing.
struct pm_statements_node * statements
ElseNode::statements.
This struct defines the functions necessary to implement the encoding interface so we can determine h...
size_t(* alpha_char)(const uint8_t *b, ptrdiff_t n)
Return the number of bytes that the next character takes if it is valid in the encoding and is alphab...
size_t(* char_width)(const uint8_t *b, ptrdiff_t n)
Return the number of bytes that the next character takes if it is valid in the encoding.
bool(* isupper_char)(const uint8_t *b, ptrdiff_t n)
Return true if the next character is valid in the encoding and is an uppercase character.
const char * name
The name of the encoding.
size_t(* alnum_char)(const uint8_t *b, ptrdiff_t n)
Return the number of bytes that the next character takes if it is valid in the encoding and is alphan...
struct pm_statements_node * statements
EnsureNode::statements.
struct pm_node * constant
FindPatternNode::constant.
pm_location_t opening_loc
FindPatternNode::opening_loc.
pm_node_t base
The embedded base node.
pm_location_t closing_loc
FindPatternNode::closing_loc.
double value
FloatNode::value.
pm_node_t base
The embedded base node.
GlobalVariableTargetNode.
struct pm_node_list elements
HashNode::elements.
pm_location_t opening_loc
HashPatternNode::opening_loc.
pm_node_t base
The embedded base node.
pm_location_t closing_loc
HashPatternNode::closing_loc.
struct pm_node * constant
HashPatternNode::constant.
All of the information necessary to store to lexing a heredoc.
size_t ident_length
The length of the heredoc identifier.
pm_heredoc_quote_t quote
The type of quote that the heredoc uses.
pm_heredoc_indent_t indent
The type of indentation that the heredoc uses.
const uint8_t * ident_start
A pointer to the start of the heredoc identifier.
struct pm_statements_node * statements
IfNode::statements.
struct pm_node * subsequent
IfNode::subsequent.
InstanceVariableReadNode.
InstanceVariableTargetNode.
InstanceVariableWriteNode.
pm_integer_t value
IntegerNode::value.
pm_node_t base
The embedded base node.
bool negative
Whether or not the integer is negative.
InterpolatedMatchLastLineNode.
InterpolatedRegularExpressionNode.
pm_node_t base
The embedded base node.
pm_location_t opening_loc
InterpolatedStringNode::opening_loc.
pm_node_t base
The embedded base node.
pm_location_t opening_loc
InterpolatedXStringNode::opening_loc.
pm_node_t base
The embedded base node.
struct pm_node_list parts
InterpolatedXStringNode::parts.
void(* callback)(void *data, pm_parser_t *parser, pm_token_t *token)
This is the callback that is called when a token is lexed.
void * data
This opaque pointer is used to provide whatever information the user deemed necessary to the callback...
When lexing Ruby source, the lexer has a small amount of state to tell which kind of token it is curr...
uint8_t terminator
This is the terminator of the list literal.
size_t nesting
This keeps track of the nesting level of the list.
bool interpolation
Whether or not interpolation is allowed in this list.
uint8_t incrementor
When lexing a list, it takes into account balancing the terminator if the terminator is one of (),...
enum pm_lex_mode::@98 mode
The type of this lex mode.
uint8_t breakpoints[11]
This is the character set that should be used to delimit the tokens within the list.
pm_heredoc_lex_mode_t base
All of the data necessary to lex a heredoc.
bool line_continuation
True if the previous token ended with a line continuation.
struct pm_lex_mode * prev
The previous lex state so that it knows how to pop.
bool label_allowed
Whether or not at the end of the string we should allow a :, which would indicate this was a dynamic ...
const uint8_t * next_start
This is the pointer to the character where lexing should resume once the heredoc has been completely ...
union pm_lex_mode::@99 as
The data associated with this type of lex mode.
size_t * common_whitespace
This is used to track the amount of common whitespace on each line so that we know how much to dedent...
int32_t line
The line number.
This struct represents an abstract linked list that provides common functionality.
struct pm_list_node * next
A pointer to the next node in the list.
This represents the overall linked list.
pm_list_node_t * head
A pointer to the head of the list.
size_t size
The size of the list.
This tracks an individual local variable in a certain lexical context, as well as the number of times...
pm_constant_id_t name
The name of the local variable.
pm_location_t location
The location of the local variable in the source.
uint32_t hash
The hash of the local variable.
uint32_t index
The index of the local variable in the local table.
uint32_t reads
The number of times the local variable is read.
uint32_t depth
LocalVariableReadNode::depth.
pm_constant_id_t name
LocalVariableReadNode::name.
uint32_t depth
LocalVariableWriteNode::depth.
pm_constant_id_t name
LocalVariableWriteNode::name.
This is a set of local variables in a certain lexical context (method, class, module,...
pm_local_t * locals
The nullable allocated memory for the local variables in the set.
uint32_t capacity
The capacity of the local variables set.
uint32_t size
The number of local variables in the set.
This represents a range of bytes in the source string to which a node or token corresponds.
const uint8_t * start
A pointer to the start location of the range in the source.
const uint8_t * end
A pointer to the end location of the range in the source.
struct pm_node_list targets
MatchWriteNode::targets.
pm_node_t base
The embedded base node.
pm_location_t lparen_loc
MultiTargetNode::lparen_loc.
struct pm_node_list lefts
MultiTargetNode::lefts.
pm_location_t rparen_loc
MultiTargetNode::rparen_loc.
size_t * offsets
The list of offsets.
size_t size
The number of offsets in the list.
A list of nodes in the source, most often used for lists of children.
size_t size
The number of nodes in the list.
struct pm_node ** nodes
The nodes in the list.
This is the base structure that represents a node in the syntax tree.
pm_node_type_t type
This represents the type of the node.
pm_location_t location
This is the location of the node in the source.
A scope of locals surrounding the code that is being parsed.
size_t locals_count
The number of locals in the scope.
uint8_t forwarding
Flags for the set of forwarding parameters in this scope.
The options that can be passed to the parser.
uint8_t command_line
A bitset of the various options that were set on the command line.
void * shebang_callback_data
Any additional data that should be passed along to the shebang callback if one was set.
bool encoding_locked
Whether or not the encoding magic comments should be respected.
bool main_script
When the file being parsed is the main script, the shebang will be considered for command-line flags ...
pm_string_t encoding
The name of the encoding that the source file is in.
int32_t line
The line within the file that the parse starts on.
pm_options_shebang_callback_t shebang_callback
The callback to call when additional switches are found in a shebang comment.
int8_t frozen_string_literal
Whether or not the frozen string literal option has been set.
bool partial_script
When the file being parsed is considered a "partial" script, jumps will not be marked as errors if th...
size_t scopes_count
The number of scopes surrounding the code that is being parsed.
pm_string_t filepath
The name of the file that is currently being parsed.
pm_options_version_t version
The version of prism that we should be parsing with.
struct pm_node * left
OrNode::left.
struct pm_node * right
OrNode::right.
struct pm_node * rest
ParametersNode::rest.
struct pm_block_parameter_node * block
ParametersNode::block.
pm_node_t base
The embedded base node.
struct pm_node * keyword_rest
ParametersNode::keyword_rest.
struct pm_node * body
ParenthesesNode::body.
This struct represents the overall parser.
const pm_encoding_t * explicit_encoding
When a string-like expression is being lexed, any byte or escape sequence that resolves to a value wh...
pm_lex_state_t lex_state
The current state of the lexer.
uint8_t command_line
The command line flags given from the options.
const pm_encoding_t * encoding
The encoding functions for the current file is attached to the parser as it's parsing so that it can ...
bool partial_script
Whether or not we are parsing a "partial" script, which is a script that will be evaluated in the con...
bool pattern_matching_newlines
This flag indicates that we are currently parsing a pattern matching expression and impacts that calc...
const uint8_t * end
The pointer to the end of the source.
bool recovering
Whether or not we're currently recovering from a syntax error.
pm_node_flags_t integer_base
We want to add a flag to integer nodes that indicates their base.
bool warn_mismatched_indentation
By default, Ruby always warns about mismatched indentation.
pm_constant_pool_t constant_pool
This constant pool keeps all of the constants defined throughout the file so that we can reference th...
bool in_keyword_arg
This flag indicates that we are currently parsing a keyword argument.
const uint8_t * next_start
This is a special field set on the parser when we need the parser to jump to a specific location when...
pm_static_literals_t * current_hash_keys
The hash keys for the hash that is currently being parsed.
pm_list_t magic_comment_list
The list of magic comments that have been found while parsing.
int lambda_enclosure_nesting
Used to temporarily track the nesting of enclosures to determine if a { is the beginning of a lambda ...
pm_lex_callback_t * lex_callback
This is an optional callback that can be attached to the parser that will be called whenever a new to...
pm_options_version_t version
The version of prism that we should use to parse.
pm_token_t previous
The previous token we were considering.
pm_string_t current_string
This string is used to pass information from the lexer to the parser.
bool parsing_eval
Whether or not we are parsing an eval string.
bool current_regular_expression_ascii_only
True if the current regular expression being lexed contains only ASCII characters.
bool encoding_changed
Whether or not the encoding has been changed by a magic comment.
pm_location_t data_loc
An optional location that represents the location of the END marker and the rest of the content of th...
pm_context_node_t * current_context
The current parsing context.
const uint8_t * start
The pointer to the start of the source.
int enclosure_nesting
Tracks the current nesting of (), [], and {}.
pm_list_t error_list
The list of errors that have been found while parsing.
int8_t frozen_string_literal
Whether or not we have found a frozen_string_literal magic comment with a true or false value.
pm_node_list_t * current_block_exits
When parsing block exits (e.g., break, next, redo), we need to validate that they are in correct cont...
const uint8_t * encoding_comment_start
This pointer indicates where a comment must start if it is to be considered an encoding comment.
pm_lex_mode_t stack[PM_LEX_STACK_SIZE]
The stack of lexer modes.
pm_list_t warning_list
The list of warnings that have been found while parsing.
const uint8_t * heredoc_end
This field indicates the end of a heredoc whose identifier was found on the current line.
int brace_nesting
Used to track the nesting of braces to ensure we get the correct value when we are interpolating bloc...
pm_encoding_changed_callback_t encoding_changed_callback
When the encoding that is being used to parse the source is changed by prism, we provide the ability ...
struct pm_parser::@104 lex_modes
A stack of lex modes.
int32_t start_line
The line number at the start of the parse.
bool encoding_locked
This is very specialized behavior for when you want to parse in a context that does not respect encod...
pm_lex_mode_t * current
The current mode of the lexer.
pm_list_t comment_list
The list of comments that have been found while parsing.
size_t index
The current index into the lexer mode stack.
pm_string_t filepath
This is the path of the file being parsed.
pm_scope_t * current_scope
The current local scope.
bool command_start
Whether or not we're at the beginning of a command.
pm_newline_list_t newline_list
This is the list of newline offsets in the source file.
bool semantic_token_seen
Whether or not the parser has seen a token that has semantic meaning (i.e., a token that is not a com...
uint32_t node_id
The next node identifier that will be assigned.
struct pm_node * right
RangeNode::right.
struct pm_node * left
RangeNode::left.
pm_node_t base
The embedded base node.
pm_integer_t numerator
RationalNode::numerator.
In order to properly set a regular expression's encoding and to validate the byte sequence for the un...
pm_buffer_t regexp_buffer
The buffer holding the regexp source.
pm_token_buffer_t base
The embedded base buffer.
pm_node_t base
The embedded base node.
pm_string_t unescaped
RegularExpressionNode::unescaped.
struct pm_node * rescue_expression
RescueModifierNode::rescue_expression.
struct pm_rescue_node * subsequent
RescueNode::subsequent.
pm_location_t then_keyword_loc
RescueNode::then_keyword_loc.
pm_node_t base
The embedded base node.
This struct represents a node in a linked list of scopes.
struct pm_scope * previous
A pointer to the previous scope in the linked list.
pm_node_list_t implicit_parameters
This is a list of the implicit parameters contained within the block.
pm_shareable_constant_value_t shareable_constant
The current state of constant shareability for this scope.
pm_locals_t locals
The IDs of the locals in the given scope.
pm_scope_parameters_t parameters
This is a bitfield that indicates the parameters that are being used in this scope.
bool closed
A boolean indicating whether or not this scope can see into its parent.
struct pm_node * expression
SplatNode::expression.
struct pm_node_list body
StatementsNode::body.
Certain sets of nodes (hash keys and when clauses) check for duplicate nodes to alert the user of pot...
pm_node_t base
The embedded base node.
pm_string_t unescaped
StringNode::unescaped.
pm_location_t closing_loc
StringNode::closing_loc.
pm_location_t opening_loc
StringNode::opening_loc.
A generic string type that can have various ownership semantics.
const uint8_t * source
A pointer to the start of the string.
size_t length
The length of the string in bytes of memory.
enum pm_string_t::@105 type
The type of the string.
pm_location_t value_loc
SymbolNode::value_loc.
pm_string_t unescaped
SymbolNode::unescaped.
When we're lexing certain types (strings, symbols, lists, etc.) we have string content associated wit...
pm_buffer_t buffer
The buffer that we're using to keep track of the string content.
const uint8_t * cursor
The cursor into the source string that points to how far we have currently copied into the buffer.
This struct represents a token in the Ruby source.
const uint8_t * end
A pointer to the end location of the token in the source.
const uint8_t * start
A pointer to the start location of the token in the source.
pm_token_type_t type
The type of the token.
struct pm_statements_node * statements
UnlessNode::statements.
struct pm_else_node * else_clause
UnlessNode::else_clause.