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 if (node->base.location.end < argument->location.end) {
2079 node->base.location.end = argument->location.end;
2082 pm_node_list_append(&node->arguments, argument);
2084 if (PM_NODE_TYPE_P(argument, PM_SPLAT_NODE)) {
2085 if (PM_NODE_FLAG_P(node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
2086 pm_node_flag_set(UP(node), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS);
2088 pm_node_flag_set(UP(node), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT);
2096static pm_array_node_t *
2097pm_array_node_create(pm_parser_t *parser, const pm_token_t *opening) {
2098 pm_array_node_t *node = PM_NODE_ALLOC(parser, pm_array_node_t);
2100 *node = (pm_array_node_t) {
2101 .base = PM_NODE_INIT_TOKEN(parser, PM_ARRAY_NODE, PM_NODE_FLAG_STATIC_LITERAL, opening),
2102 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2103 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2114pm_array_node_elements_append(pm_array_node_t *node, pm_node_t *element) {
2115 if (!node->elements.size && !node->opening_loc.start) {
2116 node->base.location.start = element->location.start;
2119 pm_node_list_append(&node->elements, element);
2120 node->base.location.end = element->location.end;
2122 // If the element is not a static literal, then the array is not a static
2123 // literal. Turn that flag off.
2124 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)) {
2125 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
2128 if (PM_NODE_TYPE_P(element, PM_SPLAT_NODE)) {
2129 pm_node_flag_set(UP(node), PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT);
2137pm_array_node_close_set(pm_array_node_t *node, const pm_token_t *closing) {
2138 assert(closing->type == PM_TOKEN_BRACKET_RIGHT || closing->type == PM_TOKEN_STRING_END || closing->type == PM_TOKEN_MISSING || closing->type == PM_TOKEN_NOT_PROVIDED);
2139 node->base.location.end = closing->end;
2140 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
2147static pm_array_pattern_node_t *
2148pm_array_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *nodes) {
2149 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2151 *node = (pm_array_pattern_node_t) {
2152 .base = PM_NODE_INIT_NODES(parser, PM_ARRAY_PATTERN_NODE, 0, nodes->nodes[0], nodes->nodes[nodes->size - 1]),
2157 .opening_loc = { 0 },
2158 .closing_loc = { 0 }
2161 // For now we're going to just copy over each pointer manually. This could be
2162 // much more efficient, as we could instead resize the node list.
2163 bool found_rest = false;
2166 PM_NODE_LIST_FOREACH(nodes, index, child) {
2167 if (!found_rest && (PM_NODE_TYPE_P(child, PM_SPLAT_NODE) || PM_NODE_TYPE_P(child, PM_IMPLICIT_REST_NODE))) {
2170 } else if (found_rest) {
2171 pm_node_list_append(&node->posts, child);
2173 pm_node_list_append(&node->requireds, child);
2183static pm_array_pattern_node_t *
2184pm_array_pattern_node_rest_create(pm_parser_t *parser, pm_node_t *rest) {
2185 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2187 *node = (pm_array_pattern_node_t) {
2188 .base = PM_NODE_INIT_NODE(parser, PM_ARRAY_PATTERN_NODE, 0, rest),
2193 .opening_loc = { 0 },
2194 .closing_loc = { 0 }
2204static pm_array_pattern_node_t *
2205pm_array_pattern_node_constant_create(pm_parser_t *parser, pm_node_t *constant, const pm_token_t *opening, const pm_token_t *closing) {
2206 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2208 *node = (pm_array_pattern_node_t) {
2209 .base = PM_NODE_INIT_NODE_TOKEN(parser, PM_ARRAY_PATTERN_NODE, 0, constant, closing),
2210 .constant = constant,
2212 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2213 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
2225static pm_array_pattern_node_t *
2226pm_array_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
2227 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2229 *node = (pm_array_pattern_node_t) {
2230 .base = PM_NODE_INIT_TOKENS(parser, PM_ARRAY_PATTERN_NODE, 0, opening, closing),
2233 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2234 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
2243pm_array_pattern_node_requireds_append(pm_array_pattern_node_t *node, pm_node_t *inner) {
2244 pm_node_list_append(&node->requireds, inner);
2250static pm_assoc_node_t *
2251pm_assoc_node_create(pm_parser_t *parser, pm_node_t *key, const pm_token_t *operator, pm_node_t *value) {
2252 pm_assoc_node_t *node = PM_NODE_ALLOC(parser, pm_assoc_node_t);
2255 if (value != NULL && value->location.end > key->location.end) {
2256 end = value->location.end;
2257 } else if (operator->type != PM_TOKEN_NOT_PROVIDED) {
2258 end = operator->end;
2260 end = key->location.end;
2263 // Hash string keys will be frozen, so we can mark them as frozen here so
2264 // that the compiler picks them up and also when we check for static literal
2265 // on the keys it gets factored in.
2266 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
2267 key->flags |= PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL;
2270 // If the key and value of this assoc node are both static literals, then
2271 // we can mark this node as a static literal.
2272 pm_node_flags_t flags = 0;
2274 !PM_NODE_TYPE_P(key, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(key, PM_HASH_NODE) && !PM_NODE_TYPE_P(key, PM_RANGE_NODE) &&
2275 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)
2277 flags = key->flags & value->flags & PM_NODE_FLAG_STATIC_LITERAL;
2280 *node = (pm_assoc_node_t) {
2281 .base = PM_NODE_INIT(parser, PM_ASSOC_NODE, flags, key->location.start, end),
2283 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
2293static pm_assoc_splat_node_t *
2294pm_assoc_splat_node_create(pm_parser_t *parser, pm_node_t *value, const pm_token_t *operator) {
2295 assert(operator->type == PM_TOKEN_USTAR_STAR);
2296 pm_assoc_splat_node_t *node = PM_NODE_ALLOC(parser, pm_assoc_splat_node_t);
2298 *node = (pm_assoc_splat_node_t) {
2301 ? PM_NODE_INIT_TOKEN(parser, PM_ASSOC_SPLAT_NODE, 0, operator)
2302 : PM_NODE_INIT_TOKEN_NODE(parser, PM_ASSOC_SPLAT_NODE, 0, operator, value)
2305 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2314static pm_back_reference_read_node_t *
2315pm_back_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
2316 assert(name->type == PM_TOKEN_BACK_REFERENCE);
2317 pm_back_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_back_reference_read_node_t);
2319 *node = (pm_back_reference_read_node_t) {
2320 .base = PM_NODE_INIT_TOKEN(parser, PM_BACK_REFERENCE_READ_NODE, 0, name),
2321 .name = pm_parser_constant_id_token(parser, name)
2330static pm_begin_node_t *
2331pm_begin_node_create(pm_parser_t *parser, const pm_token_t *begin_keyword, pm_statements_node_t *statements) {
2332 pm_begin_node_t *node = PM_NODE_ALLOC(parser, pm_begin_node_t);
2334 *node = (pm_begin_node_t) {
2336 (statements == NULL)
2337 ? PM_NODE_INIT_TOKEN(parser, PM_BEGIN_NODE, 0, begin_keyword)
2338 : PM_NODE_INIT_TOKEN_NODE(parser, PM_BEGIN_NODE, 0, begin_keyword, statements)
2340 .begin_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(begin_keyword),
2341 .statements = statements,
2342 .end_keyword_loc = { 0 }
2352pm_begin_node_rescue_clause_set(pm_begin_node_t *node, pm_rescue_node_t *rescue_clause) {
2353 // If the begin keyword doesn't exist, we set the start on the begin_node
2354 if (!node->begin_keyword_loc.start) {
2355 node->base.location.start = rescue_clause->base.location.start;
2357 node->base.location.end = rescue_clause->base.location.end;
2358 node->rescue_clause = rescue_clause;
2365pm_begin_node_else_clause_set(pm_begin_node_t *node, pm_else_node_t *else_clause) {
2366 node->base.location.end = else_clause->base.location.end;
2367 node->else_clause = else_clause;
2374pm_begin_node_ensure_clause_set(pm_begin_node_t *node, pm_ensure_node_t *ensure_clause) {
2375 node->base.location.end = ensure_clause->base.location.end;
2376 node->ensure_clause = ensure_clause;
2383pm_begin_node_end_keyword_set(pm_begin_node_t *node, const pm_token_t *end_keyword) {
2384 assert(end_keyword->type == PM_TOKEN_KEYWORD_END || end_keyword->type == PM_TOKEN_MISSING);
2386 node->base.location.end = end_keyword->end;
2387 node->end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword);
2393static pm_block_argument_node_t *
2394pm_block_argument_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
2395 pm_block_argument_node_t *node = PM_NODE_ALLOC(parser, pm_block_argument_node_t);
2397 *node = (pm_block_argument_node_t) {
2399 (expression == NULL)
2400 ? PM_NODE_INIT_TOKEN(parser, PM_BLOCK_ARGUMENT_NODE, 0, operator)
2401 : PM_NODE_INIT_TOKEN_NODE(parser, PM_BLOCK_ARGUMENT_NODE, 0, operator, expression)
2403 .expression = expression,
2404 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2413static pm_block_node_t *
2414pm_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) {
2415 pm_block_node_t *node = PM_NODE_ALLOC(parser, pm_block_node_t);
2417 *node = (pm_block_node_t) {
2418 .base = PM_NODE_INIT_TOKENS(parser, PM_BLOCK_NODE, 0, opening, closing),
2420 .parameters = parameters,
2422 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2423 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
2432static pm_block_parameter_node_t *
2433pm_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator) {
2434 assert(operator->type == PM_TOKEN_NOT_PROVIDED || operator->type == PM_TOKEN_UAMPERSAND || operator->type == PM_TOKEN_AMPERSAND);
2435 pm_block_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_block_parameter_node_t);
2437 *node = (pm_block_parameter_node_t) {
2439 (name->type == PM_TOKEN_NOT_PROVIDED)
2440 ? PM_NODE_INIT_TOKEN(parser, PM_BLOCK_PARAMETER_NODE, 0, operator)
2441 : PM_NODE_INIT_TOKENS(parser, PM_BLOCK_PARAMETER_NODE, 0, operator, name)
2443 .name = pm_parser_optional_constant_id_token(parser, name),
2444 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
2445 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2454static pm_block_parameters_node_t *
2455pm_block_parameters_node_create(pm_parser_t *parser, pm_parameters_node_t *parameters, const pm_token_t *opening) {
2456 pm_block_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_block_parameters_node_t);
2458 const uint8_t *start;
2459 if (opening->type != PM_TOKEN_NOT_PROVIDED) {
2460 start = opening->start;
2461 } else if (parameters != NULL) {
2462 start = parameters->base.location.start;
2468 if (parameters != NULL) {
2469 end = parameters->base.location.end;
2470 } else if (opening->type != PM_TOKEN_NOT_PROVIDED) {
2476 *node = (pm_block_parameters_node_t) {
2477 .base = PM_NODE_INIT(parser, PM_BLOCK_PARAMETERS_NODE, 0, start, end),
2478 .parameters = parameters,
2479 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2480 .closing_loc = { 0 },
2491pm_block_parameters_node_closing_set(pm_block_parameters_node_t *node, const pm_token_t *closing) {
2492 assert(closing->type == PM_TOKEN_PIPE || closing->type == PM_TOKEN_PARENTHESIS_RIGHT || closing->type == PM_TOKEN_MISSING);
2494 node->base.location.end = closing->end;
2495 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
2501static pm_block_local_variable_node_t *
2502pm_block_local_variable_node_create(pm_parser_t *parser, const pm_token_t *name) {
2503 pm_block_local_variable_node_t *node = PM_NODE_ALLOC(parser, pm_block_local_variable_node_t);
2505 *node = (pm_block_local_variable_node_t) {
2506 .base = PM_NODE_INIT_TOKEN(parser, PM_BLOCK_LOCAL_VARIABLE_NODE, 0, name),
2507 .name = pm_parser_constant_id_token(parser, name)
2517pm_block_parameters_node_append_local(pm_block_parameters_node_t *node, const pm_block_local_variable_node_t *local) {
2518 pm_node_list_append(&node->locals, UP(local));
2520 if (node->base.location.start == NULL) node->base.location.start = local->base.location.start;
2521 node->base.location.end = local->base.location.end;
2527static pm_break_node_t *
2528pm_break_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
2529 assert(keyword->type == PM_TOKEN_KEYWORD_BREAK);
2530 pm_break_node_t *node = PM_NODE_ALLOC(parser, pm_break_node_t);
2532 *node = (pm_break_node_t) {
2535 ? PM_NODE_INIT_TOKEN(parser, PM_BREAK_NODE, 0, keyword)
2536 : PM_NODE_INIT_TOKEN_NODE(parser, PM_BREAK_NODE, 0, keyword, arguments)
2538 .arguments = arguments,
2539 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
2545// There are certain flags that we want to use internally but don't want to
2546// expose because they are not relevant beyond parsing. Therefore we'll define
2547// them here and not define them in config.yml/a header file.
2548static const pm_node_flags_t PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY = (1 << 2);
2550static const pm_node_flags_t PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY = ((PM_CALL_NODE_FLAGS_LAST - 1) << 1);
2551static const pm_node_flags_t PM_CALL_NODE_FLAGS_COMPARISON = ((PM_CALL_NODE_FLAGS_LAST - 1) << 2);
2552static const pm_node_flags_t PM_CALL_NODE_FLAGS_INDEX = ((PM_CALL_NODE_FLAGS_LAST - 1) << 3);
2559static pm_call_node_t *
2560pm_call_node_create(pm_parser_t *parser, pm_node_flags_t flags) {
2561 pm_call_node_t *node = PM_NODE_ALLOC(parser, pm_call_node_t);
2563 *node = (pm_call_node_t) {
2564 .base = PM_NODE_INIT_BASE(parser, PM_CALL_NODE, flags),
2566 .call_operator_loc = { 0 },
2567 .message_loc = { 0 },
2568 .opening_loc = { 0 },
2570 .closing_loc = { 0 },
2583static inline pm_node_flags_t
2584pm_call_node_ignore_visibility_flag(const pm_node_t *receiver) {
2585 return PM_NODE_TYPE_P(receiver, PM_SELF_NODE) ? PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY : 0;
2592static pm_call_node_t *
2593pm_call_node_aref_create(pm_parser_t *parser, pm_node_t *receiver, pm_arguments_t *arguments) {
2594 pm_assert_value_expression(parser, receiver);
2596 pm_node_flags_t flags = pm_call_node_ignore_visibility_flag(receiver);
2597 if (arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_ARGUMENT_NODE)) {
2598 flags |= PM_CALL_NODE_FLAGS_INDEX;
2601 pm_call_node_t *node = pm_call_node_create(parser, flags);
2603 node->base.location.start = receiver->location.start;
2604 node->base.location.end = pm_arguments_end(arguments);
2606 node->receiver = receiver;
2607 node->message_loc.start = arguments->opening_loc.start;
2608 node->message_loc.end = arguments->closing_loc.end;
2610 node->opening_loc = arguments->opening_loc;
2611 node->arguments = arguments->arguments;
2612 node->closing_loc = arguments->closing_loc;
2613 node->block = arguments->block;
2615 node->name = pm_parser_constant_id_constant(parser, "[]", 2);
2622static pm_call_node_t *
2623pm_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) {
2624 pm_assert_value_expression(parser, receiver);
2625 pm_assert_value_expression(parser, argument);
2627 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver) | flags);
2629 node->base.location.start = MIN(receiver->location.start, argument->location.start);
2630 node->base.location.end = MAX(receiver->location.end, argument->location.end);
2632 node->receiver = receiver;
2633 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2635 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
2636 pm_arguments_node_arguments_append(arguments, argument);
2637 node->arguments = arguments;
2639 node->name = pm_parser_constant_id_token(parser, operator);
2643static const uint8_t * parse_operator_symbol_name(const pm_token_t *);
2648static pm_call_node_t *
2649pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_token_t *message, pm_arguments_t *arguments) {
2650 pm_assert_value_expression(parser, receiver);
2652 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2654 node->base.location.start = receiver->location.start;
2655 const uint8_t *end = pm_arguments_end(arguments);
2659 node->base.location.end = end;
2661 node->receiver = receiver;
2662 node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2663 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2664 node->opening_loc = arguments->opening_loc;
2665 node->arguments = arguments->arguments;
2666 node->closing_loc = arguments->closing_loc;
2667 node->block = arguments->block;
2669 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2670 pm_node_flag_set(UP(node), PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2677 node->name = pm_parser_constant_id_location(parser, message->start, parse_operator_symbol_name(message));
2684static pm_call_node_t *
2685pm_call_node_call_synthesized_create(pm_parser_t *parser, pm_node_t *receiver, const char *message, pm_arguments_node_t *arguments) {
2686 pm_call_node_t *node = pm_call_node_create(parser, 0);
2687 node->base.location.start = parser->start;
2688 node->base.location.end = parser->end;
2690 node->receiver = receiver;
2691 node->call_operator_loc = (pm_location_t) { .start = NULL, .end = NULL };
2692 node->message_loc = (pm_location_t) { .start = NULL, .end = NULL };
2693 node->arguments = arguments;
2695 node->name = pm_parser_constant_id_constant(parser, message, strlen(message));
2703static pm_call_node_t *
2704pm_call_node_fcall_create(pm_parser_t *parser, pm_token_t *message, pm_arguments_t *arguments) {
2705 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2707 node->base.location.start = message->start;
2708 node->base.location.end = pm_arguments_end(arguments);
2710 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2711 node->opening_loc = arguments->opening_loc;
2712 node->arguments = arguments->arguments;
2713 node->closing_loc = arguments->closing_loc;
2714 node->block = arguments->block;
2716 node->name = pm_parser_constant_id_token(parser, message);
2724static pm_call_node_t *
2725pm_call_node_fcall_synthesized_create(pm_parser_t *parser, pm_arguments_node_t *arguments, pm_constant_id_t name) {
2726 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2728 node->base.location = PM_LOCATION_NULL_VALUE(parser);
2729 node->arguments = arguments;
2738static pm_call_node_t *
2739pm_call_node_not_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *message, pm_arguments_t *arguments) {
2740 pm_assert_value_expression(parser, receiver);
2741 if (receiver != NULL) pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
2743 pm_call_node_t *node = pm_call_node_create(parser, receiver == NULL ? 0 : pm_call_node_ignore_visibility_flag(receiver));
2745 node->base.location.start = message->start;
2746 if (arguments->closing_loc.start != NULL) {
2747 node->base.location.end = arguments->closing_loc.end;
2749 assert(receiver != NULL);
2750 node->base.location.end = receiver->location.end;
2753 node->receiver = receiver;
2754 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2755 node->opening_loc = arguments->opening_loc;
2756 node->arguments = arguments->arguments;
2757 node->closing_loc = arguments->closing_loc;
2759 node->name = pm_parser_constant_id_constant(parser, "!", 1);
2766static pm_call_node_t *
2767pm_call_node_shorthand_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_arguments_t *arguments) {
2768 pm_assert_value_expression(parser, receiver);
2770 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2772 node->base.location.start = receiver->location.start;
2773 node->base.location.end = pm_arguments_end(arguments);
2775 node->receiver = receiver;
2776 node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2777 node->opening_loc = arguments->opening_loc;
2778 node->arguments = arguments->arguments;
2779 node->closing_loc = arguments->closing_loc;
2780 node->block = arguments->block;
2782 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2783 pm_node_flag_set(UP(node), PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2786 node->name = pm_parser_constant_id_constant(parser, "call", 4);
2793static pm_call_node_t *
2794pm_call_node_unary_create(pm_parser_t *parser, pm_token_t *operator, pm_node_t *receiver, const char *name) {
2795 pm_assert_value_expression(parser, receiver);
2797 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2799 node->base.location.start = operator->start;
2800 node->base.location.end = receiver->location.end;
2802 node->receiver = receiver;
2803 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2805 node->name = pm_parser_constant_id_constant(parser, name, strlen(name));
2813static pm_call_node_t *
2814pm_call_node_variable_call_create(pm_parser_t *parser, pm_token_t *message) {
2815 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2817 node->base.location = PM_LOCATION_TOKEN_VALUE(message);
2818 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2820 node->name = pm_parser_constant_id_token(parser, message);
2829pm_call_node_writable_p(const pm_parser_t *parser, const pm_call_node_t *node) {
2831 (node->message_loc.start != NULL) &&
2832 (node->message_loc.end[-1] != '!') &&
2833 (node->message_loc.end[-1] != '?') &&
2834 char_is_identifier_start(parser, node->message_loc.start, parser->end - node->message_loc.start) &&
2835 (node->opening_loc.start == NULL) &&
2836 (node->arguments == NULL) &&
2837 (node->block == NULL)
2845pm_call_write_read_name_init(pm_parser_t *parser, pm_constant_id_t *read_name, pm_constant_id_t *write_name) {
2846 pm_constant_t *write_constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *write_name);
2848 if (write_constant->length > 0) {
2849 size_t length = write_constant->length - 1;
2851 void *memory = xmalloc(length);
2852 memcpy(memory, write_constant->start, length);
2854 *read_name = pm_constant_pool_insert_owned(&parser->constant_pool, (uint8_t *) memory, length);
2856 // We can get here if the message was missing because of a syntax error.
2857 *read_name = pm_parser_constant_id_constant(parser, "", 0);
2864static pm_call_and_write_node_t *
2865pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2866 assert(target->block == NULL);
2867 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
2868 pm_call_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_and_write_node_t);
2870 *node = (pm_call_and_write_node_t) {
2871 .base = PM_NODE_INIT_NODES(parser, PM_CALL_AND_WRITE_NODE, FL(target), target, value),
2872 .receiver = target->receiver,
2873 .call_operator_loc = target->call_operator_loc,
2874 .message_loc = target->message_loc,
2876 .write_name = target->name,
2877 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2881 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
2883 // Here we're going to free the target, since it is no longer necessary.
2884 // However, we don't want to call `pm_node_destroy` because we want to keep
2885 // around all of its children since we just reused them.
2896pm_index_arguments_check(pm_parser_t *parser, const pm_arguments_node_t *arguments, const pm_node_t *block) {
2897 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) {
2898 if (arguments != NULL && PM_NODE_FLAG_P(arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) {
2900 PM_NODE_LIST_FOREACH(&arguments->arguments, index, node) {
2901 if (PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE)) {
2902 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_INDEX_KEYWORDS);
2908 if (block != NULL) {
2909 pm_parser_err_node(parser, block, PM_ERR_UNEXPECTED_INDEX_BLOCK);
2917static pm_index_and_write_node_t *
2918pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2919 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
2920 pm_index_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_and_write_node_t);
2922 pm_index_arguments_check(parser, target->arguments, target->block);
2924 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
2925 *node = (pm_index_and_write_node_t) {
2926 .base = PM_NODE_INIT_NODES(parser, PM_INDEX_AND_WRITE_NODE, FL(target), target, value),
2927 .receiver = target->receiver,
2928 .call_operator_loc = target->call_operator_loc,
2929 .opening_loc = target->opening_loc,
2930 .arguments = target->arguments,
2931 .closing_loc = target->closing_loc,
2932 .block = (pm_block_argument_node_t *) target->block,
2933 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2937 // Here we're going to free the target, since it is no longer necessary.
2938 // However, we don't want to call `pm_node_destroy` because we want to keep
2939 // around all of its children since we just reused them.
2948static pm_call_operator_write_node_t *
2949pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2950 assert(target->block == NULL);
2951 pm_call_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_operator_write_node_t);
2953 *node = (pm_call_operator_write_node_t) {
2954 .base = PM_NODE_INIT_NODES(parser, PM_CALL_OPERATOR_WRITE_NODE, FL(target), target, value),
2955 .receiver = target->receiver,
2956 .call_operator_loc = target->call_operator_loc,
2957 .message_loc = target->message_loc,
2959 .write_name = target->name,
2960 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
2961 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2965 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
2967 // Here we're going to free the target, since it is no longer necessary.
2968 // However, we don't want to call `pm_node_destroy` because we want to keep
2969 // around all of its children since we just reused them.
2978static pm_index_operator_write_node_t *
2979pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2980 pm_index_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_operator_write_node_t);
2982 pm_index_arguments_check(parser, target->arguments, target->block);
2984 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
2985 *node = (pm_index_operator_write_node_t) {
2986 .base = PM_NODE_INIT_NODES(parser, PM_INDEX_OPERATOR_WRITE_NODE, FL(target), target, value),
2987 .receiver = target->receiver,
2988 .call_operator_loc = target->call_operator_loc,
2989 .opening_loc = target->opening_loc,
2990 .arguments = target->arguments,
2991 .closing_loc = target->closing_loc,
2992 .block = (pm_block_argument_node_t *) target->block,
2993 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
2994 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2998 // Here we're going to free the target, since it is no longer necessary.
2999 // However, we don't want to call `pm_node_destroy` because we want to keep
3000 // around all of its children since we just reused them.
3009static pm_call_or_write_node_t *
3010pm_call_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3011 assert(target->block == NULL);
3012 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3013 pm_call_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_or_write_node_t);
3015 *node = (pm_call_or_write_node_t) {
3016 .base = PM_NODE_INIT_NODES(parser, PM_CALL_OR_WRITE_NODE, FL(target), target, value),
3017 .receiver = target->receiver,
3018 .call_operator_loc = target->call_operator_loc,
3019 .message_loc = target->message_loc,
3021 .write_name = target->name,
3022 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3026 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3028 // Here we're going to free the target, since it is no longer necessary.
3029 // However, we don't want to call `pm_node_destroy` because we want to keep
3030 // around all of its children since we just reused them.
3039static pm_index_or_write_node_t *
3040pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3041 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3042 pm_index_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_or_write_node_t);
3044 pm_index_arguments_check(parser, target->arguments, target->block);
3046 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3047 *node = (pm_index_or_write_node_t) {
3048 .base = PM_NODE_INIT_NODES(parser, PM_INDEX_OR_WRITE_NODE, FL(target), target, value),
3049 .receiver = target->receiver,
3050 .call_operator_loc = target->call_operator_loc,
3051 .opening_loc = target->opening_loc,
3052 .arguments = target->arguments,
3053 .closing_loc = target->closing_loc,
3054 .block = (pm_block_argument_node_t *) target->block,
3055 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3059 // Here we're going to free the target, since it is no longer necessary.
3060 // However, we don't want to call `pm_node_destroy` because we want to keep
3061 // around all of its children since we just reused them.
3071static pm_call_target_node_t *
3072pm_call_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3073 pm_call_target_node_t *node = PM_NODE_ALLOC(parser, pm_call_target_node_t);
3075 *node = (pm_call_target_node_t) {
3076 .base = PM_NODE_INIT_NODE(parser, PM_CALL_TARGET_NODE, FL(target), target),
3077 .receiver = target->receiver,
3078 .call_operator_loc = target->call_operator_loc,
3079 .name = target->name,
3080 .message_loc = target->message_loc
3083 /* It is possible to get here where we have parsed an invalid syntax tree
3084 * where the call operator was not present. In that case we will have a
3085 * problem because it is a required location. In this case we need to fill
3086 * it in with a fake location so that the syntax tree remains valid. */
3087 if (node->call_operator_loc.start == NULL) {
3088 node->call_operator_loc = (pm_location_t) {
3089 .start = target->base.location.start,
3090 .end = target->base.location.start
3094 // Here we're going to free the target, since it is no longer necessary.
3095 // However, we don't want to call `pm_node_destroy` because we want to keep
3096 // around all of its children since we just reused them.
3106static pm_index_target_node_t *
3107pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3108 pm_index_target_node_t *node = PM_NODE_ALLOC(parser, pm_index_target_node_t);
3110 pm_index_arguments_check(parser, target->arguments, target->block);
3111 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3113 *node = (pm_index_target_node_t) {
3114 .base = PM_NODE_INIT_NODE(parser, PM_INDEX_TARGET_NODE, FL(target) | PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE, target),
3115 .receiver = target->receiver,
3116 .opening_loc = target->opening_loc,
3117 .arguments = target->arguments,
3118 .closing_loc = target->closing_loc,
3119 .block = (pm_block_argument_node_t *) target->block,
3122 // Here we're going to free the target, since it is no longer necessary.
3123 // However, we don't want to call `pm_node_destroy` because we want to keep
3124 // around all of its children since we just reused them.
3133static pm_capture_pattern_node_t *
3134pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_local_variable_target_node_t *target, const pm_token_t *operator) {
3135 pm_capture_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_capture_pattern_node_t);
3137 *node = (pm_capture_pattern_node_t) {
3138 .base = PM_NODE_INIT_NODES(parser, PM_CAPTURE_PATTERN_NODE, 0, value, target),
3141 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
3150static pm_case_node_t *
3151pm_case_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3152 pm_case_node_t *node = PM_NODE_ALLOC(parser, pm_case_node_t);
3154 *node = (pm_case_node_t) {
3155 .base = PM_NODE_INIT_TOKENS(parser, PM_CASE_NODE, 0, case_keyword, end_keyword),
3156 .predicate = predicate,
3157 .else_clause = NULL,
3158 .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
3159 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3170pm_case_node_condition_append(pm_case_node_t *node, pm_node_t *condition) {
3171 assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
3173 pm_node_list_append(&node->conditions, condition);
3174 node->base.location.end = condition->location.end;
3181pm_case_node_else_clause_set(pm_case_node_t *node, pm_else_node_t *else_clause) {
3182 node->else_clause = else_clause;
3183 node->base.location.end = else_clause->base.location.end;
3190pm_case_node_end_keyword_loc_set(pm_case_node_t *node, const pm_token_t *end_keyword) {
3191 node->base.location.end = end_keyword->end;
3192 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
3198static pm_case_match_node_t *
3199pm_case_match_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3200 pm_case_match_node_t *node = PM_NODE_ALLOC(parser, pm_case_match_node_t);
3202 *node = (pm_case_match_node_t) {
3203 .base = PM_NODE_INIT_TOKENS(parser, PM_CASE_MATCH_NODE, 0, case_keyword, end_keyword),
3204 .predicate = predicate,
3205 .else_clause = NULL,
3206 .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
3207 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3218pm_case_match_node_condition_append(pm_case_match_node_t *node, pm_node_t *condition) {
3219 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
3221 pm_node_list_append(&node->conditions, condition);
3222 node->base.location.end = condition->location.end;
3229pm_case_match_node_else_clause_set(pm_case_match_node_t *node, pm_else_node_t *else_clause) {
3230 node->else_clause = else_clause;
3231 node->base.location.end = else_clause->base.location.end;
3238pm_case_match_node_end_keyword_loc_set(pm_case_match_node_t *node, const pm_token_t *end_keyword) {
3239 node->base.location.end = end_keyword->end;
3240 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
3246static pm_class_node_t *
3247pm_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) {
3248 pm_class_node_t *node = PM_NODE_ALLOC(parser, pm_class_node_t);
3250 *node = (pm_class_node_t) {
3251 .base = PM_NODE_INIT_TOKENS(parser, PM_CLASS_NODE, 0, class_keyword, end_keyword),
3253 .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
3254 .constant_path = constant_path,
3255 .inheritance_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(inheritance_operator),
3256 .superclass = superclass,
3258 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3259 .name = pm_parser_constant_id_token(parser, name)
3268static pm_class_variable_and_write_node_t *
3269pm_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) {
3270 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3271 pm_class_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_and_write_node_t);
3273 *node = (pm_class_variable_and_write_node_t) {
3274 .base = PM_NODE_INIT_NODES(parser, PM_CLASS_VARIABLE_AND_WRITE_NODE, 0, target, value),
3275 .name = target->name,
3276 .name_loc = target->base.location,
3277 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3287static pm_class_variable_operator_write_node_t *
3288pm_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) {
3289 pm_class_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_operator_write_node_t);
3291 *node = (pm_class_variable_operator_write_node_t) {
3292 .base = PM_NODE_INIT_NODES(parser, PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE, 0, target, value),
3293 .name = target->name,
3294 .name_loc = target->base.location,
3295 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3297 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3306static pm_class_variable_or_write_node_t *
3307pm_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) {
3308 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3309 pm_class_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_or_write_node_t);
3311 *node = (pm_class_variable_or_write_node_t) {
3312 .base = PM_NODE_INIT_NODES(parser, PM_CLASS_VARIABLE_OR_WRITE_NODE, 0, target, value),
3313 .name = target->name,
3314 .name_loc = target->base.location,
3315 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3325static pm_class_variable_read_node_t *
3326pm_class_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
3327 assert(token->type == PM_TOKEN_CLASS_VARIABLE);
3328 pm_class_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_read_node_t);
3330 *node = (pm_class_variable_read_node_t) {
3331 .base = PM_NODE_INIT_TOKEN(parser, PM_CLASS_VARIABLE_READ_NODE, 0, token),
3332 .name = pm_parser_constant_id_token(parser, token)
3344static inline pm_node_flags_t
3345pm_implicit_array_write_flags(const pm_node_t *node, pm_node_flags_t flags) {
3346 if (PM_NODE_TYPE_P(node, PM_ARRAY_NODE) && ((const pm_array_node_t *) node)->opening_loc.start == NULL) {
3355static pm_class_variable_write_node_t *
3356pm_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) {
3357 pm_class_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_write_node_t);
3358 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
3360 *node = (pm_class_variable_write_node_t) {
3361 .base = PM_NODE_INIT_NODES(parser, PM_CLASS_VARIABLE_WRITE_NODE, flags, read_node, value),
3362 .name = read_node->name,
3363 .name_loc = PM_LOCATION_NODE_VALUE(UP(read_node)),
3364 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3374static pm_constant_path_and_write_node_t *
3375pm_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) {
3376 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3377 pm_constant_path_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_and_write_node_t);
3379 *node = (pm_constant_path_and_write_node_t) {
3380 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_PATH_AND_WRITE_NODE, 0, target, value),
3382 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3392static pm_constant_path_operator_write_node_t *
3393pm_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) {
3394 pm_constant_path_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_operator_write_node_t);
3396 *node = (pm_constant_path_operator_write_node_t) {
3397 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_PATH_OPERATOR_WRITE_NODE, 0, target, value),
3399 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3401 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3410static pm_constant_path_or_write_node_t *
3411pm_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) {
3412 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3413 pm_constant_path_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_or_write_node_t);
3415 *node = (pm_constant_path_or_write_node_t) {
3416 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_PATH_OR_WRITE_NODE, 0, target, value),
3418 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3428static pm_constant_path_node_t *
3429pm_constant_path_node_create(pm_parser_t *parser, pm_node_t *parent, const pm_token_t *delimiter, const pm_token_t *name_token) {
3430 pm_assert_value_expression(parser, parent);
3431 pm_constant_path_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_node_t);
3433 pm_constant_id_t name = PM_CONSTANT_ID_UNSET;
3434 if (name_token->type == PM_TOKEN_CONSTANT) {
3435 name = pm_parser_constant_id_token(parser, name_token);
3438 if (parent == NULL) {
3439 *node = (pm_constant_path_node_t) {
3440 .base = PM_NODE_INIT_TOKENS(parser, PM_CONSTANT_PATH_NODE, 0, delimiter, name_token),
3443 .delimiter_loc = PM_LOCATION_TOKEN_VALUE(delimiter),
3444 .name_loc = PM_LOCATION_TOKEN_VALUE(name_token)
3447 *node = (pm_constant_path_node_t) {
3448 .base = PM_NODE_INIT_NODE_TOKEN(parser, PM_CONSTANT_PATH_NODE, 0, parent, name_token),
3451 .delimiter_loc = PM_LOCATION_TOKEN_VALUE(delimiter),
3452 .name_loc = PM_LOCATION_TOKEN_VALUE(name_token)
3462static pm_constant_path_write_node_t *
3463pm_constant_path_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3464 pm_constant_path_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_write_node_t);
3465 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
3467 *node = (pm_constant_path_write_node_t) {
3468 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_PATH_WRITE_NODE, flags, target, value),
3470 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3480static pm_constant_and_write_node_t *
3481pm_constant_and_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3482 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3483 pm_constant_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_and_write_node_t);
3485 *node = (pm_constant_and_write_node_t) {
3486 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_AND_WRITE_NODE, 0, target, value),
3487 .name = target->name,
3488 .name_loc = target->base.location,
3489 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3499static pm_constant_operator_write_node_t *
3500pm_constant_operator_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3501 pm_constant_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_operator_write_node_t);
3503 *node = (pm_constant_operator_write_node_t) {
3504 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_OPERATOR_WRITE_NODE, 0, target, value),
3505 .name = target->name,
3506 .name_loc = target->base.location,
3507 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3509 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3518static pm_constant_or_write_node_t *
3519pm_constant_or_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3520 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3521 pm_constant_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_or_write_node_t);
3523 *node = (pm_constant_or_write_node_t) {
3524 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_OR_WRITE_NODE, 0, target, value),
3525 .name = target->name,
3526 .name_loc = target->base.location,
3527 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3537static pm_constant_read_node_t *
3538pm_constant_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
3539 assert(name->type == PM_TOKEN_CONSTANT || name->type == PM_TOKEN_MISSING);
3540 pm_constant_read_node_t *node = PM_NODE_ALLOC(parser, pm_constant_read_node_t);
3542 *node = (pm_constant_read_node_t) {
3543 .base = PM_NODE_INIT_TOKEN(parser, PM_CONSTANT_READ_NODE, 0, name),
3544 .name = pm_parser_constant_id_token(parser, name)
3553static pm_constant_write_node_t *
3554pm_constant_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3555 pm_constant_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_write_node_t);
3556 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
3558 *node = (pm_constant_write_node_t) {
3559 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_WRITE_NODE, flags, target, value),
3560 .name = target->name,
3561 .name_loc = target->base.location,
3562 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3573pm_def_node_receiver_check(pm_parser_t *parser, const pm_node_t *node) {
3574 switch (PM_NODE_TYPE(node)) {
3575 case PM_BEGIN_NODE: {
3576 const pm_begin_node_t *cast = (pm_begin_node_t *) node;
3577 if (cast->statements != NULL) pm_def_node_receiver_check(parser, UP(cast->statements));
3580 case PM_PARENTHESES_NODE: {
3581 const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node;
3582 if (cast->body != NULL) pm_def_node_receiver_check(parser, cast->body);
3585 case PM_STATEMENTS_NODE: {
3586 const pm_statements_node_t *cast = (const pm_statements_node_t *) node;
3587 pm_def_node_receiver_check(parser, cast->body.nodes[cast->body.size - 1]);
3592 case PM_IMAGINARY_NODE:
3593 case PM_INTEGER_NODE:
3594 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
3595 case PM_INTERPOLATED_STRING_NODE:
3596 case PM_INTERPOLATED_SYMBOL_NODE:
3597 case PM_INTERPOLATED_X_STRING_NODE:
3598 case PM_RATIONAL_NODE:
3599 case PM_REGULAR_EXPRESSION_NODE:
3600 case PM_SOURCE_ENCODING_NODE:
3601 case PM_SOURCE_FILE_NODE:
3602 case PM_SOURCE_LINE_NODE:
3603 case PM_STRING_NODE:
3604 case PM_SYMBOL_NODE:
3605 case PM_X_STRING_NODE:
3606 pm_parser_err_node(parser, node, PM_ERR_SINGLETON_FOR_LITERALS);
3616static pm_def_node_t *
3618 pm_parser_t *parser,
3619 pm_constant_id_t name,
3620 const pm_token_t *name_loc,
3621 pm_node_t *receiver,
3622 pm_parameters_node_t *parameters,
3624 pm_constant_id_list_t *locals,
3625 const pm_token_t *def_keyword,
3626 const pm_token_t *operator,
3627 const pm_token_t *lparen,
3628 const pm_token_t *rparen,
3629 const pm_token_t *equal,
3630 const pm_token_t *end_keyword
3632 pm_def_node_t *node = PM_NODE_ALLOC(parser, pm_def_node_t);
3634 if (receiver != NULL) {
3635 pm_def_node_receiver_check(parser, receiver);
3638 *node = (pm_def_node_t) {
3640 (end_keyword->type == PM_TOKEN_NOT_PROVIDED)
3641 ? PM_NODE_INIT_TOKEN_NODE(parser, PM_DEF_NODE, 0, def_keyword, body)
3642 : PM_NODE_INIT_TOKENS(parser, PM_DEF_NODE, 0, def_keyword, end_keyword)
3645 .name_loc = PM_LOCATION_TOKEN_VALUE(name_loc),
3646 .receiver = receiver,
3647 .parameters = parameters,
3650 .def_keyword_loc = PM_LOCATION_TOKEN_VALUE(def_keyword),
3651 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3652 .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
3653 .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
3654 .equal_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(equal),
3655 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
3664static pm_defined_node_t *
3665pm_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) {
3666 pm_defined_node_t *node = PM_NODE_ALLOC(parser, pm_defined_node_t);
3668 *node = (pm_defined_node_t) {
3670 (rparen->type == PM_TOKEN_NOT_PROVIDED)
3671 ? PM_NODE_INIT_TOKEN_NODE(parser, PM_DEFINED_NODE, 0, keyword, value)
3672 : PM_NODE_INIT_TOKENS(parser, PM_DEFINED_NODE, 0, keyword, rparen)
3674 .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
3676 .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
3677 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
3686static pm_else_node_t *
3687pm_else_node_create(pm_parser_t *parser, const pm_token_t *else_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
3688 pm_else_node_t *node = PM_NODE_ALLOC(parser, pm_else_node_t);
3690 *node = (pm_else_node_t) {
3692 ((end_keyword->type == PM_TOKEN_NOT_PROVIDED) && (statements != NULL))
3693 ? PM_NODE_INIT_TOKEN_NODE(parser, PM_ELSE_NODE, 0, else_keyword, statements)
3694 : PM_NODE_INIT_TOKENS(parser, PM_ELSE_NODE, 0, else_keyword, end_keyword)
3696 .else_keyword_loc = PM_LOCATION_TOKEN_VALUE(else_keyword),
3697 .statements = statements,
3698 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
3707static pm_embedded_statements_node_t *
3708pm_embedded_statements_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
3709 pm_embedded_statements_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_statements_node_t);
3711 *node = (pm_embedded_statements_node_t) {
3712 .base = PM_NODE_INIT_TOKENS(parser, PM_EMBEDDED_STATEMENTS_NODE, 0, opening, closing),
3713 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
3714 .statements = statements,
3715 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
3724static pm_embedded_variable_node_t *
3725pm_embedded_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
3726 pm_embedded_variable_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_variable_node_t);
3728 *node = (pm_embedded_variable_node_t) {
3729 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_EMBEDDED_VARIABLE_NODE, 0, operator, variable),
3730 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3731 .variable = variable
3740static pm_ensure_node_t *
3741pm_ensure_node_create(pm_parser_t *parser, const pm_token_t *ensure_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
3742 pm_ensure_node_t *node = PM_NODE_ALLOC(parser, pm_ensure_node_t);
3744 *node = (pm_ensure_node_t) {
3745 .base = PM_NODE_INIT_TOKENS(parser, PM_ENSURE_NODE, 0, ensure_keyword, end_keyword),
3746 .ensure_keyword_loc = PM_LOCATION_TOKEN_VALUE(ensure_keyword),
3747 .statements = statements,
3748 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
3757static pm_false_node_t *
3758pm_false_node_create(pm_parser_t *parser, const pm_token_t *token) {
3759 assert(token->type == PM_TOKEN_KEYWORD_FALSE);
3760 pm_false_node_t *node = PM_NODE_ALLOC(parser, pm_false_node_t);
3762 *node = (pm_false_node_t) {
3763 .base = PM_NODE_INIT_TOKEN(parser, PM_FALSE_NODE, PM_NODE_FLAG_STATIC_LITERAL, token)
3773static pm_find_pattern_node_t *
3774pm_find_pattern_node_create(pm_parser_t *parser, pm_node_list_t *nodes) {
3775 pm_find_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_find_pattern_node_t);
3777 pm_node_t *left = nodes->nodes[0];
3778 assert(PM_NODE_TYPE_P(left, PM_SPLAT_NODE));
3779 pm_splat_node_t *left_splat_node = (pm_splat_node_t *) left;
3783 if (nodes->size == 1) {
3784 right = UP(pm_missing_node_create(parser, left->location.end, left->location.end));
3786 right = nodes->nodes[nodes->size - 1];
3787 assert(PM_NODE_TYPE_P(right, PM_SPLAT_NODE));
3790#if PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS
3791 // FindPatternNode#right is typed as SplatNode in this case, so replace the potential MissingNode with a SplatNode.
3792 // The resulting AST will anyway be ignored, but this file still needs to compile.
3793 pm_splat_node_t *right_splat_node = PM_NODE_TYPE_P(right, PM_SPLAT_NODE) ? (pm_splat_node_t *) right : left_splat_node;
3795 pm_node_t *right_splat_node = right;
3797 *node = (pm_find_pattern_node_t) {
3798 .base = PM_NODE_INIT_NODES(parser, PM_FIND_PATTERN_NODE, 0, left, right),
3800 .left = left_splat_node,
3801 .right = right_splat_node,
3803 .opening_loc = { 0 },
3804 .closing_loc = { 0 }
3807 // For now we're going to just copy over each pointer manually. This could be
3808 // much more efficient, as we could instead resize the node list to only point
3810 for (size_t index = 1; index < nodes->size - 1; index++) {
3811 pm_node_list_append(&node->requireds, nodes->nodes[index]);
3822pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
3823 ptrdiff_t diff = token->end - token->start;
3824 if (diff <= 0) return 0.0;
3826 // First, get a buffer of the content.
3827 size_t length = (size_t) diff;
3828 char *buffer = xmalloc(sizeof(char) * (length + 1));
3829 memcpy((void *) buffer, token->start, length);
3831 // Next, determine if we need to replace the decimal point because of
3832 // locale-specific options, and then normalize them if we have to.
3833 char decimal_point = *localeconv()->decimal_point;
3834 if (decimal_point != '.') {
3835 for (size_t index = 0; index < length; index++) {
3836 if (buffer[index] == '.') buffer[index] = decimal_point;
3840 // Next, handle underscores by removing them from the buffer.
3841 for (size_t index = 0; index < length; index++) {
3842 if (buffer[index] == '_') {
3843 memmove((void *) (buffer + index), (void *) (buffer + index + 1), length - index);
3848 // Null-terminate the buffer so that strtod cannot read off the end.
3849 buffer[length] = '\0';
3851 // Now, call strtod to parse the value. Note that CRuby has their own
3852 // version of strtod which avoids locales. We're okay using the locale-aware
3853 // version because we've already validated through the parser that the token
3854 // is in a valid format.
3857 double value = strtod(buffer, &eptr);
3859 // This should never happen, because we've already checked that the token
3860 // is in a valid format. However it's good to be safe.
3861 if ((eptr != buffer + length) || (errno != 0 && errno != ERANGE)) {
3862 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, (*token), PM_ERR_FLOAT_PARSE);
3863 xfree((void *) buffer);
3867 // If errno is set, then it should only be ERANGE. At this point we need to
3868 // check if it's infinity (it should be).
3869 if (errno == ERANGE && PRISM_ISINF(value)) {
3871 const char *ellipsis;
3877 warn_width = (int) length;
3881 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);
3882 value = (value < 0.0) ? -HUGE_VAL : HUGE_VAL;
3885 // Finally we can free the buffer and return the value.
3886 xfree((void *) buffer);
3893static pm_float_node_t *
3894pm_float_node_create(pm_parser_t *parser, const pm_token_t *token) {
3895 assert(token->type == PM_TOKEN_FLOAT);
3896 pm_float_node_t *node = PM_NODE_ALLOC(parser, pm_float_node_t);
3898 *node = (pm_float_node_t) {
3899 .base = PM_NODE_INIT_TOKEN(parser, PM_FLOAT_NODE, PM_NODE_FLAG_STATIC_LITERAL, token),
3900 .value = pm_double_parse(parser, token)
3909static pm_imaginary_node_t *
3910pm_float_node_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
3911 assert(token->type == PM_TOKEN_FLOAT_IMAGINARY);
3913 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
3914 *node = (pm_imaginary_node_t) {
3915 .base = PM_NODE_INIT_TOKEN(parser, PM_IMAGINARY_NODE, PM_NODE_FLAG_STATIC_LITERAL, token),
3916 .numeric = UP(pm_float_node_create(parser, &((pm_token_t) {
3917 .type = PM_TOKEN_FLOAT,
3918 .start = token->start,
3919 .end = token->end - 1
3929static pm_rational_node_t *
3930pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
3931 assert(token->type == PM_TOKEN_FLOAT_RATIONAL);
3933 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
3934 *node = (pm_rational_node_t) {
3935 .base = PM_NODE_INIT_TOKEN(parser, PM_RATIONAL_NODE, PM_INTEGER_BASE_FLAGS_DECIMAL | PM_NODE_FLAG_STATIC_LITERAL, token),
3937 .denominator = { 0 }
3940 const uint8_t *start = token->start;
3941 const uint8_t *end = token->end - 1; // r
3943 while (start < end && *start == '0') start++; // 0.1 -> .1
3944 while (end > start && end[-1] == '0') end--; // 1.0 -> 1.
3946 size_t length = (size_t) (end - start);
3948 node->denominator.value = 1;
3952 const uint8_t *point = memchr(start, '.', length);
3953 assert(point && "should have a decimal point");
3955 uint8_t *digits = xmalloc(length);
3956 if (digits == NULL) {
3957 fputs("[pm_float_node_rational_create] Failed to allocate memory", stderr);
3961 memcpy(digits, start, (unsigned long) (point - start));
3962 memcpy(digits + (point - start), point + 1, (unsigned long) (end - point - 1));
3963 pm_integer_parse(&node->numerator, PM_INTEGER_BASE_DEFAULT, digits, digits + length - 1);
3966 if (end - point > 1) memset(digits + 1, '0', (size_t) (end - point - 1));
3967 pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + (end - point));
3970 pm_integers_reduce(&node->numerator, &node->denominator);
3978static pm_imaginary_node_t *
3979pm_float_node_rational_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
3980 assert(token->type == PM_TOKEN_FLOAT_RATIONAL_IMAGINARY);
3982 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
3983 *node = (pm_imaginary_node_t) {
3984 .base = PM_NODE_INIT_TOKEN(parser, PM_IMAGINARY_NODE, PM_NODE_FLAG_STATIC_LITERAL, token),
3985 .numeric = UP(pm_float_node_rational_create(parser, &((pm_token_t) {
3986 .type = PM_TOKEN_FLOAT_RATIONAL,
3987 .start = token->start,
3988 .end = token->end - 1
3998static pm_for_node_t *
4000 pm_parser_t *parser,
4002 pm_node_t *collection,
4003 pm_statements_node_t *statements,
4004 const pm_token_t *for_keyword,
4005 const pm_token_t *in_keyword,
4006 const pm_token_t *do_keyword,
4007 const pm_token_t *end_keyword
4009 pm_for_node_t *node = PM_NODE_ALLOC(parser, pm_for_node_t);
4011 *node = (pm_for_node_t) {
4012 .base = PM_NODE_INIT_TOKENS(parser, PM_FOR_NODE, 0, for_keyword, end_keyword),
4014 .collection = collection,
4015 .statements = statements,
4016 .for_keyword_loc = PM_LOCATION_TOKEN_VALUE(for_keyword),
4017 .in_keyword_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
4018 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
4019 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
4028static pm_forwarding_arguments_node_t *
4029pm_forwarding_arguments_node_create(pm_parser_t *parser, const pm_token_t *token) {
4030 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4031 pm_forwarding_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_arguments_node_t);
4033 *node = (pm_forwarding_arguments_node_t) {
4034 .base = PM_NODE_INIT_TOKEN(parser, PM_FORWARDING_ARGUMENTS_NODE, 0, token)
4043static pm_forwarding_parameter_node_t *
4044pm_forwarding_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
4045 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4046 pm_forwarding_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_parameter_node_t);
4048 *node = (pm_forwarding_parameter_node_t) {
4049 .base = PM_NODE_INIT_TOKEN(parser, PM_FORWARDING_PARAMETER_NODE, 0, token)
4058static pm_forwarding_super_node_t *
4059pm_forwarding_super_node_create(pm_parser_t *parser, const pm_token_t *token, pm_arguments_t *arguments) {
4060 assert(arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_NODE));
4061 assert(token->type == PM_TOKEN_KEYWORD_SUPER);
4062 pm_forwarding_super_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_super_node_t);
4064 pm_block_node_t *block = NULL;
4065 if (arguments->block != NULL) {
4066 block = (pm_block_node_t *) arguments->block;
4069 *node = (pm_forwarding_super_node_t) {
4072 ? PM_NODE_INIT_TOKEN(parser, PM_FORWARDING_SUPER_NODE, 0, token)
4073 : PM_NODE_INIT_TOKEN_NODE(parser, PM_FORWARDING_SUPER_NODE, 0, token, block)
4085static pm_hash_pattern_node_t *
4086pm_hash_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4087 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4089 *node = (pm_hash_pattern_node_t) {
4090 .base = PM_NODE_INIT_TOKENS(parser, PM_HASH_PATTERN_NODE, 0, opening, closing),
4092 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4093 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
4104static pm_hash_pattern_node_t *
4105pm_hash_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *elements, pm_node_t *rest) {
4106 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4108 const uint8_t *start;
4111 if (elements->size > 0) {
4113 start = MIN(rest->location.start, elements->nodes[0]->location.start);
4114 end = MAX(rest->location.end, elements->nodes[elements->size - 1]->location.end);
4116 start = elements->nodes[0]->location.start;
4117 end = elements->nodes[elements->size - 1]->location.end;
4120 assert(rest != NULL);
4121 start = rest->location.start;
4122 end = rest->location.end;
4125 *node = (pm_hash_pattern_node_t) {
4126 .base = PM_NODE_INIT(parser, PM_HASH_PATTERN_NODE, 0, start, end),
4130 .opening_loc = { 0 },
4131 .closing_loc = { 0 }
4134 pm_node_list_concat(&node->elements, elements);
4141static pm_constant_id_t
4142pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
4143 switch (PM_NODE_TYPE(target)) {
4144 case PM_GLOBAL_VARIABLE_READ_NODE:
4145 return ((pm_global_variable_read_node_t *) target)->name;
4146 case PM_BACK_REFERENCE_READ_NODE:
4147 return ((pm_back_reference_read_node_t *) target)->name;
4148 case PM_NUMBERED_REFERENCE_READ_NODE:
4149 // This will only ever happen in the event of a syntax error, but we
4150 // still need to provide something for the node.
4151 return pm_parser_constant_id_location(parser, target->location.start, target->location.end);
4153 assert(false && "unreachable");
4154 return (pm_constant_id_t) -1;
4161static pm_global_variable_and_write_node_t *
4162pm_global_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4163 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4164 pm_global_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_and_write_node_t);
4166 *node = (pm_global_variable_and_write_node_t) {
4167 .base = PM_NODE_INIT_NODES(parser, PM_GLOBAL_VARIABLE_AND_WRITE_NODE, 0, target, value),
4168 .name = pm_global_variable_write_name(parser, target),
4169 .name_loc = target->location,
4170 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4180static pm_global_variable_operator_write_node_t *
4181pm_global_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4182 pm_global_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_operator_write_node_t);
4184 *node = (pm_global_variable_operator_write_node_t) {
4185 .base = PM_NODE_INIT_NODES(parser, PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE, 0, target, value),
4186 .name = pm_global_variable_write_name(parser, target),
4187 .name_loc = target->location,
4188 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4190 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
4199static pm_global_variable_or_write_node_t *
4200pm_global_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4201 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4202 pm_global_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_or_write_node_t);
4204 *node = (pm_global_variable_or_write_node_t) {
4205 .base = PM_NODE_INIT_NODES(parser, PM_GLOBAL_VARIABLE_OR_WRITE_NODE, 0, target, value),
4206 .name = pm_global_variable_write_name(parser, target),
4207 .name_loc = target->location,
4208 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4218static pm_global_variable_read_node_t *
4219pm_global_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
4220 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4222 *node = (pm_global_variable_read_node_t) {
4223 .base = PM_NODE_INIT_TOKEN(parser, PM_GLOBAL_VARIABLE_READ_NODE, 0, name),
4224 .name = pm_parser_constant_id_token(parser, name)
4233static pm_global_variable_read_node_t *
4234pm_global_variable_read_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name) {
4235 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4237 *node = (pm_global_variable_read_node_t) {
4238 .base = PM_NODE_INIT_BASE(parser, PM_GLOBAL_VARIABLE_READ_NODE, 0),
4248static pm_global_variable_write_node_t *
4249pm_global_variable_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4250 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4251 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
4253 *node = (pm_global_variable_write_node_t) {
4254 .base = PM_NODE_INIT_NODES(parser, PM_GLOBAL_VARIABLE_WRITE_NODE, flags, target, value),
4255 .name = pm_global_variable_write_name(parser, target),
4256 .name_loc = PM_LOCATION_NODE_VALUE(target),
4257 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
4267static pm_global_variable_write_node_t *
4268pm_global_variable_write_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name, pm_node_t *value) {
4269 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4271 *node = (pm_global_variable_write_node_t) {
4272 .base = PM_NODE_INIT_BASE(parser, PM_GLOBAL_VARIABLE_WRITE_NODE, 0),
4274 .name_loc = PM_LOCATION_NULL_VALUE(parser),
4275 .operator_loc = PM_LOCATION_NULL_VALUE(parser),
4285static pm_hash_node_t *
4286pm_hash_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4287 assert(opening != NULL);
4288 pm_hash_node_t *node = PM_NODE_ALLOC(parser, pm_hash_node_t);
4290 *node = (pm_hash_node_t) {
4291 .base = PM_NODE_INIT_TOKEN(parser, PM_HASH_NODE, PM_NODE_FLAG_STATIC_LITERAL, opening),
4292 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4293 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
4304pm_hash_node_elements_append(pm_hash_node_t *hash, pm_node_t *element) {
4305 pm_node_list_append(&hash->elements, element);
4307 bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE);
4308 if (static_literal) {
4309 pm_assoc_node_t *assoc = (pm_assoc_node_t *) element;
4310 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);
4311 static_literal = static_literal && PM_NODE_FLAG_P(assoc->key, PM_NODE_FLAG_STATIC_LITERAL);
4312 static_literal = static_literal && PM_NODE_FLAG_P(assoc, PM_NODE_FLAG_STATIC_LITERAL);
4315 if (!static_literal) {
4316 pm_node_flag_unset(UP(hash), PM_NODE_FLAG_STATIC_LITERAL);
4321pm_hash_node_closing_loc_set(pm_hash_node_t *hash, pm_token_t *token) {
4322 hash->base.location.end = token->end;
4323 hash->closing_loc = PM_LOCATION_TOKEN_VALUE(token);
4329static pm_if_node_t *
4330pm_if_node_create(pm_parser_t *parser,
4331 const pm_token_t *if_keyword,
4332 pm_node_t *predicate,
4333 const pm_token_t *then_keyword,
4334 pm_statements_node_t *statements,
4335 pm_node_t *subsequent,
4336 const pm_token_t *end_keyword
4338 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4339 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4342 if (end_keyword->type != PM_TOKEN_NOT_PROVIDED) {
4343 end = end_keyword->end;
4344 } else if (subsequent != NULL) {
4345 end = subsequent->location.end;
4346 } else if (pm_statements_node_body_length(statements) != 0) {
4347 end = statements->base.location.end;
4349 end = predicate->location.end;
4352 *node = (pm_if_node_t) {
4353 .base = PM_NODE_INIT(parser, PM_IF_NODE, PM_NODE_FLAG_NEWLINE, if_keyword->start, end),
4354 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4355 .predicate = predicate,
4356 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
4357 .statements = statements,
4358 .subsequent = subsequent,
4359 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
4368static pm_if_node_t *
4369pm_if_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *if_keyword, pm_node_t *predicate) {
4370 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4371 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4373 pm_statements_node_t *statements = pm_statements_node_create(parser);
4374 pm_statements_node_body_append(parser, statements, statement, true);
4376 *node = (pm_if_node_t) {
4377 .base = PM_NODE_INIT_NODES(parser, PM_IF_NODE, PM_NODE_FLAG_NEWLINE, statement, predicate),
4378 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4379 .predicate = predicate,
4380 .then_keyword_loc = { 0 },
4381 .statements = statements,
4383 .end_keyword_loc = { 0 }
4392static pm_if_node_t *
4393pm_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) {
4394 pm_assert_value_expression(parser, predicate);
4395 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4397 pm_statements_node_t *if_statements = pm_statements_node_create(parser);
4398 pm_statements_node_body_append(parser, if_statements, true_expression, true);
4400 pm_statements_node_t *else_statements = pm_statements_node_create(parser);
4401 pm_statements_node_body_append(parser, else_statements, false_expression, true);
4403 pm_token_t end_keyword = not_provided(parser);
4404 pm_else_node_t *else_node = pm_else_node_create(parser, colon, else_statements, &end_keyword);
4406 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4408 *node = (pm_if_node_t) {
4409 .base = PM_NODE_INIT_NODES(parser, PM_IF_NODE, PM_NODE_FLAG_NEWLINE, predicate, false_expression),
4410 .if_keyword_loc = { 0 },
4411 .predicate = predicate,
4412 .then_keyword_loc = PM_LOCATION_TOKEN_VALUE(qmark),
4413 .statements = if_statements,
4414 .subsequent = UP(else_node),
4415 .end_keyword_loc = { 0 }
4423pm_if_node_end_keyword_loc_set(pm_if_node_t *node, const pm_token_t *keyword) {
4424 node->base.location.end = keyword->end;
4425 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4429pm_else_node_end_keyword_loc_set(pm_else_node_t *node, const pm_token_t *keyword) {
4430 node->base.location.end = keyword->end;
4431 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4437static pm_implicit_node_t *
4438pm_implicit_node_create(pm_parser_t *parser, pm_node_t *value) {
4439 pm_implicit_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_node_t);
4441 *node = (pm_implicit_node_t) {
4442 .base = PM_NODE_INIT_NODE(parser, PM_IMPLICIT_NODE, 0, value),
4452static pm_implicit_rest_node_t *
4453pm_implicit_rest_node_create(pm_parser_t *parser, const pm_token_t *token) {
4454 assert(token->type == PM_TOKEN_COMMA);
4456 pm_implicit_rest_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_rest_node_t);
4458 *node = (pm_implicit_rest_node_t) {
4459 .base = PM_NODE_INIT_TOKEN(parser, PM_IMPLICIT_REST_NODE, 0, token)
4468static pm_integer_node_t *
4469pm_integer_node_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4470 assert(token->type == PM_TOKEN_INTEGER);
4471 pm_integer_node_t *node = PM_NODE_ALLOC(parser, pm_integer_node_t);
4473 *node = (pm_integer_node_t) {
4474 .base = PM_NODE_INIT_TOKEN(parser, PM_INTEGER_NODE, base | PM_NODE_FLAG_STATIC_LITERAL, token),
4478 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4480 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4481 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4482 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4483 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4484 default: assert(false && "unreachable"); break;
4487 pm_integer_parse(&node->value, integer_base, token->start, token->end);
4495static pm_imaginary_node_t *
4496pm_integer_node_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4497 assert(token->type == PM_TOKEN_INTEGER_IMAGINARY);
4499 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4500 *node = (pm_imaginary_node_t) {
4501 .base = PM_NODE_INIT_TOKEN(parser, PM_IMAGINARY_NODE, PM_NODE_FLAG_STATIC_LITERAL, token),
4502 .numeric = UP(pm_integer_node_create(parser, base, &((pm_token_t) {
4503 .type = PM_TOKEN_INTEGER,
4504 .start = token->start,
4505 .end = token->end - 1
4516static pm_rational_node_t *
4517pm_integer_node_rational_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4518 assert(token->type == PM_TOKEN_INTEGER_RATIONAL);
4520 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
4521 *node = (pm_rational_node_t) {
4522 .base = PM_NODE_INIT_TOKEN(parser, PM_RATIONAL_NODE, base | PM_NODE_FLAG_STATIC_LITERAL, token),
4524 .denominator = { .value = 1, 0 }
4527 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4529 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4530 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4531 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4532 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4533 default: assert(false && "unreachable"); break;
4536 pm_integer_parse(&node->numerator, integer_base, token->start, token->end - 1);
4545static pm_imaginary_node_t *
4546pm_integer_node_rational_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4547 assert(token->type == PM_TOKEN_INTEGER_RATIONAL_IMAGINARY);
4549 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4550 *node = (pm_imaginary_node_t) {
4551 .base = PM_NODE_INIT_TOKEN(parser, PM_IMAGINARY_NODE, PM_NODE_FLAG_STATIC_LITERAL, token),
4552 .numeric = UP(pm_integer_node_rational_create(parser, base, &((pm_token_t) {
4553 .type = PM_TOKEN_INTEGER_RATIONAL,
4554 .start = token->start,
4555 .end = token->end - 1
4565static pm_in_node_t *
4566pm_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) {
4567 pm_in_node_t *node = PM_NODE_ALLOC(parser, pm_in_node_t);
4570 if (statements != NULL) {
4571 end = statements->base.location.end;
4572 } else if (then_keyword->type != PM_TOKEN_NOT_PROVIDED) {
4573 end = then_keyword->end;
4575 end = pattern->location.end;
4578 *node = (pm_in_node_t) {
4579 .base = PM_NODE_INIT(parser, PM_IN_NODE, 0, in_keyword->start, end),
4581 .statements = statements,
4582 .in_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
4583 .then_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword)
4592static pm_instance_variable_and_write_node_t *
4593pm_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) {
4594 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4595 pm_instance_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_and_write_node_t);
4597 *node = (pm_instance_variable_and_write_node_t) {
4598 .base = PM_NODE_INIT_NODES(parser, PM_INSTANCE_VARIABLE_AND_WRITE_NODE, 0, target, value),
4599 .name = target->name,
4600 .name_loc = target->base.location,
4601 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4611static pm_instance_variable_operator_write_node_t *
4612pm_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) {
4613 pm_instance_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_operator_write_node_t);
4615 *node = (pm_instance_variable_operator_write_node_t) {
4616 .base = PM_NODE_INIT_NODES(parser, PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE, 0, target, value),
4617 .name = target->name,
4618 .name_loc = target->base.location,
4619 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4621 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
4630static pm_instance_variable_or_write_node_t *
4631pm_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) {
4632 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4633 pm_instance_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_or_write_node_t);
4635 *node = (pm_instance_variable_or_write_node_t) {
4636 .base = PM_NODE_INIT_NODES(parser, PM_INSTANCE_VARIABLE_OR_WRITE_NODE, 0, target, value),
4637 .name = target->name,
4638 .name_loc = target->base.location,
4639 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4649static pm_instance_variable_read_node_t *
4650pm_instance_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
4651 assert(token->type == PM_TOKEN_INSTANCE_VARIABLE);
4652 pm_instance_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_read_node_t);
4654 *node = (pm_instance_variable_read_node_t) {
4655 .base = PM_NODE_INIT_TOKEN(parser, PM_INSTANCE_VARIABLE_READ_NODE, 0, token),
4656 .name = pm_parser_constant_id_token(parser, token)
4666static pm_instance_variable_write_node_t *
4667pm_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) {
4668 pm_instance_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_write_node_t);
4669 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
4671 *node = (pm_instance_variable_write_node_t) {
4672 .base = PM_NODE_INIT_NODES(parser, PM_INSTANCE_VARIABLE_WRITE_NODE, flags, read_node, value),
4673 .name = read_node->name,
4674 .name_loc = PM_LOCATION_NODE_VALUE(read_node),
4675 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
4688pm_interpolated_node_append(pm_node_t *node, pm_node_list_t *parts, pm_node_t *part) {
4689 switch (PM_NODE_TYPE(part)) {
4690 case PM_STRING_NODE:
4691 pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
4693 case PM_EMBEDDED_STATEMENTS_NODE: {
4694 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
4695 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
4697 if (embedded == NULL) {
4698 // If there are no statements or more than one statement, then
4699 // we lose the static literal flag.
4700 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
4701 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
4702 // If the embedded statement is a string, then we can keep the
4703 // static literal flag and mark the string as frozen.
4704 pm_node_flag_set(embedded, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
4705 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
4706 // If the embedded statement is an interpolated string and it's
4707 // a static literal, then we can keep the static literal flag.
4709 // Otherwise we lose the static literal flag.
4710 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
4715 case PM_EMBEDDED_VARIABLE_NODE:
4716 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
4719 assert(false && "unexpected node type");
4723 pm_node_list_append(parts, part);
4729static pm_interpolated_regular_expression_node_t *
4730pm_interpolated_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4731 pm_interpolated_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_regular_expression_node_t);
4733 *node = (pm_interpolated_regular_expression_node_t) {
4734 .base = PM_NODE_INIT_TOKEN(parser, PM_INTERPOLATED_REGULAR_EXPRESSION_NODE, PM_NODE_FLAG_STATIC_LITERAL, opening),
4735 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4736 .closing_loc = PM_LOCATION_TOKEN_VALUE(opening),
4744pm_interpolated_regular_expression_node_append(pm_interpolated_regular_expression_node_t *node, pm_node_t *part) {
4745 if (node->base.location.start > part->location.start) {
4746 node->base.location.start = part->location.start;
4748 if (node->base.location.end < part->location.end) {
4749 node->base.location.end = part->location.end;
4752 pm_interpolated_node_append(UP(node), &node->parts, part);
4756pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_interpolated_regular_expression_node_t *node, const pm_token_t *closing) {
4757 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
4758 node->base.location.end = closing->end;
4759 pm_node_flag_set(UP(node), pm_regular_expression_flags_create(parser, closing));
4786pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_node_t *part) {
4787#define CLEAR_FLAGS(node) \
4788 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))
4790#define MUTABLE_FLAGS(node) \
4791 node->base.flags = (pm_node_flags_t) ((FL(node) | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE) & ~PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN);
4793 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
4794 node->base.location.start = part->location.start;
4797 node->base.location.end = MAX(node->base.location.end, part->location.end);
4799 switch (PM_NODE_TYPE(part)) {
4800 case PM_STRING_NODE:
4801 // If inner string is not frozen, it stops being a static literal. We should *not* clear other flags,
4802 // because concatenating two frozen strings (`'foo' 'bar'`) is still frozen. This holds true for
4803 // as long as this interpolation only consists of other string literals.
4804 if (!PM_NODE_FLAG_P(part, PM_STRING_FLAGS_FROZEN)) {
4805 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
4807 part->flags = (pm_node_flags_t) ((part->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
4809 case PM_INTERPOLATED_STRING_NODE:
4810 if (PM_NODE_FLAG_P(part, PM_NODE_FLAG_STATIC_LITERAL)) {
4811 // If the string that we're concatenating is a static literal,
4812 // then we can keep the static literal flag for this string.
4814 // Otherwise, we lose the static literal flag here and we should
4815 // also clear the mutability flags.
4819 case PM_EMBEDDED_STATEMENTS_NODE: {
4820 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
4821 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
4823 if (embedded == NULL) {
4824 // If we're embedding multiple statements or no statements, then
4825 // the string is not longer a static literal.
4827 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
4828 // If the embedded statement is a string, then we can make that
4829 // string as frozen and static literal, and not touch the static
4830 // literal status of this string.
4831 embedded->flags = (pm_node_flags_t) ((embedded->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
4833 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
4834 MUTABLE_FLAGS(node);
4836 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
4837 // If the embedded statement is an interpolated string, but that
4838 // string is marked as static literal, then we can keep our
4839 // static literal status for this string.
4840 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
4841 MUTABLE_FLAGS(node);
4844 // In all other cases, we lose the static literal flag here and
4851 case PM_EMBEDDED_VARIABLE_NODE:
4852 // Embedded variables clear static literal, which means we also
4853 // should clear the mutability flags.
4856 case PM_X_STRING_NODE:
4857 case PM_INTERPOLATED_X_STRING_NODE:
4858 case PM_SYMBOL_NODE:
4859 case PM_INTERPOLATED_SYMBOL_NODE:
4860 // These will only happen in error cases. But we want to handle it
4861 // here so that we don't fail the assertion.
4865 assert(false && "unexpected node type");
4869 pm_node_list_append(&node->parts, part);
4878static pm_interpolated_string_node_t *
4879pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
4880 pm_interpolated_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_string_node_t);
4881 pm_node_flags_t flags = PM_NODE_FLAG_STATIC_LITERAL;
4883 switch (parser->frozen_string_literal) {
4884 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
4885 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE;
4887 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
4888 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN;
4892 *node = (pm_interpolated_string_node_t) {
4893 .base = PM_NODE_INIT_TOKENS(parser, PM_INTERPOLATED_STRING_NODE, flags, opening, closing),
4894 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
4895 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
4899 if (parts != NULL) {
4901 PM_NODE_LIST_FOREACH(parts, index, part) {
4902 pm_interpolated_string_node_append(node, part);
4913pm_interpolated_string_node_closing_set(pm_interpolated_string_node_t *node, const pm_token_t *closing) {
4914 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
4915 node->base.location.end = closing->end;
4919pm_interpolated_symbol_node_append(pm_interpolated_symbol_node_t *node, pm_node_t *part) {
4920 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
4921 node->base.location.start = part->location.start;
4924 pm_interpolated_node_append(UP(node), &node->parts, part);
4925 node->base.location.end = MAX(node->base.location.end, part->location.end);
4929pm_interpolated_symbol_node_closing_loc_set(pm_interpolated_symbol_node_t *node, const pm_token_t *closing) {
4930 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
4931 node->base.location.end = closing->end;
4937static pm_interpolated_symbol_node_t *
4938pm_interpolated_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
4939 pm_interpolated_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_symbol_node_t);
4941 *node = (pm_interpolated_symbol_node_t) {
4942 .base = PM_NODE_INIT_TOKENS(parser, PM_INTERPOLATED_SYMBOL_NODE, PM_NODE_FLAG_STATIC_LITERAL, opening, closing),
4943 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
4944 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
4948 if (parts != NULL) {
4950 PM_NODE_LIST_FOREACH(parts, index, part) {
4951 pm_interpolated_symbol_node_append(node, part);
4961static pm_interpolated_x_string_node_t *
4962pm_interpolated_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4963 pm_interpolated_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_x_string_node_t);
4965 *node = (pm_interpolated_x_string_node_t) {
4966 .base = PM_NODE_INIT_TOKENS(parser, PM_INTERPOLATED_X_STRING_NODE, 0, opening, closing),
4967 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
4968 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
4976pm_interpolated_xstring_node_append(pm_interpolated_x_string_node_t *node, pm_node_t *part) {
4977 pm_interpolated_node_append(UP(node), &node->parts, part);
4978 node->base.location.end = part->location.end;
4982pm_interpolated_xstring_node_closing_set(pm_interpolated_x_string_node_t *node, const pm_token_t *closing) {
4983 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
4984 node->base.location.end = closing->end;
4990static pm_it_local_variable_read_node_t *
4991pm_it_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
4992 pm_it_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_it_local_variable_read_node_t);
4994 *node = (pm_it_local_variable_read_node_t) {
4995 .base = PM_NODE_INIT_TOKEN(parser, PM_IT_LOCAL_VARIABLE_READ_NODE, 0, name),
5004static pm_it_parameters_node_t *
5005pm_it_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5006 pm_it_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_it_parameters_node_t);
5008 *node = (pm_it_parameters_node_t) {
5009 .base = PM_NODE_INIT_TOKENS(parser, PM_IT_PARAMETERS_NODE, 0, opening, closing),
5018static pm_keyword_hash_node_t *
5019pm_keyword_hash_node_create(pm_parser_t *parser) {
5020 pm_keyword_hash_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_hash_node_t);
5022 *node = (pm_keyword_hash_node_t) {
5023 .base = PM_NODE_INIT_UNSET(parser, PM_KEYWORD_HASH_NODE, PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS),
5034pm_keyword_hash_node_elements_append(pm_keyword_hash_node_t *hash, pm_node_t *element) {
5035 // If the element being added is not an AssocNode or does not have a symbol
5036 // key, then we want to turn the SYMBOL_KEYS flag off.
5037 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE) || !PM_NODE_TYPE_P(((pm_assoc_node_t *) element)->key, PM_SYMBOL_NODE)) {
5038 pm_node_flag_unset(UP(hash), PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS);
5041 pm_node_list_append(&hash->elements, element);
5042 if (hash->base.location.start == NULL) {
5043 hash->base.location.start = element->location.start;
5045 hash->base.location.end = element->location.end;
5051static pm_required_keyword_parameter_node_t *
5052pm_required_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name) {
5053 pm_required_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_keyword_parameter_node_t);
5055 *node = (pm_required_keyword_parameter_node_t) {
5056 .base = PM_NODE_INIT_TOKEN(parser, PM_REQUIRED_KEYWORD_PARAMETER_NODE, 0, name),
5057 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5058 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5067static pm_optional_keyword_parameter_node_t *
5068pm_optional_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, pm_node_t *value) {
5069 pm_optional_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_keyword_parameter_node_t);
5071 *node = (pm_optional_keyword_parameter_node_t) {
5072 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_OPTIONAL_KEYWORD_PARAMETER_NODE, 0, name, value),
5073 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5074 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5084static pm_keyword_rest_parameter_node_t *
5085pm_keyword_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
5086 pm_keyword_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_rest_parameter_node_t);
5088 *node = (pm_keyword_rest_parameter_node_t) {
5090 (name->type == PM_TOKEN_NOT_PROVIDED)
5091 ? PM_NODE_INIT_TOKEN(parser, PM_KEYWORD_REST_PARAMETER_NODE, 0, operator)
5092 : PM_NODE_INIT_TOKENS(parser, PM_KEYWORD_REST_PARAMETER_NODE, 0, operator, name)
5094 .name = pm_parser_optional_constant_id_token(parser, name),
5095 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
5096 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5105static pm_lambda_node_t *
5106pm_lambda_node_create(
5107 pm_parser_t *parser,
5108 pm_constant_id_list_t *locals,
5109 const pm_token_t *operator,
5110 const pm_token_t *opening,
5111 const pm_token_t *closing,
5112 pm_node_t *parameters,
5115 pm_lambda_node_t *node = PM_NODE_ALLOC(parser, pm_lambda_node_t);
5117 *node = (pm_lambda_node_t) {
5118 .base = PM_NODE_INIT_TOKENS(parser, PM_LAMBDA_NODE, 0, operator, closing),
5120 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5121 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5122 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
5123 .parameters = parameters,
5133static pm_local_variable_and_write_node_t *
5134pm_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) {
5135 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));
5136 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5137 pm_local_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_and_write_node_t);
5139 *node = (pm_local_variable_and_write_node_t) {
5140 .base = PM_NODE_INIT_NODES(parser, PM_LOCAL_VARIABLE_AND_WRITE_NODE, 0, target, value),
5141 .name_loc = target->location,
5142 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5154static pm_local_variable_operator_write_node_t *
5155pm_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) {
5156 pm_local_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_operator_write_node_t);
5158 *node = (pm_local_variable_operator_write_node_t) {
5159 .base = PM_NODE_INIT_NODES(parser, PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE, 0, target, value),
5160 .name_loc = target->location,
5161 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5164 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
5174static pm_local_variable_or_write_node_t *
5175pm_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) {
5176 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));
5177 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5178 pm_local_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_or_write_node_t);
5180 *node = (pm_local_variable_or_write_node_t) {
5181 .base = PM_NODE_INIT_NODES(parser, PM_LOCAL_VARIABLE_OR_WRITE_NODE, 0, target, value),
5182 .name_loc = target->location,
5183 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5195static pm_local_variable_read_node_t *
5196pm_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) {
5197 if (!missing) pm_locals_read(&pm_parser_scope_find(parser, depth)->locals, name_id);
5199 pm_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_read_node_t);
5201 *node = (pm_local_variable_read_node_t) {
5202 .base = PM_NODE_INIT_TOKEN(parser, PM_LOCAL_VARIABLE_READ_NODE, 0, name),
5213static pm_local_variable_read_node_t *
5214pm_local_variable_read_node_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, false);
5223static pm_local_variable_read_node_t *
5224pm_local_variable_read_node_missing_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5225 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5226 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, true);
5232static pm_local_variable_write_node_t *
5233pm_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) {
5234 pm_local_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_write_node_t);
5235 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
5237 *node = (pm_local_variable_write_node_t) {
5238 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_LOCAL_VARIABLE_WRITE_NODE, flags, name_loc, value),
5242 .name_loc = *name_loc,
5243 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator)
5253pm_token_is_it(const uint8_t *start, const uint8_t *end) {
5254 return (end - start == 2) && (start[0] == 'i') && (start[1] == 't');
5262pm_token_is_numbered_parameter(const uint8_t *start, const uint8_t *end) {
5263 return (end - start == 2) && (start[0] == '_') && (start[1] != '0') && (pm_char_is_decimal_digit(start[1]));
5271pm_refute_numbered_parameter(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
5272 if (pm_token_is_numbered_parameter(start, end)) {
5273 PM_PARSER_ERR_FORMAT(parser, start, end, PM_ERR_PARAMETER_NUMBERED_RESERVED, start);
5281static pm_local_variable_target_node_t *
5282pm_local_variable_target_node_create(pm_parser_t *parser, const pm_location_t *location, pm_constant_id_t name, uint32_t depth) {
5283 pm_refute_numbered_parameter(parser, location->start, location->end);
5284 pm_local_variable_target_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_target_node_t);
5286 *node = (pm_local_variable_target_node_t) {
5287 .base = PM_NODE_INIT_TOKEN(parser, PM_LOCAL_VARIABLE_TARGET_NODE, 0, location),
5298static pm_match_predicate_node_t *
5299pm_match_predicate_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5300 pm_assert_value_expression(parser, value);
5302 pm_match_predicate_node_t *node = PM_NODE_ALLOC(parser, pm_match_predicate_node_t);
5304 *node = (pm_match_predicate_node_t) {
5305 .base = PM_NODE_INIT_NODES(parser, PM_MATCH_PREDICATE_NODE, 0, value, pattern),
5308 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5317static pm_match_required_node_t *
5318pm_match_required_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5319 pm_assert_value_expression(parser, value);
5321 pm_match_required_node_t *node = PM_NODE_ALLOC(parser, pm_match_required_node_t);
5323 *node = (pm_match_required_node_t) {
5324 .base = PM_NODE_INIT_NODES(parser, PM_MATCH_REQUIRED_NODE, 0, value, pattern),
5327 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5336static pm_match_write_node_t *
5337pm_match_write_node_create(pm_parser_t *parser, pm_call_node_t *call) {
5338 pm_match_write_node_t *node = PM_NODE_ALLOC(parser, pm_match_write_node_t);
5340 *node = (pm_match_write_node_t) {
5341 .base = PM_NODE_INIT_NODE(parser, PM_MATCH_WRITE_NODE, 0, call),
5352static pm_module_node_t *
5353pm_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) {
5354 pm_module_node_t *node = PM_NODE_ALLOC(parser, pm_module_node_t);
5356 *node = (pm_module_node_t) {
5357 .base = PM_NODE_INIT_TOKENS(parser, PM_MODULE_NODE, 0, module_keyword, end_keyword),
5358 .locals = (locals == NULL ? ((pm_constant_id_list_t) { .ids = NULL, .size = 0, .capacity = 0 }) : *locals),
5359 .module_keyword_loc = PM_LOCATION_TOKEN_VALUE(module_keyword),
5360 .constant_path = constant_path,
5362 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
5363 .name = pm_parser_constant_id_token(parser, name)
5372static pm_multi_target_node_t *
5373pm_multi_target_node_create(pm_parser_t *parser) {
5374 pm_multi_target_node_t *node = PM_NODE_ALLOC(parser, pm_multi_target_node_t);
5376 *node = (pm_multi_target_node_t) {
5377 .base = PM_NODE_INIT_UNSET(parser, PM_MULTI_TARGET_NODE, 0),
5381 .lparen_loc = { 0 },
5392pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t *node, pm_node_t *target) {
5393 if (PM_NODE_TYPE_P(target, PM_SPLAT_NODE)) {
5394 if (node->rest == NULL) {
5395 node->rest = target;
5397 pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
5398 pm_node_list_append(&node->rights, target);
5400 } else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
5401 if (node->rest == NULL) {
5402 node->rest = target;
5404 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
5405 pm_node_list_append(&node->rights, target);
5407 } else if (node->rest == NULL) {
5408 pm_node_list_append(&node->lefts, target);
5410 pm_node_list_append(&node->rights, target);
5413 if (node->base.location.start == NULL || (node->base.location.start > target->location.start)) {
5414 node->base.location.start = target->location.start;
5417 if (node->base.location.end == NULL || (node->base.location.end < target->location.end)) {
5418 node->base.location.end = target->location.end;
5426pm_multi_target_node_opening_set(pm_multi_target_node_t *node, const pm_token_t *lparen) {
5427 node->base.location.start = lparen->start;
5428 node->lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen);
5435pm_multi_target_node_closing_set(pm_multi_target_node_t *node, const pm_token_t *rparen) {
5436 node->base.location.end = rparen->end;
5437 node->rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen);
5443static pm_multi_write_node_t *
5444pm_multi_write_node_create(pm_parser_t *parser, pm_multi_target_node_t *target, const pm_token_t *operator, pm_node_t *value) {
5445 pm_multi_write_node_t *node = PM_NODE_ALLOC(parser, pm_multi_write_node_t);
5446 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
5448 *node = (pm_multi_write_node_t) {
5449 .base = PM_NODE_INIT_NODES(parser, PM_MULTI_WRITE_NODE, flags, target, value),
5450 .lefts = target->lefts,
5451 .rest = target->rest,
5452 .rights = target->rights,
5453 .lparen_loc = target->lparen_loc,
5454 .rparen_loc = target->rparen_loc,
5455 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5459 // Explicitly do not call pm_node_destroy here because we want to keep
5460 // around all of the information within the MultiWriteNode node.
5469static pm_next_node_t *
5470pm_next_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
5471 assert(keyword->type == PM_TOKEN_KEYWORD_NEXT);
5472 pm_next_node_t *node = PM_NODE_ALLOC(parser, pm_next_node_t);
5474 *node = (pm_next_node_t) {
5477 ? PM_NODE_INIT_TOKEN(parser, PM_NEXT_NODE, 0, keyword)
5478 : PM_NODE_INIT_TOKEN_NODE(parser, PM_NEXT_NODE, 0, keyword, arguments)
5480 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
5481 .arguments = arguments
5490static pm_nil_node_t *
5491pm_nil_node_create(pm_parser_t *parser, const pm_token_t *token) {
5492 assert(token->type == PM_TOKEN_KEYWORD_NIL);
5493 pm_nil_node_t *node = PM_NODE_ALLOC(parser, pm_nil_node_t);
5495 *node = (pm_nil_node_t) {
5496 .base = PM_NODE_INIT_TOKEN(parser, PM_NIL_NODE, PM_NODE_FLAG_STATIC_LITERAL, token)
5505static pm_no_keywords_parameter_node_t *
5506pm_no_keywords_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
5507 assert(operator->type == PM_TOKEN_USTAR_STAR || operator->type == PM_TOKEN_STAR_STAR);
5508 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
5509 pm_no_keywords_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_no_keywords_parameter_node_t);
5511 *node = (pm_no_keywords_parameter_node_t) {
5512 .base = PM_NODE_INIT_TOKENS(parser, PM_NO_KEYWORDS_PARAMETER_NODE, 0, operator, keyword),
5513 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5514 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
5523static pm_numbered_parameters_node_t *
5524pm_numbered_parameters_node_create(pm_parser_t *parser, const pm_location_t *location, uint8_t maximum) {
5525 pm_numbered_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_parameters_node_t);
5527 *node = (pm_numbered_parameters_node_t) {
5528 .base = PM_NODE_INIT_TOKEN(parser, PM_NUMBERED_PARAMETERS_NODE, 0, location),
5539#define NTH_REF_MAX ((uint32_t) (INT_MAX >> 1))
5548pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *token) {
5549 const uint8_t *start = token->start + 1;
5550 const uint8_t *end = token->end;
5552 ptrdiff_t diff = end - start;
5554#if PTRDIFF_MAX > SIZE_MAX
5555 assert(diff < (ptrdiff_t) SIZE_MAX);
5557 size_t length = (size_t) diff;
5559 char *digits = xcalloc(length + 1, sizeof(char));
5560 memcpy(digits, start, length);
5561 digits[length] = '\0';
5565 unsigned long value = strtoul(digits, &endptr, 10);
5567 if ((digits == endptr) || (*endptr != '\0')) {
5568 pm_parser_err(parser, start, end, PM_ERR_INVALID_NUMBER_DECIMAL);
5574 if ((errno == ERANGE) || (value > NTH_REF_MAX)) {
5575 PM_PARSER_WARN_FORMAT(parser, start, end, PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start);
5579 return (uint32_t) value;
5587static pm_numbered_reference_read_node_t *
5588pm_numbered_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5589 assert(name->type == PM_TOKEN_NUMBERED_REFERENCE);
5590 pm_numbered_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_reference_read_node_t);
5592 *node = (pm_numbered_reference_read_node_t) {
5593 .base = PM_NODE_INIT_TOKEN(parser, PM_NUMBERED_REFERENCE_READ_NODE, 0, name),
5594 .number = pm_numbered_reference_read_node_number(parser, name)
5603static pm_optional_parameter_node_t *
5604pm_optional_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator, pm_node_t *value) {
5605 pm_optional_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_parameter_node_t);
5607 *node = (pm_optional_parameter_node_t) {
5608 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_OPTIONAL_PARAMETER_NODE, 0, name, value),
5609 .name = pm_parser_constant_id_token(parser, name),
5610 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5611 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5621static pm_or_node_t *
5622pm_or_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
5623 pm_assert_value_expression(parser, left);
5625 pm_or_node_t *node = PM_NODE_ALLOC(parser, pm_or_node_t);
5627 *node = (pm_or_node_t) {
5628 .base = PM_NODE_INIT_NODES(parser, PM_OR_NODE, 0, left, right),
5631 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5640static pm_parameters_node_t *
5641pm_parameters_node_create(pm_parser_t *parser) {
5642 pm_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_parameters_node_t);
5644 *node = (pm_parameters_node_t) {
5645 .base = PM_NODE_INIT_UNSET(parser, PM_PARAMETERS_NODE, 0),
5647 .keyword_rest = NULL,
5662pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param) {
5663 if (params->base.location.start == NULL) {
5664 params->base.location.start = param->location.start;
5666 params->base.location.start = params->base.location.start < param->location.start ? params->base.location.start : param->location.start;
5669 if (params->base.location.end == NULL) {
5670 params->base.location.end = param->location.end;
5672 params->base.location.end = params->base.location.end > param->location.end ? params->base.location.end : param->location.end;
5680pm_parameters_node_requireds_append(pm_parameters_node_t *params, pm_node_t *param) {
5681 pm_parameters_node_location_set(params, param);
5682 pm_node_list_append(¶ms->requireds, param);
5689pm_parameters_node_optionals_append(pm_parameters_node_t *params, pm_optional_parameter_node_t *param) {
5690 pm_parameters_node_location_set(params, UP(param));
5691 pm_node_list_append(¶ms->optionals, UP(param));
5698pm_parameters_node_posts_append(pm_parameters_node_t *params, pm_node_t *param) {
5699 pm_parameters_node_location_set(params, param);
5700 pm_node_list_append(¶ms->posts, param);
5707pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
5708 pm_parameters_node_location_set(params, param);
5709 params->rest = param;
5716pm_parameters_node_keywords_append(pm_parameters_node_t *params, pm_node_t *param) {
5717 pm_parameters_node_location_set(params, param);
5718 pm_node_list_append(¶ms->keywords, param);
5725pm_parameters_node_keyword_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
5726 assert(params->keyword_rest == NULL);
5727 pm_parameters_node_location_set(params, param);
5728 params->keyword_rest = param;
5735pm_parameters_node_block_set(pm_parameters_node_t *params, pm_block_parameter_node_t *param) {
5736 assert(params->block == NULL);
5737 pm_parameters_node_location_set(params, UP(param));
5738 params->block = param;
5744static pm_program_node_t *
5745pm_program_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, pm_statements_node_t *statements) {
5746 pm_program_node_t *node = PM_NODE_ALLOC(parser, pm_program_node_t);
5748 *node = (pm_program_node_t) {
5749 .base = PM_NODE_INIT_NODE(parser, PM_PROGRAM_NODE, 0, statements),
5751 .statements = statements
5760static pm_parentheses_node_t *
5761pm_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) {
5762 pm_parentheses_node_t *node = PM_NODE_ALLOC(parser, pm_parentheses_node_t);
5764 *node = (pm_parentheses_node_t) {
5765 .base = PM_NODE_INIT_TOKENS(parser, PM_PARENTHESES_NODE, flags, opening, closing),
5767 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5768 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
5777static pm_pinned_expression_node_t *
5778pm_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) {
5779 pm_pinned_expression_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_expression_node_t);
5781 *node = (pm_pinned_expression_node_t) {
5782 .base = PM_NODE_INIT_TOKENS(parser, PM_PINNED_EXPRESSION_NODE, 0, operator, rparen),
5783 .expression = expression,
5784 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5785 .lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen),
5786 .rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen)
5795static pm_pinned_variable_node_t *
5796pm_pinned_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
5797 pm_pinned_variable_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_variable_node_t);
5799 *node = (pm_pinned_variable_node_t) {
5800 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_PINNED_VARIABLE_NODE, 0, operator, variable),
5801 .variable = variable,
5802 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5811static pm_post_execution_node_t *
5812pm_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) {
5813 pm_post_execution_node_t *node = PM_NODE_ALLOC(parser, pm_post_execution_node_t);
5815 *node = (pm_post_execution_node_t) {
5816 .base = PM_NODE_INIT_TOKENS(parser, PM_POST_EXECUTION_NODE, 0, keyword, closing),
5817 .statements = statements,
5818 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
5819 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5820 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
5829static pm_pre_execution_node_t *
5830pm_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) {
5831 pm_pre_execution_node_t *node = PM_NODE_ALLOC(parser, pm_pre_execution_node_t);
5833 *node = (pm_pre_execution_node_t) {
5834 .base = PM_NODE_INIT_TOKENS(parser, PM_PRE_EXECUTION_NODE, 0, keyword, closing),
5835 .statements = statements,
5836 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
5837 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5838 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
5847static pm_range_node_t *
5848pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
5849 pm_assert_value_expression(parser, left);
5850 pm_assert_value_expression(parser, right);
5852 pm_range_node_t *node = PM_NODE_ALLOC(parser, pm_range_node_t);
5853 pm_node_flags_t flags = 0;
5855 // Indicate that this node is an exclusive range if the operator is `...`.
5856 if (operator->type == PM_TOKEN_DOT_DOT_DOT || operator->type == PM_TOKEN_UDOT_DOT_DOT) {
5857 flags |= PM_RANGE_FLAGS_EXCLUDE_END;
5860 // Indicate that this node is a static literal (i.e., can be compiled with
5861 // a putobject in CRuby) if the left and right are implicit nil, explicit
5862 // nil, or integers.
5864 (left == NULL || PM_NODE_TYPE_P(left, PM_NIL_NODE) || PM_NODE_TYPE_P(left, PM_INTEGER_NODE)) &&
5865 (right == NULL || PM_NODE_TYPE_P(right, PM_NIL_NODE) || PM_NODE_TYPE_P(right, PM_INTEGER_NODE))
5867 flags |= PM_NODE_FLAG_STATIC_LITERAL;
5870 *node = (pm_range_node_t) {
5871 .base = PM_NODE_INIT(parser, PM_RANGE_NODE, flags, (left == NULL ? operator->start : left->location.start), (right == NULL ? operator->end : right->location.end)),
5874 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5883static pm_redo_node_t *
5884pm_redo_node_create(pm_parser_t *parser, const pm_token_t *token) {
5885 assert(token->type == PM_TOKEN_KEYWORD_REDO);
5886 pm_redo_node_t *node = PM_NODE_ALLOC(parser, pm_redo_node_t);
5888 *node = (pm_redo_node_t) {
5889 .base = PM_NODE_INIT_TOKEN(parser, PM_REDO_NODE, 0, token)
5899static pm_regular_expression_node_t *
5900pm_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) {
5901 pm_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_regular_expression_node_t);
5902 pm_node_flags_t flags = pm_regular_expression_flags_create(parser, closing) | PM_NODE_FLAG_STATIC_LITERAL;
5904 *node = (pm_regular_expression_node_t) {
5905 .base = PM_NODE_INIT_TOKENS(parser, PM_REGULAR_EXPRESSION_NODE, flags, opening, closing),
5906 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5907 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
5908 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
5909 .unescaped = *unescaped
5918static inline pm_regular_expression_node_t *
5919pm_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
5920 return pm_regular_expression_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
5926static pm_required_parameter_node_t *
5927pm_required_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
5928 pm_required_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_parameter_node_t);
5930 *node = (pm_required_parameter_node_t) {
5931 .base = PM_NODE_INIT_TOKEN(parser, PM_REQUIRED_PARAMETER_NODE, 0, token),
5932 .name = pm_parser_constant_id_token(parser, token)
5941static pm_rescue_modifier_node_t *
5942pm_rescue_modifier_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *keyword, pm_node_t *rescue_expression) {
5943 pm_rescue_modifier_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_modifier_node_t);
5945 *node = (pm_rescue_modifier_node_t) {
5946 .base = PM_NODE_INIT_NODES(parser, PM_RESCUE_MODIFIER_NODE, 0, expression, rescue_expression),
5947 .expression = expression,
5948 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
5949 .rescue_expression = rescue_expression
5958static pm_rescue_node_t *
5959pm_rescue_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
5960 pm_rescue_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_node_t);
5962 *node = (pm_rescue_node_t) {
5963 .base = PM_NODE_INIT_TOKEN(parser, PM_RESCUE_NODE, 0, keyword),
5964 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
5965 .operator_loc = { 0 },
5966 .then_keyword_loc = { 0 },
5977pm_rescue_node_operator_set(pm_rescue_node_t *node, const pm_token_t *operator) {
5978 node->operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
5985pm_rescue_node_reference_set(pm_rescue_node_t *node, pm_node_t *reference) {
5986 node->reference = reference;
5987 node->base.location.end = reference->location.end;
5994pm_rescue_node_statements_set(pm_rescue_node_t *node, pm_statements_node_t *statements) {
5995 node->statements = statements;
5996 if (pm_statements_node_body_length(statements) > 0) {
5997 node->base.location.end = statements->base.location.end;
6005pm_rescue_node_subsequent_set(pm_rescue_node_t *node, pm_rescue_node_t *subsequent) {
6006 node->subsequent = subsequent;
6007 node->base.location.end = subsequent->base.location.end;
6014pm_rescue_node_exceptions_append(pm_rescue_node_t *node, pm_node_t *exception) {
6015 pm_node_list_append(&node->exceptions, exception);
6016 node->base.location.end = exception->location.end;
6022static pm_rest_parameter_node_t *
6023pm_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
6024 pm_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_rest_parameter_node_t);
6026 *node = (pm_rest_parameter_node_t) {
6028 (name->type == PM_TOKEN_NOT_PROVIDED)
6029 ? PM_NODE_INIT_TOKEN(parser, PM_REST_PARAMETER_NODE, 0, operator)
6030 : PM_NODE_INIT_TOKENS(parser, PM_REST_PARAMETER_NODE, 0, operator, name)
6032 .name = pm_parser_optional_constant_id_token(parser, name),
6033 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
6034 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6043static pm_retry_node_t *
6044pm_retry_node_create(pm_parser_t *parser, const pm_token_t *token) {
6045 assert(token->type == PM_TOKEN_KEYWORD_RETRY);
6046 pm_retry_node_t *node = PM_NODE_ALLOC(parser, pm_retry_node_t);
6048 *node = (pm_retry_node_t) {
6049 .base = PM_NODE_INIT_TOKEN(parser, PM_RETRY_NODE, 0, token)
6058static pm_return_node_t *
6059pm_return_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6060 pm_return_node_t *node = PM_NODE_ALLOC(parser, pm_return_node_t);
6062 *node = (pm_return_node_t) {
6065 ? PM_NODE_INIT_TOKEN(parser, PM_RETURN_NODE, 0, keyword)
6066 : PM_NODE_INIT_TOKEN_NODE(parser, PM_RETURN_NODE, 0, keyword, arguments)
6068 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6069 .arguments = arguments
6078static pm_self_node_t *
6079pm_self_node_create(pm_parser_t *parser, const pm_token_t *token) {
6080 assert(token->type == PM_TOKEN_KEYWORD_SELF);
6081 pm_self_node_t *node = PM_NODE_ALLOC(parser, pm_self_node_t);
6083 *node = (pm_self_node_t) {
6084 .base = PM_NODE_INIT_TOKEN(parser, PM_SELF_NODE, 0, token)
6093static pm_shareable_constant_node_t *
6094pm_shareable_constant_node_create(pm_parser_t *parser, pm_node_t *write, pm_shareable_constant_value_t value) {
6095 pm_shareable_constant_node_t *node = PM_NODE_ALLOC(parser, pm_shareable_constant_node_t);
6097 *node = (pm_shareable_constant_node_t) {
6098 .base = PM_NODE_INIT_NODE(parser, PM_SHAREABLE_CONSTANT_NODE, (pm_node_flags_t) value, write),
6108static pm_singleton_class_node_t *
6109pm_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) {
6110 pm_singleton_class_node_t *node = PM_NODE_ALLOC(parser, pm_singleton_class_node_t);
6112 *node = (pm_singleton_class_node_t) {
6113 .base = PM_NODE_INIT_TOKENS(parser, PM_SINGLETON_CLASS_NODE, 0, class_keyword, end_keyword),
6115 .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
6116 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6117 .expression = expression,
6119 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
6128static pm_source_encoding_node_t *
6129pm_source_encoding_node_create(pm_parser_t *parser, const pm_token_t *token) {
6130 assert(token->type == PM_TOKEN_KEYWORD___ENCODING__);
6131 pm_source_encoding_node_t *node = PM_NODE_ALLOC(parser, pm_source_encoding_node_t);
6133 *node = (pm_source_encoding_node_t) {
6134 .base = PM_NODE_INIT_TOKEN(parser, PM_SOURCE_ENCODING_NODE, PM_NODE_FLAG_STATIC_LITERAL, token)
6143static pm_source_file_node_t*
6144pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword) {
6145 pm_source_file_node_t *node = PM_NODE_ALLOC(parser, pm_source_file_node_t);
6146 assert(file_keyword->type == PM_TOKEN_KEYWORD___FILE__);
6148 pm_node_flags_t flags = 0;
6150 switch (parser->frozen_string_literal) {
6151 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6152 flags |= PM_STRING_FLAGS_MUTABLE;
6154 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6155 flags |= PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6159 *node = (pm_source_file_node_t) {
6160 .base = PM_NODE_INIT_TOKEN(parser, PM_SOURCE_FILE_NODE, flags, file_keyword),
6161 .filepath = parser->filepath
6170static pm_source_line_node_t *
6171pm_source_line_node_create(pm_parser_t *parser, const pm_token_t *token) {
6172 assert(token->type == PM_TOKEN_KEYWORD___LINE__);
6173 pm_source_line_node_t *node = PM_NODE_ALLOC(parser, pm_source_line_node_t);
6175 *node = (pm_source_line_node_t) {
6176 .base = PM_NODE_INIT_TOKEN(parser, PM_SOURCE_LINE_NODE, PM_NODE_FLAG_STATIC_LITERAL, token)
6185static pm_splat_node_t *
6186pm_splat_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
6187 pm_splat_node_t *node = PM_NODE_ALLOC(parser, pm_splat_node_t);
6189 *node = (pm_splat_node_t) {
6191 (expression == NULL)
6192 ? PM_NODE_INIT_TOKEN(parser, PM_SPLAT_NODE, 0, operator)
6193 : PM_NODE_INIT_TOKEN_NODE(parser, PM_SPLAT_NODE, 0, operator, expression)
6195 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6196 .expression = expression
6205static pm_statements_node_t *
6206pm_statements_node_create(pm_parser_t *parser) {
6207 pm_statements_node_t *node = PM_NODE_ALLOC(parser, pm_statements_node_t);
6209 *node = (pm_statements_node_t) {
6210 .base = PM_NODE_INIT_BASE(parser, PM_STATEMENTS_NODE, 0),
6221pm_statements_node_body_length(pm_statements_node_t *node) {
6222 return node && node->body.size;
6229pm_statements_node_location_set(pm_statements_node_t *node, const uint8_t *start, const uint8_t *end) {
6230 node->base.location = (pm_location_t) { .start = start, .end = end };
6238pm_statements_node_body_update(pm_statements_node_t *node, pm_node_t *statement) {
6239 if (pm_statements_node_body_length(node) == 0 || statement->location.start < node->base.location.start) {
6240 node->base.location.start = statement->location.start;
6243 if (statement->location.end > node->base.location.end) {
6244 node->base.location.end = statement->location.end;
6252pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline) {
6253 pm_statements_node_body_update(node, statement);
6255 if (node->body.size > 0) {
6256 const pm_node_t *previous = node->body.nodes[node->body.size - 1];
6258 switch (PM_NODE_TYPE(previous)) {
6263 case PM_RETURN_NODE:
6264 pm_parser_warn_node(parser, statement, PM_WARN_UNREACHABLE_STATEMENT);
6271 pm_node_list_append(&node->body, statement);
6272 if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
6279pm_statements_node_body_prepend(pm_statements_node_t *node, pm_node_t *statement) {
6280 pm_statements_node_body_update(node, statement);
6281 pm_node_list_prepend(&node->body, statement);
6282 pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
6288static inline pm_string_node_t *
6289pm_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) {
6290 pm_string_node_t *node = PM_NODE_ALLOC(parser, pm_string_node_t);
6291 pm_node_flags_t flags = 0;
6293 switch (parser->frozen_string_literal) {
6294 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6295 flags = PM_STRING_FLAGS_MUTABLE;
6297 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6298 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6302 const uint8_t *start = (opening->type == PM_TOKEN_NOT_PROVIDED ? content->start : opening->start);
6303 const uint8_t *end = (closing->type == PM_TOKEN_NOT_PROVIDED ? content->end : closing->end);
6305 *node = (pm_string_node_t) {
6306 .base = PM_NODE_INIT(parser, PM_STRING_NODE, flags, start, end),
6307 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
6308 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
6309 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
6310 .unescaped = *string
6319static pm_string_node_t *
6320pm_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6321 return pm_string_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6328static pm_string_node_t *
6329pm_string_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6330 pm_string_node_t *node = pm_string_node_create_unescaped(parser, opening, content, closing, &parser->current_string);
6331 parser->current_string = PM_STRING_EMPTY;
6338static pm_super_node_t *
6339pm_super_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_t *arguments) {
6340 assert(keyword->type == PM_TOKEN_KEYWORD_SUPER);
6341 pm_super_node_t *node = PM_NODE_ALLOC(parser, pm_super_node_t);
6343 const uint8_t *end = pm_arguments_end(arguments);
6345 assert(false && "unreachable");
6348 *node = (pm_super_node_t) {
6349 .base = PM_NODE_INIT(parser, PM_SUPER_NODE, 0, keyword->start, end),
6350 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6351 .lparen_loc = arguments->opening_loc,
6352 .arguments = arguments->arguments,
6353 .rparen_loc = arguments->closing_loc,
6354 .block = arguments->block
6365pm_ascii_only_p(const pm_string_t *contents) {
6366 const size_t length = pm_string_length(contents);
6367 const uint8_t *source = pm_string_source(contents);
6369 for (size_t index = 0; index < length; index++) {
6370 if (source[index] & 0x80) return false;
6380parse_symbol_encoding_validate_utf8(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
6381 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
6382 size_t width = pm_encoding_utf_8_char_width(cursor, end - cursor);
6385 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
6398parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
6399 const pm_encoding_t *encoding = parser->encoding;
6401 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
6402 size_t width = encoding->char_width(cursor, end - cursor);
6405 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
6422static inline pm_node_flags_t
6423parse_symbol_encoding(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents, bool validate) {
6424 if (parser->explicit_encoding != NULL) {
6425 // A Symbol may optionally have its encoding explicitly set. This will
6426 // happen if an escape sequence results in a non-ASCII code point.
6427 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
6428 if (validate) parse_symbol_encoding_validate_utf8(parser, location, contents);
6429 return PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING;
6430 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
6431 return PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING;
6432 } else if (validate) {
6433 parse_symbol_encoding_validate_other(parser, location, contents);
6435 } else if (pm_ascii_only_p(contents)) {
6436 // Ruby stipulates that all source files must use an ASCII-compatible
6437 // encoding. Thus, all symbols appearing in source are eligible for
6438 // "downgrading" to US-ASCII.
6439 return PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING;
6440 } else if (validate) {
6441 parse_symbol_encoding_validate_other(parser, location, contents);
6447static pm_node_flags_t
6448parse_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) {
6449 assert ((modifier == 'n' && modifier_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) ||
6450 (modifier == 'u' && modifier_encoding == PM_ENCODING_UTF_8_ENTRY) ||
6451 (modifier == 'e' && modifier_encoding == PM_ENCODING_EUC_JP_ENTRY) ||
6452 (modifier == 's' && modifier_encoding == PM_ENCODING_WINDOWS_31J_ENTRY));
6454 // There's special validation logic used if a string does not contain any character escape sequences.
6455 if (parser->explicit_encoding == NULL) {
6456 // If an ASCII-only string without character escapes is used with an encoding modifier, then resulting Regexp
6457 // has the modifier encoding, unless the ASCII-8BIT modifier is used, in which case the Regexp "downgrades" to
6458 // the US-ASCII encoding.
6460 return modifier == 'n' ? PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING : flags;
6463 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
6465 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
6467 } else if (parser->encoding != modifier_encoding) {
6468 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_ENCODING_OPTION_MISMATCH, modifier, parser->encoding->name);
6470 if (modifier == 'n' && !ascii_only) {
6471 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));
6478 // 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.
6479 bool mixed_encoding = false;
6481 if (mixed_encoding) {
6482 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
6483 } else if (modifier != 'n' && parser->explicit_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) {
6484 // 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.
6485 bool valid_string_in_modifier_encoding = true;
6487 if (!valid_string_in_modifier_encoding) {
6488 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
6490 } else if (modifier != 'u' && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
6491 // 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.
6492 if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
6493 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));
6497 // We've determined the encoding would naturally be EUC-JP and there is no need to force the encoding to anything else.
6507static pm_node_flags_t
6508parse_and_validate_regular_expression_encoding(pm_parser_t *parser, const pm_string_t *source, bool ascii_only, pm_node_flags_t flags) {
6509 // 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.
6510 bool valid_unicode_range = true;
6511 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY && !valid_unicode_range) {
6512 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));
6516 // US-ASCII strings do not admit multi-byte character literals. However, character escape sequences corresponding
6517 // to multi-byte characters are allowed.
6518 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY && parser->explicit_encoding == NULL && !ascii_only) {
6519 // CRuby will continue processing even though a SyntaxError has already been detected. It may result in the
6520 // following error message appearing twice. We do the same for compatibility.
6521 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
6532 if (flags & PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT) {
6533 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'n', PM_ENCODING_ASCII_8BIT_ENTRY);
6536 if (flags & PM_REGULAR_EXPRESSION_FLAGS_UTF_8) {
6537 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'u', PM_ENCODING_UTF_8_ENTRY);
6540 if (flags & PM_REGULAR_EXPRESSION_FLAGS_EUC_JP) {
6541 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'e', PM_ENCODING_EUC_JP_ENTRY);
6544 if (flags & PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J) {
6545 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 's', PM_ENCODING_WINDOWS_31J_ENTRY);
6548 // At this point no encoding modifiers will be present on the regular expression as they would have already
6549 // been processed. Ruby stipulates that all source files must use an ASCII-compatible encoding. Thus, all
6550 // regular expressions without an encoding modifier appearing in source are eligible for "downgrading" to US-ASCII.
6552 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING;
6555 // A Regexp may optionally have its encoding explicitly set via a character escape sequence in the source string
6556 // or by specifying a modifier.
6558 // NB: an explicitly set encoding is ignored by Ruby if the Regexp consists of only US ASCII code points.
6559 if (parser->explicit_encoding != NULL) {
6560 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
6561 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING;
6562 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
6563 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING;
6574static pm_symbol_node_t *
6575pm_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) {
6576 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
6578 const uint8_t *start = (opening->type == PM_TOKEN_NOT_PROVIDED ? value->start : opening->start);
6579 const uint8_t *end = (closing->type == PM_TOKEN_NOT_PROVIDED ? value->end : closing->end);
6581 *node = (pm_symbol_node_t) {
6582 .base = PM_NODE_INIT(parser, PM_SYMBOL_NODE, PM_NODE_FLAG_STATIC_LITERAL | flags, start, end),
6583 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
6584 .value_loc = PM_LOCATION_TOKEN_VALUE(value),
6585 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
6586 .unescaped = *unescaped
6595static inline pm_symbol_node_t *
6596pm_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
6597 return pm_symbol_node_create_unescaped(parser, opening, value, closing, &PM_STRING_EMPTY, 0);
6603static pm_symbol_node_t *
6604pm_symbol_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
6605 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));
6606 parser->current_string = PM_STRING_EMPTY;
6613static pm_symbol_node_t *
6614pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
6615 pm_symbol_node_t *node;
6617 switch (token->type) {
6618 case PM_TOKEN_LABEL: {
6619 pm_token_t opening = not_provided(parser);
6620 pm_token_t closing = { .type = PM_TOKEN_LABEL_END, .start = token->end - 1, .end = token->end };
6622 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end - 1 };
6623 node = pm_symbol_node_create(parser, &opening, &label, &closing);
6625 assert((label.end - label.start) >= 0);
6626 pm_string_shared_init(&node->unescaped, label.start, label.end);
6627 pm_node_flag_set(UP(node), parse_symbol_encoding(parser, &label, &node->unescaped, false));
6631 case PM_TOKEN_MISSING: {
6632 pm_token_t opening = not_provided(parser);
6633 pm_token_t closing = not_provided(parser);
6635 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end };
6636 node = pm_symbol_node_create(parser, &opening, &label, &closing);
6640 assert(false && "unreachable");
6651static pm_symbol_node_t *
6652pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
6653 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
6655 *node = (pm_symbol_node_t) {
6656 .base = PM_NODE_INIT_BASE(parser, PM_SYMBOL_NODE, PM_NODE_FLAG_STATIC_LITERAL | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING),
6657 .value_loc = PM_LOCATION_NULL_VALUE(parser),
6661 pm_string_constant_init(&node->unescaped, content, strlen(content));
6669pm_symbol_node_label_p(pm_node_t *node) {
6670 const uint8_t *end = NULL;
6672 switch (PM_NODE_TYPE(node)) {
6673 case PM_SYMBOL_NODE:
6674 end = ((pm_symbol_node_t *) node)->closing_loc.end;
6676 case PM_INTERPOLATED_SYMBOL_NODE:
6677 end = ((pm_interpolated_symbol_node_t *) node)->closing_loc.end;
6683 return (end != NULL) && (end[-1] == ':');
6689static pm_symbol_node_t *
6690pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const pm_token_t *opening, const pm_token_t *closing) {
6691 pm_symbol_node_t *new_node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
6693 *new_node = (pm_symbol_node_t) {
6694 .base = PM_NODE_INIT_TOKENS(parser, PM_SYMBOL_NODE, PM_NODE_FLAG_STATIC_LITERAL, opening, closing),
6695 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
6696 .value_loc = node->content_loc,
6697 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
6698 .unescaped = node->unescaped
6701 pm_token_t content = { .type = PM_TOKEN_IDENTIFIER, .start = node->content_loc.start, .end = node->content_loc.end };
6702 pm_node_flag_set(UP(new_node), parse_symbol_encoding(parser, &content, &node->unescaped, true));
6704 // We are explicitly _not_ using pm_node_destroy here because we don't want
6705 // to trash the unescaped string. We could instead copy the string if we
6706 // know that it is owned, but we're taking the fast path for now.
6715static pm_string_node_t *
6716pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
6717 pm_string_node_t *new_node = PM_NODE_ALLOC(parser, pm_string_node_t);
6718 pm_node_flags_t flags = 0;
6720 switch (parser->frozen_string_literal) {
6721 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6722 flags = PM_STRING_FLAGS_MUTABLE;
6724 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6725 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6729 *new_node = (pm_string_node_t) {
6730 .base = PM_NODE_INIT_NODE(parser, PM_STRING_NODE, flags, node),
6731 .opening_loc = node->opening_loc,
6732 .content_loc = node->value_loc,
6733 .closing_loc = node->closing_loc,
6734 .unescaped = node->unescaped
6737 // We are explicitly _not_ using pm_node_destroy here because we don't want
6738 // to trash the unescaped string. We could instead copy the string if we
6739 // know that it is owned, but we're taking the fast path for now.
6748static pm_true_node_t *
6749pm_true_node_create(pm_parser_t *parser, const pm_token_t *token) {
6750 assert(token->type == PM_TOKEN_KEYWORD_TRUE);
6751 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
6753 *node = (pm_true_node_t) {
6754 .base = PM_NODE_INIT_TOKEN(parser, PM_TRUE_NODE, PM_NODE_FLAG_STATIC_LITERAL, token)
6763static pm_true_node_t *
6764pm_true_node_synthesized_create(pm_parser_t *parser) {
6765 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
6767 *node = (pm_true_node_t) {
6768 .base = PM_NODE_INIT_BASE(parser, PM_TRUE_NODE, PM_NODE_FLAG_STATIC_LITERAL)
6777static pm_undef_node_t *
6778pm_undef_node_create(pm_parser_t *parser, const pm_token_t *token) {
6779 assert(token->type == PM_TOKEN_KEYWORD_UNDEF);
6780 pm_undef_node_t *node = PM_NODE_ALLOC(parser, pm_undef_node_t);
6782 *node = (pm_undef_node_t) {
6783 .base = PM_NODE_INIT_TOKEN(parser, PM_UNDEF_NODE, 0, token),
6784 .keyword_loc = PM_LOCATION_TOKEN_VALUE(token),
6795pm_undef_node_append(pm_undef_node_t *node, pm_node_t *name) {
6796 node->base.location.end = name->location.end;
6797 pm_node_list_append(&node->names, name);
6803static pm_unless_node_t *
6804pm_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) {
6805 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6807 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
6808 pm_node_t *end = statements == NULL ? predicate : UP(statements);
6810 *node = (pm_unless_node_t) {
6811 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_UNLESS_NODE, PM_NODE_FLAG_NEWLINE, keyword, end),
6812 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6813 .predicate = predicate,
6814 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
6815 .statements = statements,
6816 .else_clause = NULL,
6817 .end_keyword_loc = { 0 }
6826static pm_unless_node_t *
6827pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *unless_keyword, pm_node_t *predicate) {
6828 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6829 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
6831 pm_statements_node_t *statements = pm_statements_node_create(parser);
6832 pm_statements_node_body_append(parser, statements, statement, true);
6834 *node = (pm_unless_node_t) {
6835 .base = PM_NODE_INIT_NODES(parser, PM_UNLESS_NODE, PM_NODE_FLAG_NEWLINE, statement, predicate),
6836 .keyword_loc = PM_LOCATION_TOKEN_VALUE(unless_keyword),
6837 .predicate = predicate,
6838 .then_keyword_loc = { 0 },
6839 .statements = statements,
6840 .else_clause = NULL,
6841 .end_keyword_loc = { 0 }
6848pm_unless_node_end_keyword_loc_set(pm_unless_node_t *node, const pm_token_t *end_keyword) {
6849 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
6850 node->base.location.end = end_keyword->end;
6859pm_loop_modifier_block_exits(pm_parser_t *parser, pm_statements_node_t *statements) {
6860 assert(parser->current_block_exits != NULL);
6862 // All of the block exits that we want to remove should be within the
6863 // statements, and since we are modifying the statements, we shouldn't have
6864 // to check the end location.
6865 const uint8_t *start = statements->base.location.start;
6867 for (size_t index = parser->current_block_exits->size; index > 0; index--) {
6868 pm_node_t *block_exit = parser->current_block_exits->nodes[index - 1];
6869 if (block_exit->location.start < start) break;
6871 // Implicitly remove from the list by lowering the size.
6872 parser->current_block_exits->size--;
6879static pm_until_node_t *
6880pm_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) {
6881 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
6882 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6884 *node = (pm_until_node_t) {
6885 .base = PM_NODE_INIT_TOKENS(parser, PM_UNTIL_NODE, flags, keyword, closing),
6886 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6887 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
6888 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
6889 .predicate = predicate,
6890 .statements = statements
6899static pm_until_node_t *
6900pm_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) {
6901 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
6902 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6903 pm_loop_modifier_block_exits(parser, statements);
6905 *node = (pm_until_node_t) {
6906 .base = PM_NODE_INIT_NODES(parser, PM_UNTIL_NODE, flags, statements, predicate),
6907 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6908 .do_keyword_loc = { 0 },
6909 .closing_loc = { 0 },
6910 .predicate = predicate,
6911 .statements = statements
6920static pm_when_node_t *
6921pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
6922 pm_when_node_t *node = PM_NODE_ALLOC(parser, pm_when_node_t);
6924 *node = (pm_when_node_t) {
6925 .base = PM_NODE_INIT_TOKEN(parser, PM_WHEN_NODE, 0, keyword),
6926 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6928 .then_keyword_loc = { 0 },
6939pm_when_node_conditions_append(pm_when_node_t *node, pm_node_t *condition) {
6940 node->base.location.end = condition->location.end;
6941 pm_node_list_append(&node->conditions, condition);
6948pm_when_node_then_keyword_loc_set(pm_when_node_t *node, const pm_token_t *then_keyword) {
6949 node->base.location.end = then_keyword->end;
6950 node->then_keyword_loc = PM_LOCATION_TOKEN_VALUE(then_keyword);
6957pm_when_node_statements_set(pm_when_node_t *node, pm_statements_node_t *statements) {
6958 if (statements->base.location.end > node->base.location.end) {
6959 node->base.location.end = statements->base.location.end;
6962 node->statements = statements;
6968static pm_while_node_t *
6969pm_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) {
6970 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
6971 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6973 *node = (pm_while_node_t) {
6974 .base = PM_NODE_INIT_TOKENS(parser, PM_WHILE_NODE, flags, keyword, closing),
6975 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6976 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
6977 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
6978 .predicate = predicate,
6979 .statements = statements
6988static pm_while_node_t *
6989pm_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) {
6990 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
6991 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6992 pm_loop_modifier_block_exits(parser, statements);
6994 *node = (pm_while_node_t) {
6995 .base = PM_NODE_INIT_NODES(parser, PM_WHILE_NODE, flags, statements, predicate),
6996 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6997 .do_keyword_loc = { 0 },
6998 .closing_loc = { 0 },
6999 .predicate = predicate,
7000 .statements = statements
7009static pm_while_node_t *
7010pm_while_node_synthesized_create(pm_parser_t *parser, pm_node_t *predicate, pm_statements_node_t *statements) {
7011 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7013 *node = (pm_while_node_t) {
7014 .base = PM_NODE_INIT_BASE(parser, PM_WHILE_NODE, 0),
7015 .keyword_loc = PM_LOCATION_NULL_VALUE(parser),
7016 .do_keyword_loc = PM_LOCATION_NULL_VALUE(parser),
7017 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
7018 .predicate = predicate,
7019 .statements = statements
7029static pm_x_string_node_t *
7030pm_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) {
7031 pm_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_x_string_node_t);
7033 *node = (pm_x_string_node_t) {
7034 .base = PM_NODE_INIT_TOKENS(parser, PM_X_STRING_NODE, PM_STRING_FLAGS_FROZEN, opening, closing),
7035 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
7036 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
7037 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
7038 .unescaped = *unescaped
7047static inline pm_x_string_node_t *
7048pm_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7049 return pm_xstring_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7055static pm_yield_node_t *
7056pm_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) {
7057 pm_yield_node_t *node = PM_NODE_ALLOC(parser, pm_yield_node_t);
7060 if (rparen_loc->start != NULL) {
7061 end = rparen_loc->end;
7062 } else if (arguments != NULL) {
7063 end = arguments->base.location.end;
7064 } else if (lparen_loc->start != NULL) {
7065 end = lparen_loc->end;
7070 *node = (pm_yield_node_t) {
7071 .base = PM_NODE_INIT(parser, PM_YIELD_NODE, 0, keyword->start, end),
7072 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7073 .lparen_loc = *lparen_loc,
7074 .arguments = arguments,
7075 .rparen_loc = *rparen_loc
7086pm_parser_local_depth_constant_id(pm_parser_t *parser, pm_constant_id_t constant_id) {
7087 pm_scope_t *scope = parser->current_scope;
7090 while (scope != NULL) {
7091 if (pm_locals_find(&scope->locals, constant_id) != UINT32_MAX) return depth;
7092 if (scope->closed) break;
7094 scope = scope->previous;
7107pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
7108 return pm_parser_local_depth_constant_id(parser, pm_parser_constant_id_token(parser, token));
7115pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7116 pm_locals_write(&parser->current_scope->locals, constant_id, start, end, reads);
7122static pm_constant_id_t
7123pm_parser_local_add_location(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7124 pm_constant_id_t constant_id = pm_parser_constant_id_location(parser, start, end);
7125 if (constant_id != 0) pm_parser_local_add(parser, constant_id, start, end, reads);
7132static inline pm_constant_id_t
7133pm_parser_local_add_token(pm_parser_t *parser, pm_token_t *token, uint32_t reads) {
7134 return pm_parser_local_add_location(parser, token->start, token->end, reads);
7140static pm_constant_id_t
7141pm_parser_local_add_owned(pm_parser_t *parser, uint8_t *start, size_t length) {
7142 pm_constant_id_t constant_id = pm_parser_constant_id_owned(parser, start, length);
7143 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
7150static pm_constant_id_t
7151pm_parser_local_add_constant(pm_parser_t *parser, const char *start, size_t length) {
7152 pm_constant_id_t constant_id = pm_parser_constant_id_constant(parser, start, length);
7153 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
7165pm_parser_parameter_name_check(pm_parser_t *parser, const pm_token_t *name) {
7166 // We want to check whether the parameter name is a numbered parameter or
7168 pm_refute_numbered_parameter(parser, name->start, name->end);
7170 // Otherwise we'll fetch the constant id for the parameter name and check
7171 // whether it's already in the current scope.
7172 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, name);
7174 if (pm_locals_find(&parser->current_scope->locals, constant_id) != UINT32_MAX) {
7175 // Add an error if the parameter doesn't start with _ and has been seen before
7176 if ((name->start < name->end) && (*name->start != '_')) {
7177 pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NAME_DUPLICATED);
7188pm_parser_scope_pop(pm_parser_t *parser) {
7189 pm_scope_t *scope = parser->current_scope;
7190 parser->current_scope = scope->previous;
7191 pm_locals_free(&scope->locals);
7192 pm_node_list_free(&scope->implicit_parameters);
7196/******************************************************************************/
7198/******************************************************************************/
7204pm_state_stack_push(pm_state_stack_t *stack, bool value) {
7205 *stack = (*stack << 1) | (value & 1);
7212pm_state_stack_pop(pm_state_stack_t *stack) {
7220pm_state_stack_p(const pm_state_stack_t *stack) {
7225pm_accepts_block_stack_push(pm_parser_t *parser, bool value) {
7226 // Use the negation of the value to prevent stack overflow.
7227 pm_state_stack_push(&parser->accepts_block_stack, !value);
7231pm_accepts_block_stack_pop(pm_parser_t *parser) {
7232 pm_state_stack_pop(&parser->accepts_block_stack);
7236pm_accepts_block_stack_p(pm_parser_t *parser) {
7237 return !pm_state_stack_p(&parser->accepts_block_stack);
7241pm_do_loop_stack_push(pm_parser_t *parser, bool value) {
7242 pm_state_stack_push(&parser->do_loop_stack, value);
7246pm_do_loop_stack_pop(pm_parser_t *parser) {
7247 pm_state_stack_pop(&parser->do_loop_stack);
7251pm_do_loop_stack_p(pm_parser_t *parser) {
7252 return pm_state_stack_p(&parser->do_loop_stack);
7255/******************************************************************************/
7256/* Lexer check helpers */
7257/******************************************************************************/
7263static inline uint8_t
7264peek_at(const pm_parser_t *parser, const uint8_t *cursor) {
7265 if (cursor < parser->end) {
7277static inline uint8_t
7278peek_offset(pm_parser_t *parser, ptrdiff_t offset) {
7279 return peek_at(parser, parser->current.end + offset);
7286static inline uint8_t
7287peek(const pm_parser_t *parser) {
7288 return peek_at(parser, parser->current.end);
7296match(pm_parser_t *parser, uint8_t value) {
7297 if (peek(parser) == value) {
7298 parser->current.end++;
7309match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
7310 if (peek_at(parser, cursor) == '\n') {
7313 if (peek_at(parser, cursor) == '\r' && peek_at(parser, cursor + 1) == '\n') {
7325match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
7326 return match_eol_at(parser, parser->current.end + offset);
7335match_eol(pm_parser_t *parser) {
7336 return match_eol_at(parser, parser->current.end);
7342static inline const uint8_t *
7343next_newline(const uint8_t *cursor, ptrdiff_t length) {
7344 assert(length >= 0);
7346 // Note that it's okay for us to use memchr here to look for \n because none
7347 // of the encodings that we support have \n as a component of a multi-byte
7349 return memchr(cursor, '\n', (size_t) length);
7356ambiguous_operator_p(const pm_parser_t *parser, bool space_seen) {
7357 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));
7365parser_lex_magic_comment_encoding_value(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
7366 const pm_encoding_t *encoding = pm_encoding_find(start, end);
7368 if (encoding != NULL) {
7369 if (parser->encoding != encoding) {
7370 parser->encoding = encoding;
7371 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
7374 parser->encoding_changed = (encoding != PM_ENCODING_UTF_8_ENTRY);
7386parser_lex_magic_comment_encoding(pm_parser_t *parser) {
7387 const uint8_t *cursor = parser->current.start + 1;
7388 const uint8_t *end = parser->current.end;
7390 bool separator = false;
7392 if (end - cursor <= 6) return;
7393 switch (cursor[6]) {
7394 case 'C': case 'c': cursor += 6; continue;
7395 case 'O': case 'o': cursor += 5; continue;
7396 case 'D': case 'd': cursor += 4; continue;
7397 case 'I': case 'i': cursor += 3; continue;
7398 case 'N': case 'n': cursor += 2; continue;
7399 case 'G': case 'g': cursor += 1; continue;
7406 if (pm_char_is_whitespace(*cursor)) break;
7409 if (pm_strncasecmp(cursor - 6, (const uint8_t *) "coding", 6) == 0) break;
7415 if (++cursor >= end) return;
7416 } while (pm_char_is_whitespace(*cursor));
7418 if (separator) break;
7419 if (*cursor != '=' && *cursor != ':') return;
7425 const uint8_t *value_start = cursor;
7426 while ((*cursor == '-' || *cursor == '_' || parser->encoding->alnum_char(cursor, 1)) && ++cursor < end);
7428 if (!parser_lex_magic_comment_encoding_value(parser, value_start, cursor)) {
7429 // If we were unable to parse the encoding value, then we've got an
7430 // issue because we didn't understand the encoding that the user was
7431 // trying to use. In this case we'll keep using the default encoding but
7432 // add an error to the parser to indicate an unsuccessful parse.
7433 pm_parser_err(parser, value_start, cursor, PM_ERR_INVALID_ENCODING_MAGIC_COMMENT);
7438 PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE,
7439 PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE,
7440 PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID
7441} pm_magic_comment_boolean_value_t;
7447static pm_magic_comment_boolean_value_t
7448parser_lex_magic_comment_boolean_value(const uint8_t *value_start, uint32_t value_length) {
7449 if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "true", 4) == 0) {
7450 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE;
7451 } else if (value_length == 5 && pm_strncasecmp(value_start, (const uint8_t *) "false", 5) == 0) {
7452 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE;
7454 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID;
7459pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
7460 return b == '\'' || b == '"' || b == ':' || b == ';';
7468static inline const uint8_t *
7469parser_lex_magic_comment_emacs_marker(
pm_parser_t *parser,
const uint8_t *cursor,
const uint8_t *end) {
7470 while ((cursor + 3 <= end) && (cursor = pm_memchr(cursor,
'-', (
size_t) (end - cursor), parser->
encoding_changed, parser->
encoding)) != NULL) {
7471 if (cursor + 3 <= end && cursor[1] ==
'*' && cursor[2] ==
'-') {
7490parser_lex_magic_comment(
pm_parser_t *parser,
bool semantic_token_seen) {
7493 const uint8_t *start = parser->
current.start + 1;
7494 const uint8_t *end = parser->
current.end;
7495 if (end - start <= 7)
return false;
7497 const uint8_t *cursor;
7498 bool indicator =
false;
7500 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
7503 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
7514 while (cursor < end) {
7515 while (cursor < end && (pm_char_is_magic_comment_key_delimiter(*cursor) || pm_char_is_whitespace(*cursor))) cursor++;
7517 const uint8_t *key_start = cursor;
7518 while (cursor < end && (!pm_char_is_magic_comment_key_delimiter(*cursor) && !pm_char_is_whitespace(*cursor))) cursor++;
7520 const uint8_t *key_end = cursor;
7521 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7522 if (cursor == end)
break;
7524 if (*cursor ==
':') {
7527 if (!indicator)
return false;
7531 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7532 if (cursor == end)
break;
7534 const uint8_t *value_start;
7535 const uint8_t *value_end;
7537 if (*cursor ==
'"') {
7538 value_start = ++cursor;
7539 for (; cursor < end && *cursor !=
'"'; cursor++) {
7540 if (*cursor ==
'\\' && (cursor + 1 < end)) cursor++;
7543 if (cursor < end && *cursor ==
'"') cursor++;
7545 value_start = cursor;
7546 while (cursor < end && *cursor !=
'"' && *cursor !=
';' && !pm_char_is_whitespace(*cursor)) cursor++;
7551 while (cursor < end && (*cursor ==
';' || pm_char_is_whitespace(*cursor))) cursor++;
7553 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7554 if (cursor != end)
return false;
7560 const size_t key_length = (size_t) (key_end - key_start);
7564 pm_string_shared_init(&key, key_start, key_end);
7566 uint8_t *buffer =
xmalloc(key_length);
7567 if (buffer == NULL)
break;
7569 memcpy(buffer, key_start, key_length);
7570 buffer[dash - key_start] =
'_';
7572 while ((dash = pm_memchr(dash + 1,
'-', (
size_t) (key_end - dash - 1), parser->
encoding_changed, parser->
encoding)) != NULL) {
7573 buffer[dash - key_start] =
'_';
7576 pm_string_owned_init(&key, buffer, key_length);
7582 uint32_t value_length = (uint32_t) (value_end - value_start);
7588 (key_length == 8 && pm_strncasecmp(key_source, (
const uint8_t *)
"encoding", 8) == 0) ||
7589 (key_length == 6 && pm_strncasecmp(key_source, (
const uint8_t *)
"coding", 6) == 0)
7591 result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
7595 if (key_length == 11) {
7596 if (pm_strncasecmp(key_source, (
const uint8_t *)
"warn_indent", 11) == 0) {
7597 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7598 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7599 PM_PARSER_WARN_TOKEN_FORMAT(
7602 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7604 (
const char *) key_source,
7606 (
const char *) value_start
7609 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7612 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7617 }
else if (key_length == 21) {
7618 if (pm_strncasecmp(key_source, (
const uint8_t *)
"frozen_string_literal", 21) == 0) {
7621 if (semantic_token_seen) {
7622 pm_parser_warn_token(parser, &parser->
current, PM_WARN_IGNORED_FROZEN_STRING_LITERAL);
7624 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7625 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7626 PM_PARSER_WARN_TOKEN_FORMAT(
7629 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7631 (
const char *) key_source,
7633 (
const char *) value_start
7636 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7639 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7645 }
else if (key_length == 24) {
7646 if (pm_strncasecmp(key_source, (
const uint8_t *)
"shareable_constant_value", 24) == 0) {
7647 const uint8_t *cursor = parser->
current.start;
7648 while ((cursor > parser->
start) && ((cursor[-1] ==
' ') || (cursor[-1] ==
'\t'))) cursor--;
7650 if (!((cursor == parser->
start) || (cursor[-1] ==
'\n'))) {
7651 pm_parser_warn_token(parser, &parser->
current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
7652 }
else if (value_length == 4 && pm_strncasecmp(value_start, (
const uint8_t *)
"none", 4) == 0) {
7653 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
7654 }
else if (value_length == 7 && pm_strncasecmp(value_start, (
const uint8_t *)
"literal", 7) == 0) {
7655 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
7656 }
else if (value_length == 23 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_everything", 23) == 0) {
7657 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING);
7658 }
else if (value_length == 17 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_copy", 17) == 0) {
7659 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY);
7661 PM_PARSER_WARN_TOKEN_FORMAT(
7664 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7666 (
const char *) key_source,
7668 (
const char *) value_start
7696static const uint32_t context_terminators[] = {
7698 [
PM_CONTEXT_BEGIN] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7701 [
PM_CONTEXT_BEGIN_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7703 [
PM_CONTEXT_BLOCK_KEYWORDS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7707 [
PM_CONTEXT_BLOCK_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7708 [
PM_CONTEXT_CASE_WHEN] = (1U << PM_TOKEN_KEYWORD_WHEN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
7709 [
PM_CONTEXT_CASE_IN] = (1U << PM_TOKEN_KEYWORD_IN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
7710 [
PM_CONTEXT_CLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7713 [
PM_CONTEXT_CLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7714 [
PM_CONTEXT_DEF] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7717 [
PM_CONTEXT_DEF_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7722 [
PM_CONTEXT_ELSIF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
7726 [
PM_CONTEXT_IF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
7728 [
PM_CONTEXT_LAMBDA_DO_END] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7731 [
PM_CONTEXT_LAMBDA_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7734 [
PM_CONTEXT_MODULE] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7737 [
PM_CONTEXT_MODULE_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7741 [
PM_CONTEXT_PREDICATE] = (1U << PM_TOKEN_KEYWORD_THEN) | (1U << PM_TOKEN_NEWLINE) | (1U << PM_TOKEN_SEMICOLON),
7744 [
PM_CONTEXT_SCLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7747 [
PM_CONTEXT_SCLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7749 [
PM_CONTEXT_UNLESS] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7756 return token->type < 32 && (context_terminators[context] & (1U << token->type));
7767 while (context_node != NULL) {
7768 if (context_terminator(context_node->
context, token))
return context_node->
context;
7769 context_node = context_node->
prev;
7778 if (context_node == NULL)
return false;
7803 while (context_node != NULL) {
7804 if (context_node->
context == context)
return true;
7805 context_node = context_node->
prev;
7815 while (context_node != NULL) {
7816 switch (context_node->
context) {
7837 context_node = context_node->
prev;
7852 assert(
false &&
"unreachable");
7910 assert(
false &&
"unreachable");
7919pm_strspn_number_validate(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const uint8_t *invalid) {
7920 if (invalid != NULL) {
7921 pm_diagnostic_id_t diag_id = (invalid == (
string + length - 1)) ? PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING : PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER;
7922 pm_parser_err(parser, invalid, invalid + 1, diag_id);
7927pm_strspn_binary_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
7928 const uint8_t *invalid = NULL;
7929 size_t length = pm_strspn_binary_number(
string, parser->
end -
string, &invalid);
7930 pm_strspn_number_validate(parser,
string, length, invalid);
7935pm_strspn_octal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
7936 const uint8_t *invalid = NULL;
7937 size_t length = pm_strspn_octal_number(
string, parser->
end -
string, &invalid);
7938 pm_strspn_number_validate(parser,
string, length, invalid);
7943pm_strspn_decimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
7944 const uint8_t *invalid = NULL;
7945 size_t length = pm_strspn_decimal_number(
string, parser->
end -
string, &invalid);
7946 pm_strspn_number_validate(parser,
string, length, invalid);
7951pm_strspn_hexadecimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
7952 const uint8_t *invalid = NULL;
7953 size_t length = pm_strspn_hexadecimal_number(
string, parser->
end -
string, &invalid);
7954 pm_strspn_number_validate(parser,
string, length, invalid);
7958static pm_token_type_t
7959lex_optional_float_suffix(
pm_parser_t *parser,
bool* seen_e) {
7960 pm_token_type_t
type = PM_TOKEN_INTEGER;
7964 if (peek(parser) ==
'.') {
7965 if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
7967 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
7968 type = PM_TOKEN_FLOAT;
7978 if ((peek(parser) ==
'e') || (peek(parser) ==
'E')) {
7979 if ((peek_offset(parser, 1) ==
'+') || (peek_offset(parser, 1) ==
'-')) {
7982 if (pm_char_is_decimal_digit(peek(parser))) {
7984 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
7986 pm_parser_err_current(parser, PM_ERR_INVALID_FLOAT_EXPONENT);
7988 }
else if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
7990 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
7996 type = PM_TOKEN_FLOAT;
8002static pm_token_type_t
8003lex_numeric_prefix(
pm_parser_t *parser,
bool* seen_e) {
8004 pm_token_type_t
type = PM_TOKEN_INTEGER;
8007 if (peek_offset(parser, -1) ==
'0') {
8008 switch (*parser->
current.end) {
8013 if (pm_char_is_decimal_digit(peek(parser))) {
8014 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8017 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_DECIMAL);
8026 if (pm_char_is_binary_digit(peek(parser))) {
8027 parser->
current.end += pm_strspn_binary_number_validate(parser, parser->
current.end);
8030 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
8040 if (pm_char_is_octal_digit(peek(parser))) {
8041 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8044 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
8060 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8068 if (pm_char_is_hexadecimal_digit(peek(parser))) {
8069 parser->
current.end += pm_strspn_hexadecimal_number_validate(parser, parser->
current.end);
8072 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
8075 parser->
integer_base = PM_INTEGER_BASE_FLAGS_HEXADECIMAL;
8080 type = lex_optional_float_suffix(parser, seen_e);
8087 type = lex_optional_float_suffix(parser, seen_e);
8094 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8097 type = lex_optional_float_suffix(parser, seen_e);
8103 if (peek_offset(parser, 0) ==
'.' && pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8104 const uint8_t *fraction_start = parser->
current.end;
8105 const uint8_t *fraction_end = parser->
current.end + 2;
8106 fraction_end += pm_strspn_decimal_digit(fraction_end, parser->
end - fraction_end);
8107 pm_parser_err(parser, fraction_start, fraction_end, PM_ERR_INVALID_NUMBER_FRACTION);
8113static pm_token_type_t
8115 pm_token_type_t
type = PM_TOKEN_INTEGER;
8119 bool seen_e =
false;
8120 type = lex_numeric_prefix(parser, &seen_e);
8122 const uint8_t *end = parser->
current.end;
8123 pm_token_type_t suffix_type =
type;
8125 if (
type == PM_TOKEN_INTEGER) {
8126 if (match(parser,
'r')) {
8127 suffix_type = PM_TOKEN_INTEGER_RATIONAL;
8129 if (match(parser,
'i')) {
8130 suffix_type = PM_TOKEN_INTEGER_RATIONAL_IMAGINARY;
8132 }
else if (match(parser,
'i')) {
8133 suffix_type = PM_TOKEN_INTEGER_IMAGINARY;
8136 if (!seen_e && match(parser,
'r')) {
8137 suffix_type = PM_TOKEN_FLOAT_RATIONAL;
8139 if (match(parser,
'i')) {
8140 suffix_type = PM_TOKEN_FLOAT_RATIONAL_IMAGINARY;
8142 }
else if (match(parser,
'i')) {
8143 suffix_type = PM_TOKEN_FLOAT_IMAGINARY;
8147 const uint8_t b = peek(parser);
8148 if (b !=
'\0' && (b >= 0x80 || ((b >=
'a' && b <=
'z') || (b >=
'A' && b <=
'Z')) || b ==
'_')) {
8158static pm_token_type_t
8161 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
8162 return PM_TOKEN_GLOBAL_VARIABLE;
8167 bool allow_multiple =
true;
8169 switch (*parser->
current.end) {
8187 return PM_TOKEN_GLOBAL_VARIABLE;
8194 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_BACK_REFERENCE;
8200 if ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0) {
8203 }
while ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0);
8207 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
current, diag_id);
8210 return PM_TOKEN_GLOBAL_VARIABLE;
8223 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_NUMBERED_REFERENCE;
8227 allow_multiple =
false;
8232 if ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0) {
8235 }
while (allow_multiple && (width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0);
8236 }
else if (pm_char_is_whitespace(peek(parser))) {
8239 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
8245 PM_PARSER_ERR_FORMAT(parser, parser->
current.start, end, diag_id, (
int) (end - parser->
current.start), (
const char *) parser->
current.start);
8248 return PM_TOKEN_GLOBAL_VARIABLE;
8265static inline pm_token_type_t
8266lex_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) {
8267 if (memcmp(current_start, value, vlen) == 0) {
8270 if (parser->
lex_state & PM_LEX_STATE_FNAME) {
8271 lex_state_set(parser, PM_LEX_STATE_ENDFN);
8273 lex_state_set(parser, state);
8274 if (state == PM_LEX_STATE_BEG) {
8278 if ((modifier_type != PM_TOKEN_EOF) && !(last_state & (PM_LEX_STATE_BEG | PM_LEX_STATE_LABELED | PM_LEX_STATE_CLASS))) {
8279 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
8280 return modifier_type;
8287 return PM_TOKEN_EOF;
8290static pm_token_type_t
8291lex_identifier(
pm_parser_t *parser,
bool previous_command_start) {
8294 const uint8_t *end = parser->
end;
8295 const uint8_t *current_start = parser->
current.start;
8296 const uint8_t *current_end = parser->
current.end;
8299 if (encoding_changed) {
8300 while ((width = char_is_identifier(parser, current_end, end - current_end)) > 0) {
8301 current_end += width;
8304 while ((width = char_is_identifier_utf8(current_end, end - current_end)) > 0) {
8305 current_end += width;
8308 parser->
current.end = current_end;
8312 width = (size_t) (current_end - current_start);
8314 if (current_end < end) {
8315 if (((current_end + 1 >= end) || (current_end[1] !=
'=')) && (match(parser,
'!') || match(parser,
'?'))) {
8321 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
8322 (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')
8326 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
8327 (void) match(parser,
':');
8328 return PM_TOKEN_LABEL;
8331 if (parser->
lex_state != PM_LEX_STATE_DOT) {
8332 if (width == 8 && (lex_keyword(parser, current_start,
"defined?", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_DEFINED, PM_TOKEN_EOF) != PM_TOKEN_EOF)) {
8333 return PM_TOKEN_KEYWORD_DEFINED;
8337 return PM_TOKEN_METHOD_NAME;
8340 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,
'=')) {
8343 return PM_TOKEN_IDENTIFIER;
8347 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
8348 peek(parser) ==
':' && peek_offset(parser, 1) !=
':'
8352 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
8353 (void) match(parser,
':');
8354 return PM_TOKEN_LABEL;
8358 if (parser->
lex_state != PM_LEX_STATE_DOT) {
8359 pm_token_type_t
type;
8362 if (lex_keyword(parser, current_start,
"do", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_DO, PM_TOKEN_EOF) != PM_TOKEN_EOF) {
8363 if (pm_do_loop_stack_p(parser)) {
8364 return PM_TOKEN_KEYWORD_DO_LOOP;
8366 return PM_TOKEN_KEYWORD_DO;
8369 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;
8370 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;
8371 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;
8374 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;
8375 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;
8376 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;
8377 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;
8378 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;
8379 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;
8380 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;
8383 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;
8384 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;
8385 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;
8386 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;
8387 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;
8388 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;
8389 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;
8390 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;
8393 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;
8394 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;
8395 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;
8396 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;
8397 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;
8398 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;
8399 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;
8400 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;
8401 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;
8402 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;
8403 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;
8404 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;
8405 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;
8408 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;
8409 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;
8410 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;
8411 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;
8412 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;
8415 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;
8416 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;
8419 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;
8424 if (encoding_changed) {
8425 return parser->
encoding->
isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8427 return pm_encoding_utf_8_isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8453static pm_token_type_t
8454lex_interpolation(
pm_parser_t *parser,
const uint8_t *pound) {
8457 if (pound + 1 >= parser->
end) {
8458 parser->
current.end = pound + 1;
8459 return PM_TOKEN_STRING_CONTENT;
8468 if (pound + 2 >= parser->
end) {
8469 parser->
current.end = pound + 1;
8470 return PM_TOKEN_STRING_CONTENT;
8475 const uint8_t *variable = pound + 2;
8476 if (*variable ==
'@' && pound + 3 < parser->
end) variable++;
8478 if (char_is_identifier_start(parser, variable, parser->
end - variable)) {
8482 if (pound > parser->
current.start) {
8484 return PM_TOKEN_STRING_CONTENT;
8489 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
8490 parser->
current.end = pound + 1;
8491 return PM_TOKEN_EMBVAR;
8497 parser->
current.end = pound + 1;
8498 return PM_TOKEN_NOT_PROVIDED;
8503 if (pound + 2 >= parser->
end) {
8504 parser->
current.end = pound + 1;
8505 return PM_TOKEN_STRING_CONTENT;
8511 const uint8_t *check = pound + 2;
8513 if (pound[2] ==
'-') {
8514 if (pound + 3 >= parser->
end) {
8515 parser->
current.end = pound + 2;
8516 return PM_TOKEN_STRING_CONTENT;
8527 char_is_identifier_start(parser, check, parser->
end - check) ||
8528 (pound[2] !=
'-' && (pm_char_is_decimal_digit(pound[2]) || char_is_global_name_punctuation(pound[2])))
8533 if (pound > parser->
current.start) {
8535 return PM_TOKEN_STRING_CONTENT;
8540 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
8541 parser->
current.end = pound + 1;
8542 return PM_TOKEN_EMBVAR;
8547 parser->
current.end = pound + 1;
8548 return PM_TOKEN_NOT_PROVIDED;
8553 if (pound > parser->
current.start) {
8555 return PM_TOKEN_STRING_CONTENT;
8562 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBEXPR });
8563 parser->
current.end = pound + 2;
8565 pm_do_loop_stack_push(parser,
false);
8566 return PM_TOKEN_EMBEXPR_BEGIN;
8571 parser->
current.end = pound + 1;
8572 return PM_TOKEN_NOT_PROVIDED;
8576static const uint8_t PM_ESCAPE_FLAG_NONE = 0x0;
8577static const uint8_t PM_ESCAPE_FLAG_CONTROL = 0x1;
8578static const uint8_t PM_ESCAPE_FLAG_META = 0x2;
8579static const uint8_t PM_ESCAPE_FLAG_SINGLE = 0x4;
8580static const uint8_t PM_ESCAPE_FLAG_REGEXP = 0x8;
8585static const bool ascii_printable_chars[] = {
8586 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
8587 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8588 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8589 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8590 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8591 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
8592 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8593 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
8597char_is_ascii_printable(
const uint8_t b) {
8598 return (b < 0x80) && ascii_printable_chars[b];
8605static inline uint8_t
8606escape_hexadecimal_digit(
const uint8_t value) {
8607 return (uint8_t) ((value <=
'9') ? (value -
'0') : (value & 0x7) + 9);
8615static inline uint32_t
8618 for (
size_t index = 0; index < length; index++) {
8619 if (index != 0) value <<= 4;
8620 value |= escape_hexadecimal_digit(
string[index]);
8625 if (value >= 0xD800 && value <= 0xDFFF) {
8626 if (error_location != NULL) {
8627 pm_parser_err(parser, error_location->
start, error_location->
end, PM_ERR_ESCAPE_INVALID_UNICODE);
8629 pm_parser_err(parser,
string,
string + length, PM_ERR_ESCAPE_INVALID_UNICODE);
8640static inline uint8_t
8641escape_byte(uint8_t value,
const uint8_t flags) {
8642 if (flags & PM_ESCAPE_FLAG_CONTROL) value &= 0x9f;
8643 if (flags & PM_ESCAPE_FLAG_META) value |= 0x80;
8651escape_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) {
8655 if (value >= 0x80 || flags & PM_ESCAPE_FLAG_SINGLE) {
8663 if (!pm_buffer_append_unicode_codepoint(buffer, value)) {
8664 pm_parser_err(parser, start, end, PM_ERR_ESCAPE_INVALID_UNICODE);
8665 pm_buffer_append_byte(buffer, 0xEF);
8666 pm_buffer_append_byte(buffer, 0xBF);
8667 pm_buffer_append_byte(buffer, 0xBD);
8679 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_MIXED_ENCODING, parser->
encoding->
name);
8685 pm_buffer_append_byte(buffer,
byte);
8705 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8706 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X",
byte);
8709 escape_write_byte_encoded(parser, buffer,
byte);
8721 width = pm_encoding_utf_8_char_width(parser->
current.end, parser->
end - parser->
current.end);
8725 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(*parser->
current.end++, flags));
8726 }
else if (width > 1) {
8728 pm_buffer_t *b = (flags & PM_ESCAPE_FLAG_REGEXP) ? regular_expression_buffer : buffer;
8729 pm_buffer_append_bytes(b, parser->
current.end, width);
8735 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
8745escape_read_warn(
pm_parser_t *parser, uint8_t flags, uint8_t flag,
const char *
type) {
8746#define FLAG(value) ((value & PM_ESCAPE_FLAG_CONTROL) ? "\\C-" : (value & PM_ESCAPE_FLAG_META) ? "\\M-" : "")
8748 PM_PARSER_WARN_TOKEN_FORMAT(
8751 PM_WARN_INVALID_CHARACTER,
8765 uint8_t peeked = peek(parser);
8769 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\\', flags));
8774 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\'', flags));
8779 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\a', flags));
8784 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\b', flags));
8789 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\033', flags));
8794 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\f', flags));
8799 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\n', flags));
8804 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\r', flags));
8809 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
' ', flags));
8814 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\t', flags));
8819 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\v', flags));
8822 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': {
8823 uint8_t value = (uint8_t) (*parser->
current.end -
'0');
8826 if (pm_char_is_octal_digit(peek(parser))) {
8827 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
8830 if (pm_char_is_octal_digit(peek(parser))) {
8831 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
8836 value = escape_byte(value, flags);
8837 escape_write_byte(parser, buffer, regular_expression_buffer, flags, value);
8841 const uint8_t *start = parser->
current.end - 1;
8844 uint8_t
byte = peek(parser);
8846 if (pm_char_is_hexadecimal_digit(
byte)) {
8847 uint8_t value = escape_hexadecimal_digit(
byte);
8850 byte = peek(parser);
8851 if (pm_char_is_hexadecimal_digit(
byte)) {
8852 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(
byte));
8856 value = escape_byte(value, flags);
8857 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8858 if (flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) {
8859 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X", value);
8861 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
8865 escape_write_byte_encoded(parser, buffer, value);
8867 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
8873 const uint8_t *start = parser->
current.end - 1;
8877 const uint8_t *start = parser->
current.end - 2;
8878 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
8879 }
else if (peek(parser) ==
'{') {
8880 const uint8_t *unicode_codepoints_start = parser->
current.end - 2;
8885 if ((whitespace = pm_strspn_inline_whitespace(parser->
current.end, parser->
end - parser->
current.end)) > 0) {
8886 parser->
current.end += whitespace;
8887 }
else if (peek(parser) ==
'\\' && peek_offset(parser, 1) ==
'n') {
8898 const uint8_t *extra_codepoints_start = NULL;
8899 int codepoints_count = 0;
8902 const uint8_t *unicode_start = parser->
current.end;
8903 size_t hexadecimal_length = pm_strspn_hexadecimal_digit(parser->
current.end, parser->
end - parser->
current.end);
8905 if (hexadecimal_length > 6) {
8907 pm_parser_err(parser, unicode_start, unicode_start + hexadecimal_length, PM_ERR_ESCAPE_INVALID_UNICODE_LONG);
8908 }
else if (hexadecimal_length == 0) {
8911 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8915 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
8917 pm_parser_err(parser, parser->
current.end, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE);
8918 pm_parser_err(parser, parser->
current.end, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
8924 parser->
current.end += hexadecimal_length;
8926 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count == 2) {
8927 extra_codepoints_start = unicode_start;
8930 uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length, NULL);
8931 escape_write_unicode(parser, buffer, flags, unicode_start, parser->
current.end, value);
8938 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count > 1) {
8939 pm_parser_err(parser, extra_codepoints_start, parser->
current.end - 1, PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL);
8943 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_LIST, (
int) (parser->
current.end - start), start);
8944 }
else if (peek(parser) ==
'}') {
8947 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8951 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
8953 pm_parser_err(parser, unicode_codepoints_start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
8957 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8958 pm_buffer_append_bytes(regular_expression_buffer, unicode_codepoints_start, (
size_t) (parser->
current.end - unicode_codepoints_start));
8961 size_t length = pm_strspn_hexadecimal_digit(parser->
current.end, MIN(parser->
end - parser->
current.end, 4));
8964 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8965 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
8967 const uint8_t *start = parser->
current.end - 2;
8968 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
8970 }
else if (length == 4) {
8971 uint32_t value = escape_unicode(parser, parser->
current.end, 4, NULL);
8973 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8974 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end + 4 - start));
8977 escape_write_unicode(parser, buffer, flags, start, parser->
current.end + 4, value);
8980 parser->
current.end += length;
8982 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8986 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
8988 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_UNICODE);
8997 if (flags & PM_ESCAPE_FLAG_CONTROL) {
8998 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9002 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9006 uint8_t peeked = peek(parser);
9010 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9016 if (match(parser,
'u') || match(parser,
'U')) {
9017 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9021 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9025 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9026 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9030 escape_read_warn(parser, flags, 0,
"\\t");
9031 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9034 if (!char_is_ascii_printable(peeked)) {
9035 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9040 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9047 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9048 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9051 if (peek(parser) !=
'-') {
9053 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9059 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9063 uint8_t peeked = peek(parser);
9067 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9073 if (match(parser,
'u') || match(parser,
'U')) {
9074 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9078 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9082 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9083 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9087 escape_read_warn(parser, flags, 0,
"\\t");
9088 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9091 if (!char_is_ascii_printable(peeked)) {
9093 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9098 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9105 if (flags & PM_ESCAPE_FLAG_META) {
9106 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META_REPEAT);
9109 if (peek(parser) !=
'-') {
9111 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
9117 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
9121 uint8_t peeked = peek(parser);
9126 if (match(parser,
'u') || match(parser,
'U')) {
9127 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9131 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_META);
9135 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_META,
"\\s");
9136 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9140 escape_read_warn(parser, flags & ((uint8_t) ~PM_ESCAPE_FLAG_CONTROL), PM_ESCAPE_FLAG_META,
"\\t");
9141 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9144 if (!char_is_ascii_printable(peeked)) {
9146 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
9151 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9156 if (peek_offset(parser, 1) ==
'\n') {
9158 escape_write_byte_encoded(parser, buffer, escape_byte(
'\n', flags));
9164 if ((flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) && !char_is_ascii_printable(peeked)) {
9166 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
9170 escape_write_escape_encoded(parser, buffer, regular_expression_buffer, flags);
9172 pm_parser_err_current(parser, PM_ERR_INVALID_ESCAPE_CHARACTER);
9204static pm_token_type_t
9206 if (lex_state_end_p(parser)) {
9207 lex_state_set(parser, PM_LEX_STATE_BEG);
9208 return PM_TOKEN_QUESTION_MARK;
9212 pm_parser_err_current(parser, PM_ERR_INCOMPLETE_QUESTION_MARK);
9214 return PM_TOKEN_CHARACTER_LITERAL;
9217 if (pm_char_is_whitespace(*parser->
current.end)) {
9218 lex_state_set(parser, PM_LEX_STATE_BEG);
9219 return PM_TOKEN_QUESTION_MARK;
9222 lex_state_set(parser, PM_LEX_STATE_BEG);
9224 if (match(parser,
'\\')) {
9225 lex_state_set(parser, PM_LEX_STATE_END);
9228 pm_buffer_init_capacity(&buffer, 3);
9230 escape_read(parser, &buffer, NULL, PM_ESCAPE_FLAG_SINGLE);
9233 return PM_TOKEN_CHARACTER_LITERAL;
9242 (parser->
current.end + encoding_width >= parser->
end) ||
9243 !char_is_identifier(parser, parser->
current.end + encoding_width, parser->
end - (parser->
current.end + encoding_width))
9246 lex_state_set(parser, PM_LEX_STATE_END);
9247 parser->
current.end += encoding_width;
9249 return PM_TOKEN_CHARACTER_LITERAL;
9253 return PM_TOKEN_QUESTION_MARK;
9260static pm_token_type_t
9262 pm_token_type_t
type = match(parser,
'@') ? PM_TOKEN_CLASS_VARIABLE : PM_TOKEN_INSTANCE_VARIABLE;
9263 const uint8_t *end = parser->
end;
9266 if ((width = char_is_identifier_start(parser, parser->
current.end, end - parser->
current.end)) > 0) {
9269 while ((width = char_is_identifier(parser, parser->
current.end, end - parser->
current.end)) > 0) {
9272 }
else if (parser->
current.end < end && pm_char_is_decimal_digit(*parser->
current.end)) {
9273 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE;
9275 diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS_3_3 : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE_3_3;
9279 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, diag_id, (
int) ((parser->
current.end + width) - parser->
current.start), (
const char *) parser->
current.start);
9281 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_CLASS_VARIABLE_BARE : PM_ERR_INSTANCE_VARIABLE_BARE;
9282 pm_parser_err_token(parser, &parser->
current, diag_id);
9288 lex_mode_pop(parser);
9310 if (comment == NULL)
return NULL;
9325static pm_token_type_t
9328 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
9330 if (newline == NULL) {
9333 pm_newline_list_append(&parser->
newline_list, newline);
9334 parser->
current.end = newline + 1;
9337 parser->
current.type = PM_TOKEN_EMBDOC_BEGIN;
9338 parser_lex_callback(parser);
9341 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_EMBDOC);
9342 if (comment == NULL)
return PM_TOKEN_EOF;
9346 while (parser->
current.end + 4 <= parser->
end) {
9352 (memcmp(parser->
current.end,
"=end", 4) == 0) &&
9355 pm_char_is_whitespace(parser->
current.end[4]) ||
9356 (parser->
current.end[4] ==
'\0') ||
9357 (parser->
current.end[4] ==
'\004') ||
9358 (parser->
current.end[4] ==
'\032')
9361 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
9363 if (newline == NULL) {
9366 pm_newline_list_append(&parser->
newline_list, newline);
9367 parser->
current.end = newline + 1;
9370 parser->
current.type = PM_TOKEN_EMBDOC_END;
9371 parser_lex_callback(parser);
9376 return PM_TOKEN_EMBDOC_END;
9381 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
9383 if (newline == NULL) {
9386 pm_newline_list_append(&parser->
newline_list, newline);
9387 parser->
current.end = newline + 1;
9390 parser->
current.type = PM_TOKEN_EMBDOC_LINE;
9391 parser_lex_callback(parser);
9394 pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
9399 return PM_TOKEN_EOF;
9409 parser->
current.type = PM_TOKEN_IGNORED_NEWLINE;
9410 parser_lex_callback(parser);
9434 const uint8_t *cursor = parser->
current.end;
9436 while (cursor < parser->end && *cursor !=
'\n' && *cursor !=
'#') {
9437 if (!pm_char_is_inline_whitespace(*cursor++))
return false;
9500 pm_buffer_append_byte(&token_buffer->
buffer,
byte);
9517 width = pm_encoding_utf_8_char_width(parser->
current.end, parser->
end - parser->
current.end);
9522 return (width == 0 ? 1 : width);
9530 size_t width = parser_char_width(parser);
9531 pm_buffer_append_bytes(&token_buffer->
buffer, parser->
current.end, width);
9537 size_t width = parser_char_width(parser);
9544pm_slice_ascii_only_p(
const uint8_t *value,
size_t length) {
9545 for (
size_t index = 0; index < length; index++) {
9546 if (value[index] & 0x80)
return false;
9581 if (token_buffer->
cursor == NULL) {
9584 pm_buffer_append_bytes(&token_buffer->
buffer, token_buffer->
cursor, (
size_t) (parser->
current.end - token_buffer->
cursor));
9585 pm_token_buffer_copy(parser, token_buffer);
9597 pm_regexp_token_buffer_copy(parser, token_buffer);
9601#define PM_TOKEN_BUFFER_DEFAULT_SIZE 16
9613 const uint8_t *start;
9614 if (token_buffer->
cursor == NULL) {
9615 pm_buffer_init_capacity(&token_buffer->
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9616 start = parser->
current.start;
9618 start = token_buffer->
cursor;
9621 const uint8_t *end = parser->
current.end - 1;
9622 assert(end >= start);
9623 pm_buffer_append_bytes(&token_buffer->
buffer, start, (
size_t) (end - start));
9625 token_buffer->
cursor = end;
9630 const uint8_t *start;
9632 pm_buffer_init_capacity(&token_buffer->
base.
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9633 pm_buffer_init_capacity(&token_buffer->
regexp_buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9634 start = parser->
current.start;
9639 const uint8_t *end = parser->
current.end - 1;
9640 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, (
size_t) (end - start));
9641 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, (
size_t) (end - start));
9646#undef PM_TOKEN_BUFFER_DEFAULT_SIZE
9654 size_t whitespace = 0;
9657 case PM_HEREDOC_INDENT_NONE:
9662 case PM_HEREDOC_INDENT_DASH:
9664 *cursor += pm_strspn_inline_whitespace(*cursor, parser->
end - *cursor);
9666 case PM_HEREDOC_INDENT_TILDE:
9669 while (*cursor < parser->end && pm_char_is_inline_whitespace(**cursor)) {
9670 if (**cursor ==
'\t') {
9671 whitespace = (whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
9690 size_t eol_length = match_eol(parser);
9697 parser_flush_heredoc_end(parser);
9703 uint8_t delimiter = *parser->
current.end;
9707 if (eol_length == 2) {
9708 delimiter = *(parser->
current.end + 1);
9711 parser->
current.end += eol_length;
9715 return *parser->
current.end++;
9722#define LEX(token_type) parser->current.type = token_type; parser_lex_callback(parser); return
9741 bool lexed_comment =
false;
9749 case PM_LEX_DEFAULT:
9750 case PM_LEX_EMBEXPR:
9767 bool space_seen =
false;
9771 bool chomping =
true;
9772 while (parser->
current.end < parser->
end && chomping) {
9773 switch (*parser->
current.end) {
9782 if (match_eol_offset(parser, 1)) {
9785 pm_parser_warn(parser, parser->
current.end, parser->
current.end + 1, PM_WARN_UNEXPECTED_CARRIAGE_RETURN);
9791 size_t eol_length = match_eol_offset(parser, 1);
9797 parser->
current.end += eol_length + 1;
9801 }
else if (pm_char_is_inline_whitespace(*parser->
current.end)) {
9834 switch (*parser->
current.end++) {
9842 const uint8_t *ending = next_newline(parser->
current.end, parser->
end - parser->
current.end);
9843 parser->
current.end = ending == NULL ? parser->
end : ending;
9848 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_INLINE);
9851 if (ending) parser->
current.end++;
9852 parser->
current.type = PM_TOKEN_COMMENT;
9853 parser_lex_callback(parser);
9865 parser_lex_magic_comment_encoding(parser);
9869 lexed_comment =
true;
9875 size_t eol_length = match_eol_at(parser, parser->
current.end - 1);
9887 if (!lexed_comment) {
9888 parser->
current.end += eol_length - 1;
9897 parser_flush_heredoc_end(parser);
9902 switch (lex_state_ignored_p(parser)) {
9903 case PM_IGNORED_NEWLINE_NONE:
9905 case PM_IGNORED_NEWLINE_PATTERN:
9907 if (!lexed_comment) parser_lex_ignored_newline(parser);
9908 lex_state_set(parser, PM_LEX_STATE_BEG);
9910 parser->
current.type = PM_TOKEN_NEWLINE;
9914 case PM_IGNORED_NEWLINE_ALL:
9915 if (!lexed_comment) parser_lex_ignored_newline(parser);
9916 lexed_comment =
false;
9917 goto lex_next_token;
9925 next_content += pm_strspn_inline_whitespace(next_content, parser->
end - next_content);
9927 if (next_content < parser->end) {
9933 if (next_content[0] ==
'#') {
9935 const uint8_t *following = next_newline(next_content, parser->
end - next_content);
9937 while (following && (following + 1 < parser->
end)) {
9939 following += pm_strspn_inline_whitespace(following, parser->
end - following);
9943 if (peek_at(parser, following) !=
'#')
break;
9947 following = next_newline(following, parser->
end - following);
9952 if (lex_state_ignored_p(parser)) {
9953 if (!lexed_comment) parser_lex_ignored_newline(parser);
9954 lexed_comment =
false;
9955 goto lex_next_token;
9961 (peek_at(parser, following) ==
'.') ||
9962 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'.')
9964 if (!lexed_comment) parser_lex_ignored_newline(parser);
9965 lexed_comment =
false;
9966 goto lex_next_token;
9976 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'&') ||
9977 (peek_at(parser, following) ==
'|' && peek_at(parser, following + 1) ==
'|') ||
9978 (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))) ||
9979 (peek_at(parser, following) ==
'o' && peek_at(parser, following + 1) ==
'r' && !char_is_identifier(parser, following + 2, parser->
end - (following + 2)))
9982 if (!lexed_comment) parser_lex_ignored_newline(parser);
9983 lexed_comment =
false;
9984 goto lex_next_token;
9990 if (next_content[0] ==
'.') {
9994 if (peek_at(parser, next_content + 1) ==
'.') {
9995 if (!lexed_comment) parser_lex_ignored_newline(parser);
9996 lex_state_set(parser, PM_LEX_STATE_BEG);
9998 parser->
current.type = PM_TOKEN_NEWLINE;
10002 if (!lexed_comment) parser_lex_ignored_newline(parser);
10003 lex_state_set(parser, PM_LEX_STATE_DOT);
10004 parser->
current.start = next_content;
10005 parser->
current.end = next_content + 1;
10012 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'.') {
10013 if (!lexed_comment) parser_lex_ignored_newline(parser);
10014 lex_state_set(parser, PM_LEX_STATE_DOT);
10015 parser->
current.start = next_content;
10016 parser->
current.end = next_content + 2;
10018 LEX(PM_TOKEN_AMPERSAND_DOT);
10024 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'&') {
10025 if (!lexed_comment) parser_lex_ignored_newline(parser);
10026 lex_state_set(parser, PM_LEX_STATE_BEG);
10027 parser->
current.start = next_content;
10028 parser->
current.end = next_content + 2;
10030 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
10035 if (peek_at(parser, next_content) ==
'|' && peek_at(parser, next_content + 1) ==
'|') {
10036 if (!lexed_comment) parser_lex_ignored_newline(parser);
10037 lex_state_set(parser, PM_LEX_STATE_BEG);
10038 parser->
current.start = next_content;
10039 parser->
current.end = next_content + 2;
10041 LEX(PM_TOKEN_PIPE_PIPE);
10047 peek_at(parser, next_content) ==
'a' &&
10048 peek_at(parser, next_content + 1) ==
'n' &&
10049 peek_at(parser, next_content + 2) ==
'd' &&
10050 !char_is_identifier(parser, next_content + 3, parser->
end - (next_content + 3))
10052 if (!lexed_comment) parser_lex_ignored_newline(parser);
10053 lex_state_set(parser, PM_LEX_STATE_BEG);
10054 parser->
current.start = next_content;
10055 parser->
current.end = next_content + 3;
10058 LEX(PM_TOKEN_KEYWORD_AND);
10064 peek_at(parser, next_content) ==
'o' &&
10065 peek_at(parser, next_content + 1) ==
'r' &&
10066 !char_is_identifier(parser, next_content + 2, parser->
end - (next_content + 2))
10068 if (!lexed_comment) parser_lex_ignored_newline(parser);
10069 lex_state_set(parser, PM_LEX_STATE_BEG);
10070 parser->
current.start = next_content;
10071 parser->
current.end = next_content + 2;
10074 LEX(PM_TOKEN_KEYWORD_OR);
10081 lex_state_set(parser, PM_LEX_STATE_BEG);
10083 parser->
current.type = PM_TOKEN_NEWLINE;
10084 if (!lexed_comment) parser_lex_callback(parser);
10094 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10095 LEX(PM_TOKEN_COMMA);
10099 pm_token_type_t
type = PM_TOKEN_PARENTHESIS_LEFT;
10101 if (space_seen && (lex_state_arg_p(parser) || parser->
lex_state == (PM_LEX_STATE_END | PM_LEX_STATE_LABEL))) {
10102 type = PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES;
10106 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10107 pm_do_loop_stack_push(parser,
false);
10114 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10115 pm_do_loop_stack_pop(parser);
10116 LEX(PM_TOKEN_PARENTHESIS_RIGHT);
10120 lex_state_set(parser, PM_LEX_STATE_BEG);
10122 LEX(PM_TOKEN_SEMICOLON);
10127 pm_token_type_t
type = PM_TOKEN_BRACKET_LEFT;
10129 if (lex_state_operator_p(parser)) {
10130 if (match(parser,
']')) {
10132 lex_state_set(parser, PM_LEX_STATE_ARG);
10133 LEX(match(parser,
'=') ? PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL : PM_TOKEN_BRACKET_LEFT_RIGHT);
10136 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABEL);
10140 if (lex_state_beg_p(parser) || (lex_state_arg_p(parser) && (space_seen || lex_state_p(parser, PM_LEX_STATE_LABELED)))) {
10141 type = PM_TOKEN_BRACKET_LEFT_ARRAY;
10144 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10145 pm_do_loop_stack_push(parser,
false);
10151 lex_state_set(parser, PM_LEX_STATE_END);
10152 pm_do_loop_stack_pop(parser);
10153 LEX(PM_TOKEN_BRACKET_RIGHT);
10157 pm_token_type_t
type = PM_TOKEN_BRACE_LEFT;
10162 lex_state_set(parser, PM_LEX_STATE_BEG);
10163 type = PM_TOKEN_LAMBDA_BEGIN;
10164 }
else if (lex_state_p(parser, PM_LEX_STATE_LABELED)) {
10166 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10167 }
else if (lex_state_p(parser, PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_END | PM_LEX_STATE_ENDFN)) {
10170 lex_state_set(parser, PM_LEX_STATE_BEG);
10171 }
else if (lex_state_p(parser, PM_LEX_STATE_ENDARG)) {
10174 lex_state_set(parser, PM_LEX_STATE_BEG);
10177 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10182 pm_do_loop_stack_push(parser,
false);
10190 pm_do_loop_stack_pop(parser);
10193 lex_mode_pop(parser);
10194 LEX(PM_TOKEN_EMBEXPR_END);
10198 lex_state_set(parser, PM_LEX_STATE_END);
10199 LEX(PM_TOKEN_BRACE_RIGHT);
10203 if (match(parser,
'*')) {
10204 if (match(parser,
'=')) {
10205 lex_state_set(parser, PM_LEX_STATE_BEG);
10206 LEX(PM_TOKEN_STAR_STAR_EQUAL);
10209 pm_token_type_t
type = PM_TOKEN_STAR_STAR;
10211 if (lex_state_spcarg_p(parser, space_seen)) {
10212 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR_STAR);
10213 type = PM_TOKEN_USTAR_STAR;
10214 }
else if (lex_state_beg_p(parser)) {
10215 type = PM_TOKEN_USTAR_STAR;
10216 }
else if (ambiguous_operator_p(parser, space_seen)) {
10217 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"**",
"argument prefix");
10220 if (lex_state_operator_p(parser)) {
10221 lex_state_set(parser, PM_LEX_STATE_ARG);
10223 lex_state_set(parser, PM_LEX_STATE_BEG);
10229 if (match(parser,
'=')) {
10230 lex_state_set(parser, PM_LEX_STATE_BEG);
10231 LEX(PM_TOKEN_STAR_EQUAL);
10234 pm_token_type_t
type = PM_TOKEN_STAR;
10236 if (lex_state_spcarg_p(parser, space_seen)) {
10237 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR);
10238 type = PM_TOKEN_USTAR;
10239 }
else if (lex_state_beg_p(parser)) {
10240 type = PM_TOKEN_USTAR;
10241 }
else if (ambiguous_operator_p(parser, space_seen)) {
10242 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"*",
"argument prefix");
10245 if (lex_state_operator_p(parser)) {
10246 lex_state_set(parser, PM_LEX_STATE_ARG);
10248 lex_state_set(parser, PM_LEX_STATE_BEG);
10256 if (lex_state_operator_p(parser)) {
10257 lex_state_set(parser, PM_LEX_STATE_ARG);
10258 if (match(parser,
'@')) {
10259 LEX(PM_TOKEN_BANG);
10262 lex_state_set(parser, PM_LEX_STATE_BEG);
10265 if (match(parser,
'=')) {
10266 LEX(PM_TOKEN_BANG_EQUAL);
10269 if (match(parser,
'~')) {
10270 LEX(PM_TOKEN_BANG_TILDE);
10273 LEX(PM_TOKEN_BANG);
10278 current_token_starts_line(parser) &&
10280 memcmp(parser->
current.end,
"begin", 5) == 0 &&
10281 (pm_char_is_whitespace(peek_offset(parser, 5)) || (peek_offset(parser, 5) ==
'\0'))
10283 pm_token_type_t
type = lex_embdoc(parser);
10284 if (
type == PM_TOKEN_EOF) {
10288 goto lex_next_token;
10291 if (lex_state_operator_p(parser)) {
10292 lex_state_set(parser, PM_LEX_STATE_ARG);
10294 lex_state_set(parser, PM_LEX_STATE_BEG);
10297 if (match(parser,
'>')) {
10298 LEX(PM_TOKEN_EQUAL_GREATER);
10301 if (match(parser,
'~')) {
10302 LEX(PM_TOKEN_EQUAL_TILDE);
10305 if (match(parser,
'=')) {
10306 LEX(match(parser,
'=') ? PM_TOKEN_EQUAL_EQUAL_EQUAL : PM_TOKEN_EQUAL_EQUAL);
10309 LEX(PM_TOKEN_EQUAL);
10313 if (match(parser,
'<')) {
10315 !lex_state_p(parser, PM_LEX_STATE_DOT | PM_LEX_STATE_CLASS) &&
10316 !lex_state_end_p(parser) &&
10317 (!lex_state_p(parser, PM_LEX_STATE_ARG_ANY) || lex_state_p(parser, PM_LEX_STATE_LABELED) || space_seen)
10319 const uint8_t *end = parser->
current.end;
10324 if (match(parser,
'-')) {
10325 indent = PM_HEREDOC_INDENT_DASH;
10327 else if (match(parser,
'~')) {
10328 indent = PM_HEREDOC_INDENT_TILDE;
10331 if (match(parser,
'`')) {
10332 quote = PM_HEREDOC_QUOTE_BACKTICK;
10334 else if (match(parser,
'"')) {
10335 quote = PM_HEREDOC_QUOTE_DOUBLE;
10337 else if (match(parser,
'\'')) {
10338 quote = PM_HEREDOC_QUOTE_SINGLE;
10341 const uint8_t *ident_start = parser->
current.end;
10346 }
else if (quote == PM_HEREDOC_QUOTE_NONE && (width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) == 0) {
10349 if (quote == PM_HEREDOC_QUOTE_NONE) {
10350 parser->
current.end += width;
10352 while ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end))) {
10353 parser->
current.end += width;
10359 if (*parser->
current.end ==
'\r' || *parser->
current.end ==
'\n')
break;
10364 size_t ident_length = (size_t) (parser->
current.end - ident_start);
10365 bool ident_error =
false;
10367 if (quote != PM_HEREDOC_QUOTE_NONE && !match(parser, (uint8_t) quote)) {
10368 pm_parser_err(parser, ident_start, ident_start + ident_length, PM_ERR_HEREDOC_IDENTIFIER);
10369 ident_error =
true;
10374 .mode = PM_LEX_HEREDOC,
10377 .ident_start = ident_start,
10378 .ident_length = ident_length,
10382 .next_start = parser->
current.end,
10384 .line_continuation =
false
10389 const uint8_t *body_start = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10391 if (body_start == NULL) {
10396 if (!ident_error) pm_parser_err_heredoc_term(parser, ident_start, ident_length);
10397 body_start = parser->
end;
10401 pm_newline_list_append(&parser->
newline_list, body_start);
10410 LEX(PM_TOKEN_HEREDOC_START);
10414 if (match(parser,
'=')) {
10415 lex_state_set(parser, PM_LEX_STATE_BEG);
10416 LEX(PM_TOKEN_LESS_LESS_EQUAL);
10419 if (ambiguous_operator_p(parser, space_seen)) {
10420 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"<<",
"here document");
10423 if (lex_state_operator_p(parser)) {
10424 lex_state_set(parser, PM_LEX_STATE_ARG);
10426 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
10427 lex_state_set(parser, PM_LEX_STATE_BEG);
10430 LEX(PM_TOKEN_LESS_LESS);
10433 if (lex_state_operator_p(parser)) {
10434 lex_state_set(parser, PM_LEX_STATE_ARG);
10436 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
10437 lex_state_set(parser, PM_LEX_STATE_BEG);
10440 if (match(parser,
'=')) {
10441 if (match(parser,
'>')) {
10442 LEX(PM_TOKEN_LESS_EQUAL_GREATER);
10445 LEX(PM_TOKEN_LESS_EQUAL);
10448 LEX(PM_TOKEN_LESS);
10452 if (match(parser,
'>')) {
10453 if (lex_state_operator_p(parser)) {
10454 lex_state_set(parser, PM_LEX_STATE_ARG);
10456 lex_state_set(parser, PM_LEX_STATE_BEG);
10458 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_GREATER_EQUAL : PM_TOKEN_GREATER_GREATER);
10461 if (lex_state_operator_p(parser)) {
10462 lex_state_set(parser, PM_LEX_STATE_ARG);
10464 lex_state_set(parser, PM_LEX_STATE_BEG);
10467 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_EQUAL : PM_TOKEN_GREATER);
10471 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
10472 lex_mode_push_string(parser,
true, label_allowed,
'\0',
'"');
10473 LEX(PM_TOKEN_STRING_BEGIN);
10478 if (lex_state_p(parser, PM_LEX_STATE_FNAME)) {
10479 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10480 LEX(PM_TOKEN_BACKTICK);
10483 if (lex_state_p(parser, PM_LEX_STATE_DOT)) {
10484 if (previous_command_start) {
10485 lex_state_set(parser, PM_LEX_STATE_CMDARG);
10487 lex_state_set(parser, PM_LEX_STATE_ARG);
10490 LEX(PM_TOKEN_BACKTICK);
10493 lex_mode_push_string(parser,
true,
false,
'\0',
'`');
10494 LEX(PM_TOKEN_BACKTICK);
10499 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
10500 lex_mode_push_string(parser,
false, label_allowed,
'\0',
'\'');
10501 LEX(PM_TOKEN_STRING_BEGIN);
10506 LEX(lex_question_mark(parser));
10510 if (match(parser,
'&')) {
10511 lex_state_set(parser, PM_LEX_STATE_BEG);
10513 if (match(parser,
'=')) {
10514 LEX(PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
10517 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
10520 if (match(parser,
'=')) {
10521 lex_state_set(parser, PM_LEX_STATE_BEG);
10522 LEX(PM_TOKEN_AMPERSAND_EQUAL);
10525 if (match(parser,
'.')) {
10526 lex_state_set(parser, PM_LEX_STATE_DOT);
10527 LEX(PM_TOKEN_AMPERSAND_DOT);
10530 pm_token_type_t
type = PM_TOKEN_AMPERSAND;
10531 if (lex_state_spcarg_p(parser, space_seen)) {
10532 if ((peek(parser) !=
':') || (peek_offset(parser, 1) ==
'\0')) {
10533 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
10535 const uint8_t delim = peek_offset(parser, 1);
10537 if ((delim !=
'\'') && (delim !=
'"') && !char_is_identifier(parser, parser->
current.end + 1, parser->
end - (parser->
current.end + 1))) {
10538 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
10542 type = PM_TOKEN_UAMPERSAND;
10543 }
else if (lex_state_beg_p(parser)) {
10544 type = PM_TOKEN_UAMPERSAND;
10545 }
else if (ambiguous_operator_p(parser, space_seen)) {
10546 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"&",
"argument prefix");
10549 if (lex_state_operator_p(parser)) {
10550 lex_state_set(parser, PM_LEX_STATE_ARG);
10552 lex_state_set(parser, PM_LEX_STATE_BEG);
10560 if (match(parser,
'|')) {
10561 if (match(parser,
'=')) {
10562 lex_state_set(parser, PM_LEX_STATE_BEG);
10563 LEX(PM_TOKEN_PIPE_PIPE_EQUAL);
10566 if (lex_state_p(parser, PM_LEX_STATE_BEG)) {
10568 LEX(PM_TOKEN_PIPE);
10571 lex_state_set(parser, PM_LEX_STATE_BEG);
10572 LEX(PM_TOKEN_PIPE_PIPE);
10575 if (match(parser,
'=')) {
10576 lex_state_set(parser, PM_LEX_STATE_BEG);
10577 LEX(PM_TOKEN_PIPE_EQUAL);
10580 if (lex_state_operator_p(parser)) {
10581 lex_state_set(parser, PM_LEX_STATE_ARG);
10583 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10586 LEX(PM_TOKEN_PIPE);
10590 if (lex_state_operator_p(parser)) {
10591 lex_state_set(parser, PM_LEX_STATE_ARG);
10593 if (match(parser,
'@')) {
10594 LEX(PM_TOKEN_UPLUS);
10597 LEX(PM_TOKEN_PLUS);
10600 if (match(parser,
'=')) {
10601 lex_state_set(parser, PM_LEX_STATE_BEG);
10602 LEX(PM_TOKEN_PLUS_EQUAL);
10606 lex_state_beg_p(parser) ||
10607 (lex_state_spcarg_p(parser, space_seen) ? (pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS),
true) : false)
10609 lex_state_set(parser, PM_LEX_STATE_BEG);
10611 if (pm_char_is_decimal_digit(peek(parser))) {
10613 pm_token_type_t
type = lex_numeric(parser);
10614 lex_state_set(parser, PM_LEX_STATE_END);
10618 LEX(PM_TOKEN_UPLUS);
10621 if (ambiguous_operator_p(parser, space_seen)) {
10622 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"+",
"unary operator");
10625 lex_state_set(parser, PM_LEX_STATE_BEG);
10626 LEX(PM_TOKEN_PLUS);
10631 if (lex_state_operator_p(parser)) {
10632 lex_state_set(parser, PM_LEX_STATE_ARG);
10634 if (match(parser,
'@')) {
10635 LEX(PM_TOKEN_UMINUS);
10638 LEX(PM_TOKEN_MINUS);
10641 if (match(parser,
'=')) {
10642 lex_state_set(parser, PM_LEX_STATE_BEG);
10643 LEX(PM_TOKEN_MINUS_EQUAL);
10646 if (match(parser,
'>')) {
10647 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10648 LEX(PM_TOKEN_MINUS_GREATER);
10651 bool spcarg = lex_state_spcarg_p(parser, space_seen);
10652 bool is_beg = lex_state_beg_p(parser);
10653 if (!is_beg && spcarg) {
10654 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS);
10657 if (is_beg || spcarg) {
10658 lex_state_set(parser, PM_LEX_STATE_BEG);
10659 LEX(pm_char_is_decimal_digit(peek(parser)) ? PM_TOKEN_UMINUS_NUM : PM_TOKEN_UMINUS);
10662 if (ambiguous_operator_p(parser, space_seen)) {
10663 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"-",
"unary operator");
10666 lex_state_set(parser, PM_LEX_STATE_BEG);
10667 LEX(PM_TOKEN_MINUS);
10672 bool beg_p = lex_state_beg_p(parser);
10674 if (match(parser,
'.')) {
10675 if (match(parser,
'.')) {
10678 if (lex_state_p(parser, PM_LEX_STATE_END)) {
10679 lex_state_set(parser, PM_LEX_STATE_BEG);
10681 lex_state_set(parser, PM_LEX_STATE_ENDARG);
10683 LEX(PM_TOKEN_UDOT_DOT_DOT);
10687 pm_parser_warn_token(parser, &parser->
current, PM_WARN_DOT_DOT_DOT_EOL);
10690 lex_state_set(parser, PM_LEX_STATE_BEG);
10691 LEX(beg_p ? PM_TOKEN_UDOT_DOT_DOT : PM_TOKEN_DOT_DOT_DOT);
10694 lex_state_set(parser, PM_LEX_STATE_BEG);
10695 LEX(beg_p ? PM_TOKEN_UDOT_DOT : PM_TOKEN_DOT_DOT);
10698 lex_state_set(parser, PM_LEX_STATE_DOT);
10713 pm_token_type_t
type = lex_numeric(parser);
10714 lex_state_set(parser, PM_LEX_STATE_END);
10720 if (match(parser,
':')) {
10721 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)) {
10722 lex_state_set(parser, PM_LEX_STATE_BEG);
10723 LEX(PM_TOKEN_UCOLON_COLON);
10726 lex_state_set(parser, PM_LEX_STATE_DOT);
10727 LEX(PM_TOKEN_COLON_COLON);
10730 if (lex_state_end_p(parser) || pm_char_is_whitespace(peek(parser)) || peek(parser) ==
'#') {
10731 lex_state_set(parser, PM_LEX_STATE_BEG);
10732 LEX(PM_TOKEN_COLON);
10735 if (peek(parser) ==
'"' || peek(parser) ==
'\'') {
10736 lex_mode_push_string(parser, peek(parser) ==
'"',
false,
'\0', *parser->
current.end);
10740 lex_state_set(parser, PM_LEX_STATE_FNAME);
10741 LEX(PM_TOKEN_SYMBOL_BEGIN);
10745 if (lex_state_beg_p(parser)) {
10746 lex_mode_push_regexp(parser,
'\0',
'/');
10747 LEX(PM_TOKEN_REGEXP_BEGIN);
10750 if (match(parser,
'=')) {
10751 lex_state_set(parser, PM_LEX_STATE_BEG);
10752 LEX(PM_TOKEN_SLASH_EQUAL);
10755 if (lex_state_spcarg_p(parser, space_seen)) {
10756 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_SLASH);
10757 lex_mode_push_regexp(parser,
'\0',
'/');
10758 LEX(PM_TOKEN_REGEXP_BEGIN);
10761 if (ambiguous_operator_p(parser, space_seen)) {
10762 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"/",
"regexp literal");
10765 if (lex_state_operator_p(parser)) {
10766 lex_state_set(parser, PM_LEX_STATE_ARG);
10768 lex_state_set(parser, PM_LEX_STATE_BEG);
10771 LEX(PM_TOKEN_SLASH);
10775 if (lex_state_operator_p(parser)) {
10776 lex_state_set(parser, PM_LEX_STATE_ARG);
10778 lex_state_set(parser, PM_LEX_STATE_BEG);
10780 LEX(match(parser,
'=') ? PM_TOKEN_CARET_EQUAL : PM_TOKEN_CARET);
10784 if (lex_state_operator_p(parser)) {
10785 (void) match(parser,
'@');
10786 lex_state_set(parser, PM_LEX_STATE_ARG);
10788 lex_state_set(parser, PM_LEX_STATE_BEG);
10791 LEX(PM_TOKEN_TILDE);
10799 if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->
current.end >= parser->
end)) {
10800 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT_EOF);
10801 LEX(PM_TOKEN_PERCENT);
10804 if (!lex_state_beg_p(parser) && match(parser,
'=')) {
10805 lex_state_set(parser, PM_LEX_STATE_BEG);
10806 LEX(PM_TOKEN_PERCENT_EQUAL);
10808 lex_state_beg_p(parser) ||
10809 (lex_state_p(parser, PM_LEX_STATE_FITEM) && (peek(parser) ==
's')) ||
10810 lex_state_spcarg_p(parser, space_seen)
10813 if (*parser->
current.end >= 0x80) {
10814 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
10817 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10818 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10819 LEX(PM_TOKEN_STRING_BEGIN);
10824 uint8_t delimiter = peek_offset(parser, 1);
10826 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
10827 goto lex_next_token;
10830 switch (peek(parser)) {
10835 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
10837 lex_mode_push_list_eof(parser);
10840 LEX(PM_TOKEN_PERCENT_LOWER_I);
10846 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
10848 lex_mode_push_list_eof(parser);
10851 LEX(PM_TOKEN_PERCENT_UPPER_I);
10857 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10858 lex_mode_push_regexp(parser, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10860 lex_mode_push_regexp(parser,
'\0',
'\0');
10863 LEX(PM_TOKEN_REGEXP_BEGIN);
10869 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10870 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10872 lex_mode_push_string_eof(parser);
10875 LEX(PM_TOKEN_STRING_BEGIN);
10881 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10882 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10884 lex_mode_push_string_eof(parser);
10887 LEX(PM_TOKEN_STRING_BEGIN);
10893 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10894 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10895 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
10897 lex_mode_push_string_eof(parser);
10900 LEX(PM_TOKEN_SYMBOL_BEGIN);
10906 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
10908 lex_mode_push_list_eof(parser);
10911 LEX(PM_TOKEN_PERCENT_LOWER_W);
10917 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
10919 lex_mode_push_list_eof(parser);
10922 LEX(PM_TOKEN_PERCENT_UPPER_W);
10928 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10929 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10931 lex_mode_push_string_eof(parser);
10934 LEX(PM_TOKEN_PERCENT_LOWER_X);
10941 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
10942 goto lex_next_token;
10946 if (ambiguous_operator_p(parser, space_seen)) {
10947 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"%",
"string literal");
10950 lex_state_set(parser, lex_state_operator_p(parser) ? PM_LEX_STATE_ARG : PM_LEX_STATE_BEG);
10951 LEX(PM_TOKEN_PERCENT);
10956 pm_token_type_t
type = lex_global_variable(parser);
10961 lex_mode_pop(parser);
10964 lex_state_set(parser, PM_LEX_STATE_END);
10970 lex_state_set(parser, parser->
lex_state & PM_LEX_STATE_FNAME ? PM_LEX_STATE_ENDFN : PM_LEX_STATE_END);
10971 LEX(lex_at_variable(parser));
10974 if (*parser->
current.start !=
'_') {
10975 size_t width = char_is_identifier_start(parser, parser->
current.start, parser->
end - parser->
current.start);
10982 if (*parser->
current.start >= 0x80) {
10983 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *parser->
current.start);
10984 }
else if (*parser->
current.start ==
'\\') {
10985 switch (peek_at(parser, parser->
current.start + 1)) {
10988 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped space");
10992 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped form feed");
10996 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped horizontal tab");
11000 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped vertical tab");
11003 if (peek_at(parser, parser->
current.start + 2) !=
'\n') {
11005 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped carriage return");
11010 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"backslash");
11013 }
else if (char_is_ascii_printable(*parser->
current.start)) {
11014 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_PRINTABLE_CHARACTER, *parser->
current.start);
11016 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_CHARACTER, *parser->
current.start);
11019 goto lex_next_token;
11025 pm_token_type_t
type = lex_identifier(parser, previous_command_start);
11033 current_token_starts_line(parser) &&
11034 (memcmp(parser->
current.start,
"__END__", 7) == 0) &&
11035 (parser->
current.end == parser->
end || match_eol(parser))
11040 const uint8_t *cursor = parser->
current.end;
11041 while ((cursor = next_newline(cursor, parser->
end - cursor)) != NULL) {
11042 pm_newline_list_append(&parser->
newline_list, cursor++);
11046 parser->
current.type = PM_TOKEN___END__;
11047 parser_lex_callback(parser);
11057 if (
type == PM_TOKEN_IDENTIFIER ||
type == PM_TOKEN_CONSTANT ||
type == PM_TOKEN_METHOD_NAME) {
11058 if (lex_state_p(parser, PM_LEX_STATE_BEG_ANY | PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_DOT)) {
11059 if (previous_command_start) {
11060 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11062 lex_state_set(parser, PM_LEX_STATE_ARG);
11064 }
else if (parser->
lex_state == PM_LEX_STATE_FNAME) {
11065 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11067 lex_state_set(parser, PM_LEX_STATE_END);
11072 !(last_state & (PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME)) &&
11073 (
type == PM_TOKEN_IDENTIFIER) &&
11074 ((pm_parser_local_depth(parser, &parser->
current) != -1) ||
11075 pm_token_is_numbered_parameter(parser->
current.start, parser->
current.end))
11077 lex_state_set(parser, PM_LEX_STATE_END | PM_LEX_STATE_LABEL);
11084 case PM_LEX_LIST: {
11098 whitespace = pm_strspn_inline_whitespace(parser->
current.end, parser->
end - parser->
current.end);
11099 if (peek_offset(parser, (ptrdiff_t)whitespace) ==
'\n') {
11106 if (whitespace > 0) {
11107 parser->
current.end += whitespace;
11108 if (peek_offset(parser, -1) ==
'\n') {
11110 parser_flush_heredoc_end(parser);
11112 LEX(PM_TOKEN_WORDS_SEP);
11124 const uint8_t *breakpoints = lex_mode->
as.list.
breakpoints;
11125 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11131 while (breakpoint != NULL) {
11134 if (pm_char_is_whitespace(*breakpoint)) {
11135 parser->
current.end = breakpoint;
11136 pm_token_buffer_flush(parser, &token_buffer);
11137 LEX(PM_TOKEN_STRING_CONTENT);
11146 parser->
current.end = breakpoint + 1;
11147 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11154 if (breakpoint > parser->
current.start) {
11155 parser->
current.end = breakpoint;
11156 pm_token_buffer_flush(parser, &token_buffer);
11157 LEX(PM_TOKEN_STRING_CONTENT);
11162 parser->
current.end = breakpoint + 1;
11163 lex_mode_pop(parser);
11164 lex_state_set(parser, PM_LEX_STATE_END);
11165 LEX(PM_TOKEN_STRING_END);
11169 if (*breakpoint ==
'\0') {
11170 breakpoint = pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->
end - (breakpoint + 1),
true);
11177 if (*breakpoint ==
'\\') {
11178 parser->
current.end = breakpoint + 1;
11187 pm_token_buffer_escape(parser, &token_buffer);
11188 uint8_t peeked = peek(parser);
11196 pm_token_buffer_push_byte(&token_buffer, peeked);
11201 if (peek(parser) !=
'\n') {
11202 pm_token_buffer_push_byte(&token_buffer,
'\r');
11207 pm_token_buffer_push_byte(&token_buffer,
'\n');
11213 parser_flush_heredoc_end(parser);
11214 pm_token_buffer_copy(parser, &token_buffer);
11215 LEX(PM_TOKEN_STRING_CONTENT);
11225 pm_token_buffer_push_byte(&token_buffer, peeked);
11228 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
11230 pm_token_buffer_push_byte(&token_buffer,
'\\');
11231 pm_token_buffer_push_escaped(&token_buffer, parser);
11238 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11243 if (*breakpoint ==
'#') {
11244 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11246 if (
type == PM_TOKEN_NOT_PROVIDED) {
11251 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11255 if (
type == PM_TOKEN_STRING_CONTENT) {
11256 pm_token_buffer_flush(parser, &token_buffer);
11265 parser->
current.end = breakpoint + 1;
11266 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11272 pm_token_buffer_flush(parser, &token_buffer);
11273 LEX(PM_TOKEN_STRING_CONTENT);
11279 pm_token_buffer_flush(parser, &token_buffer);
11280 LEX(PM_TOKEN_STRING_CONTENT);
11282 case PM_LEX_REGEXP: {
11304 const uint8_t *breakpoints = lex_mode->
as.regexp.
breakpoints;
11305 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11308 while (breakpoint != NULL) {
11310 bool is_terminator = (*breakpoint == term);
11315 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
11316 if (term ==
'\n') {
11317 is_terminator =
true;
11323 if (term ==
'\r') {
11324 is_terminator =
false;
11330 if (is_terminator) {
11332 parser->
current.end = breakpoint + 1;
11333 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11341 if (breakpoint > parser->
current.start) {
11342 parser->
current.end = breakpoint;
11343 pm_regexp_token_buffer_flush(parser, &token_buffer);
11344 LEX(PM_TOKEN_STRING_CONTENT);
11348 size_t eol_length = match_eol_at(parser, breakpoint);
11350 parser->
current.end = breakpoint + eol_length;
11359 parser->
current.end = breakpoint + 1;
11366 lex_mode_pop(parser);
11367 lex_state_set(parser, PM_LEX_STATE_END);
11368 LEX(PM_TOKEN_REGEXP_END);
11373 if (*breakpoint && *breakpoint == lex_mode->
as.regexp.
incrementor) {
11374 parser->
current.end = breakpoint + 1;
11375 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11380 switch (*breakpoint) {
11383 parser->
current.end = breakpoint + 1;
11384 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11387 if (peek_at(parser, breakpoint + 1) !=
'\n') {
11388 parser->
current.end = breakpoint + 1;
11389 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11394 parser->
current.end = breakpoint;
11395 pm_regexp_token_buffer_escape(parser, &token_buffer);
11403 pm_newline_list_append(&parser->
newline_list, breakpoint);
11404 parser->
current.end = breakpoint + 1;
11405 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11409 parser->
current.end = breakpoint + 1;
11410 parser_flush_heredoc_end(parser);
11411 pm_regexp_token_buffer_flush(parser, &token_buffer);
11412 LEX(PM_TOKEN_STRING_CONTENT);
11417 parser->
current.end = breakpoint + 1;
11426 pm_regexp_token_buffer_escape(parser, &token_buffer);
11427 uint8_t peeked = peek(parser);
11432 if (peek(parser) !=
'\n') {
11434 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11436 pm_regexp_token_buffer_push_byte(&token_buffer,
'\r');
11437 pm_token_buffer_push_byte(&token_buffer.
base,
'\r');
11446 parser_flush_heredoc_end(parser);
11447 pm_regexp_token_buffer_copy(parser, &token_buffer);
11448 LEX(PM_TOKEN_STRING_CONTENT);
11469 case '$':
case ')':
case '*':
case '+':
11470 case '.':
case '>':
case '?':
case ']':
11471 case '^':
case '|':
case '}':
11472 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11478 pm_regexp_token_buffer_push_byte(&token_buffer, peeked);
11479 pm_token_buffer_push_byte(&token_buffer.
base, peeked);
11484 if (peeked < 0x80) pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11485 pm_regexp_token_buffer_push_escaped(&token_buffer, parser);
11490 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11496 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11498 if (
type == PM_TOKEN_NOT_PROVIDED) {
11503 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11507 if (
type == PM_TOKEN_STRING_CONTENT) {
11508 pm_regexp_token_buffer_flush(parser, &token_buffer);
11514 assert(
false &&
"unreachable");
11520 pm_regexp_token_buffer_flush(parser, &token_buffer);
11521 LEX(PM_TOKEN_STRING_CONTENT);
11527 pm_regexp_token_buffer_flush(parser, &token_buffer);
11528 LEX(PM_TOKEN_STRING_CONTENT);
11530 case PM_LEX_STRING: {
11549 const uint8_t *breakpoints = lex_mode->
as.string.
breakpoints;
11550 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11556 while (breakpoint != NULL) {
11561 parser->
current.end = breakpoint + 1;
11562 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11567 bool is_terminator = (*breakpoint == term);
11572 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
11573 if (term ==
'\n') {
11574 is_terminator =
true;
11580 if (term ==
'\r') {
11581 is_terminator =
false;
11588 if (is_terminator) {
11592 parser->
current.end = breakpoint + 1;
11593 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11600 if (breakpoint > parser->
current.start) {
11601 parser->
current.end = breakpoint;
11602 pm_token_buffer_flush(parser, &token_buffer);
11603 LEX(PM_TOKEN_STRING_CONTENT);
11608 size_t eol_length = match_eol_at(parser, breakpoint);
11610 parser->
current.end = breakpoint + eol_length;
11619 parser->
current.end = breakpoint + 1;
11622 if (lex_mode->
as.string.
label_allowed && (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')) {
11624 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
11625 lex_mode_pop(parser);
11626 LEX(PM_TOKEN_LABEL_END);
11633 parser_flush_heredoc_end(parser);
11636 lex_state_set(parser, PM_LEX_STATE_END);
11637 lex_mode_pop(parser);
11638 LEX(PM_TOKEN_STRING_END);
11641 switch (*breakpoint) {
11644 parser->
current.end = breakpoint + 1;
11645 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11648 if (peek_at(parser, breakpoint + 1) !=
'\n') {
11649 parser->
current.end = breakpoint + 1;
11650 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11657 parser->
current.end = breakpoint;
11658 pm_token_buffer_escape(parser, &token_buffer);
11659 token_buffer.
cursor = breakpoint;
11668 pm_newline_list_append(&parser->
newline_list, breakpoint);
11669 parser->
current.end = breakpoint + 1;
11670 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11674 parser->
current.end = breakpoint + 1;
11675 parser_flush_heredoc_end(parser);
11676 pm_token_buffer_flush(parser, &token_buffer);
11677 LEX(PM_TOKEN_STRING_CONTENT);
11680 parser->
current.end = breakpoint + 1;
11689 pm_token_buffer_escape(parser, &token_buffer);
11690 uint8_t peeked = peek(parser);
11694 pm_token_buffer_push_byte(&token_buffer,
'\\');
11699 if (peek(parser) !=
'\n') {
11701 pm_token_buffer_push_byte(&token_buffer,
'\\');
11703 pm_token_buffer_push_byte(&token_buffer,
'\r');
11709 pm_token_buffer_push_byte(&token_buffer,
'\\');
11710 pm_token_buffer_push_byte(&token_buffer,
'\n');
11717 parser_flush_heredoc_end(parser);
11718 pm_token_buffer_copy(parser, &token_buffer);
11719 LEX(PM_TOKEN_STRING_CONTENT);
11729 pm_token_buffer_push_byte(&token_buffer, peeked);
11732 pm_token_buffer_push_byte(&token_buffer, peeked);
11735 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
11737 pm_token_buffer_push_byte(&token_buffer,
'\\');
11738 pm_token_buffer_push_escaped(&token_buffer, parser);
11745 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11749 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11751 if (
type == PM_TOKEN_NOT_PROVIDED) {
11756 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11760 if (
type == PM_TOKEN_STRING_CONTENT) {
11761 pm_token_buffer_flush(parser, &token_buffer);
11767 assert(
false &&
"unreachable");
11772 pm_token_buffer_flush(parser, &token_buffer);
11773 LEX(PM_TOKEN_STRING_CONTENT);
11779 pm_token_buffer_flush(parser, &token_buffer);
11780 LEX(PM_TOKEN_STRING_CONTENT);
11782 case PM_LEX_HEREDOC: {
11809 lex_state_set(parser, PM_LEX_STATE_END);
11810 lex_mode_pop(parser);
11811 LEX(PM_TOKEN_HEREDOC_END);
11814 const uint8_t *ident_start = heredoc_lex_mode->
ident_start;
11819 if (current_token_starts_line(parser)) {
11820 const uint8_t *start = parser->
current.start;
11822 if (!line_continuation && (start + ident_length <= parser->end)) {
11823 const uint8_t *newline = next_newline(start, parser->
end - start);
11824 const uint8_t *ident_end = newline;
11825 const uint8_t *terminator_end = newline;
11827 if (newline == NULL) {
11828 terminator_end = parser->
end;
11829 ident_end = parser->
end;
11832 if (newline[-1] ==
'\r') {
11837 const uint8_t *terminator_start = ident_end - ident_length;
11838 const uint8_t *cursor = start;
11840 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
11841 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
11847 (cursor == terminator_start) &&
11848 (memcmp(terminator_start, ident_start, ident_length) == 0)
11850 if (newline != NULL) {
11851 pm_newline_list_append(&parser->
newline_list, newline);
11854 parser->
current.end = terminator_end;
11862 lex_state_set(parser, PM_LEX_STATE_END);
11863 lex_mode_pop(parser);
11864 LEX(PM_TOKEN_HEREDOC_END);
11868 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, heredoc_lex_mode->
indent);
11870 heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE &&
11873 peek_at(parser, start) !=
'\n'
11882 uint8_t breakpoints[] =
"\r\n\\#";
11885 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
11886 breakpoints[3] =
'\0';
11889 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11891 bool was_line_continuation =
false;
11893 while (breakpoint != NULL) {
11894 switch (*breakpoint) {
11897 parser->
current.end = breakpoint + 1;
11898 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11901 parser->
current.end = breakpoint + 1;
11903 if (peek_at(parser, breakpoint + 1) !=
'\n') {
11904 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11911 pm_token_buffer_escape(parser, &token_buffer);
11912 token_buffer.
cursor = breakpoint;
11917 parser_flush_heredoc_end(parser);
11918 parser->
current.end = breakpoint + 1;
11919 pm_token_buffer_flush(parser, &token_buffer);
11920 LEX(PM_TOKEN_STRING_CONTENT);
11923 pm_newline_list_append(&parser->
newline_list, breakpoint);
11927 const uint8_t *start = breakpoint + 1;
11929 if (!was_line_continuation && (start + ident_length <= parser->end)) {
11932 const uint8_t *newline = next_newline(start, parser->
end - start);
11934 if (newline == NULL) {
11935 newline = parser->
end;
11936 }
else if (newline[-1] ==
'\r') {
11941 const uint8_t *terminator_start = newline - ident_length;
11945 const uint8_t *cursor = start;
11947 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
11948 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
11954 cursor == terminator_start &&
11955 (memcmp(terminator_start, ident_start, ident_length) == 0)
11957 parser->
current.end = breakpoint + 1;
11958 pm_token_buffer_flush(parser, &token_buffer);
11959 LEX(PM_TOKEN_STRING_CONTENT);
11963 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->
as.heredoc.
base.
indent);
11970 if (lex_mode->
as.heredoc.
base.
indent == PM_HEREDOC_INDENT_TILDE) {
11975 parser->
current.end = breakpoint + 1;
11976 pm_token_buffer_flush(parser, &token_buffer);
11977 LEX(PM_TOKEN_STRING_CONTENT);
11982 parser->
current.end = breakpoint + 1;
11983 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11993 parser->
current.end = breakpoint + 1;
12002 pm_token_buffer_escape(parser, &token_buffer);
12003 uint8_t peeked = peek(parser);
12005 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12009 if (peek(parser) !=
'\n') {
12010 pm_token_buffer_push_byte(&token_buffer,
'\\');
12011 pm_token_buffer_push_byte(&token_buffer,
'\r');
12016 pm_token_buffer_push_byte(&token_buffer,
'\\');
12017 pm_token_buffer_push_byte(&token_buffer,
'\n');
12019 breakpoint = parser->
current.end;
12022 pm_token_buffer_push_byte(&token_buffer,
'\\');
12023 pm_token_buffer_push_escaped(&token_buffer, parser);
12030 if (peek(parser) !=
'\n') {
12031 pm_token_buffer_push_byte(&token_buffer,
'\r');
12039 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12040 const uint8_t *end = parser->
current.end;
12048 parser->
current.end = breakpoint;
12049 pm_token_buffer_flush(parser, &token_buffer);
12053 parser->
current.end = end + 1;
12055 LEX(PM_TOKEN_STRING_CONTENT);
12058 was_line_continuation =
true;
12060 breakpoint = parser->
current.end;
12063 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12069 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12073 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12075 if (
type == PM_TOKEN_NOT_PROVIDED) {
12081 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12085 if (
type == PM_TOKEN_STRING_CONTENT) {
12086 pm_token_buffer_flush(parser, &token_buffer);
12092 assert(
false &&
"unreachable");
12095 was_line_continuation =
false;
12100 pm_token_buffer_flush(parser, &token_buffer);
12101 LEX(PM_TOKEN_STRING_CONTENT);
12107 pm_token_buffer_flush(parser, &token_buffer);
12108 LEX(PM_TOKEN_STRING_CONTENT);
12112 assert(
false &&
"unreachable");
12130 PM_BINDING_POWER_UNSET = 0,
12131 PM_BINDING_POWER_STATEMENT = 2,
12132 PM_BINDING_POWER_MODIFIER_RESCUE = 4,
12133 PM_BINDING_POWER_MODIFIER = 6,
12134 PM_BINDING_POWER_COMPOSITION = 8,
12135 PM_BINDING_POWER_NOT = 10,
12136 PM_BINDING_POWER_MATCH = 12,
12137 PM_BINDING_POWER_DEFINED = 14,
12138 PM_BINDING_POWER_MULTI_ASSIGNMENT = 16,
12139 PM_BINDING_POWER_ASSIGNMENT = 18,
12140 PM_BINDING_POWER_TERNARY = 20,
12141 PM_BINDING_POWER_RANGE = 22,
12142 PM_BINDING_POWER_LOGICAL_OR = 24,
12143 PM_BINDING_POWER_LOGICAL_AND = 26,
12144 PM_BINDING_POWER_EQUALITY = 28,
12145 PM_BINDING_POWER_COMPARISON = 30,
12146 PM_BINDING_POWER_BITWISE_OR = 32,
12147 PM_BINDING_POWER_BITWISE_AND = 34,
12148 PM_BINDING_POWER_SHIFT = 36,
12149 PM_BINDING_POWER_TERM = 38,
12150 PM_BINDING_POWER_FACTOR = 40,
12151 PM_BINDING_POWER_UMINUS = 42,
12152 PM_BINDING_POWER_EXPONENT = 44,
12153 PM_BINDING_POWER_UNARY = 46,
12154 PM_BINDING_POWER_INDEX = 48,
12155 PM_BINDING_POWER_CALL = 50,
12156 PM_BINDING_POWER_MAX = 52
12157} pm_binding_power_t;
12180#define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true, false }
12181#define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, false }
12182#define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true, false }
12183#define NON_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, true }
12184#define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false, false }
12188 [PM_TOKEN_KEYWORD_RESCUE_MODIFIER] = { PM_BINDING_POWER_MODIFIER_RESCUE, PM_BINDING_POWER_COMPOSITION,
true,
false },
12191 [PM_TOKEN_KEYWORD_IF_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12192 [PM_TOKEN_KEYWORD_UNLESS_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12193 [PM_TOKEN_KEYWORD_UNTIL_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12194 [PM_TOKEN_KEYWORD_WHILE_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12197 [PM_TOKEN_KEYWORD_AND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
12198 [PM_TOKEN_KEYWORD_OR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
12201 [PM_TOKEN_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
12202 [PM_TOKEN_KEYWORD_IN] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
12205 [PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
12206 [PM_TOKEN_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
12207 [PM_TOKEN_CARET_EQUAL] = BINDING_POWER_ASSIGNMENT,
12208 [PM_TOKEN_EQUAL] = BINDING_POWER_ASSIGNMENT,
12209 [PM_TOKEN_GREATER_GREATER_EQUAL] = BINDING_POWER_ASSIGNMENT,
12210 [PM_TOKEN_LESS_LESS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12211 [PM_TOKEN_MINUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12212 [PM_TOKEN_PERCENT_EQUAL] = BINDING_POWER_ASSIGNMENT,
12213 [PM_TOKEN_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
12214 [PM_TOKEN_PIPE_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
12215 [PM_TOKEN_PLUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12216 [PM_TOKEN_SLASH_EQUAL] = BINDING_POWER_ASSIGNMENT,
12217 [PM_TOKEN_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
12218 [PM_TOKEN_STAR_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
12221 [PM_TOKEN_QUESTION_MARK] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_TERNARY),
12224 [PM_TOKEN_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
12225 [PM_TOKEN_DOT_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
12226 [PM_TOKEN_UDOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
12227 [PM_TOKEN_UDOT_DOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
12230 [PM_TOKEN_PIPE_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_OR),
12233 [PM_TOKEN_AMPERSAND_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_AND),
12236 [PM_TOKEN_BANG_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12237 [PM_TOKEN_BANG_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12238 [PM_TOKEN_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12239 [PM_TOKEN_EQUAL_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12240 [PM_TOKEN_EQUAL_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12241 [PM_TOKEN_LESS_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12244 [PM_TOKEN_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12245 [PM_TOKEN_GREATER_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12246 [PM_TOKEN_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12247 [PM_TOKEN_LESS_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12250 [PM_TOKEN_CARET] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12251 [PM_TOKEN_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12254 [PM_TOKEN_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_AND),
12257 [PM_TOKEN_GREATER_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
12258 [PM_TOKEN_LESS_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
12261 [PM_TOKEN_MINUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
12262 [PM_TOKEN_PLUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
12265 [PM_TOKEN_PERCENT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12266 [PM_TOKEN_SLASH] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12267 [PM_TOKEN_STAR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12268 [PM_TOKEN_USTAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_FACTOR),
12271 [PM_TOKEN_UMINUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UMINUS),
12272 [PM_TOKEN_UMINUS_NUM] = { PM_BINDING_POWER_UMINUS, PM_BINDING_POWER_MAX,
false,
false },
12275 [PM_TOKEN_STAR_STAR] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_EXPONENT),
12276 [PM_TOKEN_USTAR_STAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12279 [PM_TOKEN_BANG] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12280 [PM_TOKEN_TILDE] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12281 [PM_TOKEN_UPLUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12284 [PM_TOKEN_BRACKET_LEFT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_INDEX),
12287 [PM_TOKEN_COLON_COLON] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
12288 [PM_TOKEN_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
12289 [PM_TOKEN_AMPERSAND_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL)
12292#undef BINDING_POWER_ASSIGNMENT
12293#undef LEFT_ASSOCIATIVE
12294#undef RIGHT_ASSOCIATIVE
12295#undef RIGHT_ASSOCIATIVE_UNARY
12309match2(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
12310 return match1(parser, type1) || match1(parser, type2);
12317match3(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3) {
12318 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3);
12325match4(
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) {
12326 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4);
12333match7(
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) {
12334 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7);
12341match8(
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) {
12342 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);
12353 if (match1(parser,
type)) {
12354 parser_lex(parser);
12365accept2(
pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
12366 if (match2(parser, type1, type2)) {
12367 parser_lex(parser);
12386 if (accept1(parser,
type))
return;
12389 pm_parser_err(parser, location, location, diag_id);
12401 if (accept2(parser, type1, type2))
return;
12404 pm_parser_err(parser, location, location, diag_id);
12415expect1_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
12416 if (match1(parser, PM_TOKEN_HEREDOC_END)) {
12417 parser_lex(parser);
12419 pm_parser_err_heredoc_term(parser, ident_start, ident_length);
12426parse_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);
12433parse_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) {
12434 pm_node_t *node = parse_expression(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
12435 pm_assert_value_expression(parser, node);
12458token_begins_expression_p(pm_token_type_t
type) {
12460 case PM_TOKEN_EQUAL_GREATER:
12461 case PM_TOKEN_KEYWORD_IN:
12465 case PM_TOKEN_BRACE_RIGHT:
12466 case PM_TOKEN_BRACKET_RIGHT:
12467 case PM_TOKEN_COLON:
12468 case PM_TOKEN_COMMA:
12469 case PM_TOKEN_EMBEXPR_END:
12471 case PM_TOKEN_LAMBDA_BEGIN:
12472 case PM_TOKEN_KEYWORD_DO:
12473 case PM_TOKEN_KEYWORD_DO_LOOP:
12474 case PM_TOKEN_KEYWORD_END:
12475 case PM_TOKEN_KEYWORD_ELSE:
12476 case PM_TOKEN_KEYWORD_ELSIF:
12477 case PM_TOKEN_KEYWORD_ENSURE:
12478 case PM_TOKEN_KEYWORD_THEN:
12479 case PM_TOKEN_KEYWORD_RESCUE:
12480 case PM_TOKEN_KEYWORD_WHEN:
12481 case PM_TOKEN_NEWLINE:
12482 case PM_TOKEN_PARENTHESIS_RIGHT:
12483 case PM_TOKEN_SEMICOLON:
12489 assert(pm_binding_powers[
type].left == PM_BINDING_POWER_UNSET);
12491 case PM_TOKEN_UAMPERSAND:
12495 case PM_TOKEN_UCOLON_COLON:
12496 case PM_TOKEN_UMINUS:
12497 case PM_TOKEN_UMINUS_NUM:
12498 case PM_TOKEN_UPLUS:
12499 case PM_TOKEN_BANG:
12500 case PM_TOKEN_TILDE:
12501 case PM_TOKEN_UDOT_DOT:
12502 case PM_TOKEN_UDOT_DOT_DOT:
12509 return pm_binding_powers[
type].
left == PM_BINDING_POWER_UNSET;
12518parse_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) {
12519 if (accept1(parser, PM_TOKEN_USTAR)) {
12521 pm_node_t *expression = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
12522 return UP(pm_splat_node_create(parser, &
operator, expression));
12525 return parse_value_expression(parser, binding_power, accepts_command_call,
false, diag_id, depth);
12529pm_node_unreference_each(
const pm_node_t *node,
void *data) {
12530 switch (PM_NODE_TYPE(node)) {
12535 case PM_BREAK_NODE:
12537 case PM_REDO_NODE: {
12541 while (index < parser->current_block_exits->size) {
12544 if (block_exit == node) {
12567 case PM_LOCAL_VARIABLE_READ_NODE:
12568 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
12572 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
12573 if (implicit_parameters->
nodes[index] == node) {
12577 if (index != implicit_parameters->
size - 1) {
12578 memmove(&implicit_parameters->
nodes[index], &implicit_parameters->
nodes[index + 1], (implicit_parameters->
size - index - 1) *
sizeof(
pm_node_t *));
12581 implicit_parameters->
size--;
12600 pm_visit_node(node, pm_node_unreference_each, parser);
12614 size_t length = constant->
length;
12615 uint8_t *name =
xcalloc(length + 1,
sizeof(uint8_t));
12616 if (name == NULL)
return;
12618 memcpy(name, constant->
start, length);
12619 name[length] =
'=';
12624 *name_field = pm_constant_pool_insert_owned(&parser->
constant_pool, name, length + 1);
12635 switch (PM_NODE_TYPE(target)) {
12636 case PM_SOURCE_ENCODING_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
12637 case PM_FALSE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
12638 case PM_SOURCE_FILE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
12639 case PM_SOURCE_LINE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
12640 case PM_NIL_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
12641 case PM_SELF_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
12642 case PM_TRUE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
12649 pm_node_destroy(parser, target);
12663 switch (PM_NODE_TYPE(target)) {
12664 case PM_MISSING_NODE:
12666 case PM_SOURCE_ENCODING_NODE:
12667 case PM_FALSE_NODE:
12668 case PM_SOURCE_FILE_NODE:
12669 case PM_SOURCE_LINE_NODE:
12672 case PM_TRUE_NODE: {
12675 return parse_unwriteable_target(parser, target);
12677 case PM_CLASS_VARIABLE_READ_NODE:
12679 target->
type = PM_CLASS_VARIABLE_TARGET_NODE;
12681 case PM_CONSTANT_PATH_NODE:
12682 if (context_def_p(parser)) {
12683 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
12687 target->
type = PM_CONSTANT_PATH_TARGET_NODE;
12690 case PM_CONSTANT_READ_NODE:
12691 if (context_def_p(parser)) {
12692 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
12696 target->
type = PM_CONSTANT_TARGET_NODE;
12699 case PM_BACK_REFERENCE_READ_NODE:
12700 case PM_NUMBERED_REFERENCE_READ_NODE:
12701 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
12703 case PM_GLOBAL_VARIABLE_READ_NODE:
12705 target->
type = PM_GLOBAL_VARIABLE_TARGET_NODE;
12707 case PM_LOCAL_VARIABLE_READ_NODE: {
12710 pm_node_unreference(parser, target);
12714 uint32_t name = cast->
name;
12715 uint32_t depth = cast->
depth;
12716 pm_locals_unread(&pm_parser_scope_find(parser, depth)->locals, name);
12719 target->
type = PM_LOCAL_VARIABLE_TARGET_NODE;
12723 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
12725 pm_node_t *node = UP(pm_local_variable_target_node_create(parser, &target->
location, name, 0));
12727 pm_node_unreference(parser, target);
12728 pm_node_destroy(parser, target);
12732 case PM_INSTANCE_VARIABLE_READ_NODE:
12734 target->
type = PM_INSTANCE_VARIABLE_TARGET_NODE;
12736 case PM_MULTI_TARGET_NODE:
12737 if (splat_parent) {
12740 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
12744 case PM_SPLAT_NODE: {
12753 case PM_CALL_NODE: {
12765 (call->
block == NULL)
12780 pm_node_destroy(parser, target);
12782 return UP(pm_local_variable_target_node_create(parser, &message_loc, name, 0));
12786 if (multiple && PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
12787 pm_parser_err_node(parser, (
const pm_node_t *) call, PM_ERR_UNEXPECTED_SAFE_NAVIGATION);
12790 parse_write_name(parser, &call->
name);
12791 return UP(pm_call_target_node_create(parser, call));
12798 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
12799 return UP(pm_index_target_node_create(parser, call));
12807 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
12818 pm_node_t *result = parse_target(parser, target, multiple,
false);
12823 !match1(parser, PM_TOKEN_EQUAL) &&
12825 !(context_p(parser,
PM_CONTEXT_PARENS) && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
12827 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
12841 if (shareable_constant != PM_SCOPE_SHAREABLE_CONSTANT_NONE) {
12842 return UP(pm_shareable_constant_node_create(parser, write, shareable_constant));
12853 switch (PM_NODE_TYPE(target)) {
12854 case PM_MISSING_NODE:
12855 pm_node_destroy(parser, value);
12857 case PM_CLASS_VARIABLE_READ_NODE: {
12859 pm_node_destroy(parser, target);
12862 case PM_CONSTANT_PATH_NODE: {
12865 if (context_def_p(parser)) {
12866 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
12869 return parse_shareable_constant_write(parser, node);
12871 case PM_CONSTANT_READ_NODE: {
12874 if (context_def_p(parser)) {
12875 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
12878 pm_node_destroy(parser, target);
12879 return parse_shareable_constant_write(parser, node);
12881 case PM_BACK_REFERENCE_READ_NODE:
12882 case PM_NUMBERED_REFERENCE_READ_NODE:
12883 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
12885 case PM_GLOBAL_VARIABLE_READ_NODE: {
12887 pm_node_destroy(parser, target);
12890 case PM_LOCAL_VARIABLE_READ_NODE: {
12896 uint32_t depth = local_read->
depth;
12897 pm_scope_t *scope = pm_parser_scope_find(parser, depth);
12900 pm_diagnostic_id_t diag_id = (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND) ? PM_ERR_EXPRESSION_NOT_WRITABLE_NUMBERED : PM_ERR_PARAMETER_NUMBERED_RESERVED;
12902 pm_node_unreference(parser, target);
12905 pm_locals_unread(&scope->
locals, name);
12906 pm_node_destroy(parser, target);
12908 return UP(pm_local_variable_write_node_create(parser, name, depth, value, &name_loc,
operator));
12910 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
12912 pm_node_t *node = UP(pm_local_variable_write_node_create(parser, name, 0, value, &target->
location,
operator));
12914 pm_node_unreference(parser, target);
12915 pm_node_destroy(parser, target);
12919 case PM_INSTANCE_VARIABLE_READ_NODE: {
12921 pm_node_destroy(parser, target);
12924 case PM_MULTI_TARGET_NODE:
12926 case PM_SPLAT_NODE: {
12934 pm_multi_target_node_targets_append(parser, multi_target, UP(splat));
12936 return UP(pm_multi_write_node_create(parser, multi_target,
operator, value));
12938 case PM_CALL_NODE: {
12950 (call->
block == NULL)
12964 pm_parser_local_add_location(parser, message.
start, message.
end, 0);
12965 pm_node_destroy(parser, target);
12968 target = UP(pm_local_variable_write_node_create(parser, constant_id, 0, value, &message,
operator));
12970 pm_refute_numbered_parameter(parser, message.
start, message.
end);
12988 pm_arguments_node_arguments_append(arguments, value);
12990 call->
equal_loc = PM_LOCATION_TOKEN_VALUE(
operator);
12992 parse_write_name(parser, &call->
name);
12993 pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
13002 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
13004 call->
arguments = pm_arguments_node_create(parser);
13007 pm_arguments_node_arguments_append(call->
arguments, value);
13011 call->
name = pm_parser_constant_id_constant(parser,
"[]=", 3);
13012 call->
equal_loc = PM_LOCATION_TOKEN_VALUE(
operator);
13016 pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
13031 pm_node_unreference(parser, value);
13032 pm_node_destroy(parser, value);
13039 pm_parser_err_token(parser,
operator, PM_ERR_WRITE_TARGET_UNEXPECTED);
13052 switch (PM_NODE_TYPE(target)) {
13053 case PM_SOURCE_ENCODING_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13054 case PM_FALSE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13055 case PM_SOURCE_FILE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13056 case PM_SOURCE_LINE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13057 case PM_NIL_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13058 case PM_SELF_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13059 case PM_TRUE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13066 pm_node_destroy(parser, target);
13081parse_targets(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13082 bool has_rest = PM_NODE_TYPE_P(first_target, PM_SPLAT_NODE);
13085 pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target,
true,
false));
13087 while (accept1(parser, PM_TOKEN_COMMA)) {
13088 if (accept1(parser, PM_TOKEN_USTAR)) {
13093 pm_parser_err_previous(parser, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
13099 if (token_begins_expression_p(parser->
current.type)) {
13100 name = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13101 name = parse_target(parser, name,
true,
true);
13104 pm_node_t *splat = UP(pm_splat_node_create(parser, &star_operator, name));
13105 pm_multi_target_node_targets_append(parser, result, splat);
13107 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
13109 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13110 target = parse_target(parser, target,
true,
false);
13112 pm_multi_target_node_targets_append(parser, result, target);
13113 context_pop(parser);
13114 }
else if (token_begins_expression_p(parser->
current.type)) {
13115 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13116 target = parse_target(parser, target,
true,
false);
13118 pm_multi_target_node_targets_append(parser, result, target);
13119 }
else if (!match1(parser, PM_TOKEN_EOF)) {
13123 pm_multi_target_node_targets_append(parser, result, rest);
13136parse_targets_validate(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13137 pm_node_t *result = parse_targets(parser, first_target, binding_power, depth);
13138 accept1(parser, PM_TOKEN_NEWLINE);
13141 if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
13142 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13155 while (accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE));
13158 if (context_terminator(context, &parser->
current))
return NULL;
13164 context_push(parser, context);
13167 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
13168 pm_statements_node_body_append(parser, statements, node,
true);
13181 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
13184 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13185 if (context_terminator(context, &parser->
current))
break;
13195 if (context_terminator(context, &parser->
current))
break;
13207 if (PM_NODE_TYPE_P(node, PM_MISSING_NODE)) {
13208 parser_lex(parser);
13214 if (match1(parser, PM_TOKEN_EOF)) {
13219 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13220 if (context_terminator(context, &parser->
current))
break;
13221 }
else if (!accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_EOF)) {
13231 context_pop(parser);
13232 bool last_value =
true;
13236 last_value =
false;
13241 pm_void_statements_check(parser, statements, last_value);
13254 if (duplicated != NULL) {
13258 pm_diagnostic_list_append_format(
13262 PM_WARN_DUPLICATED_HASH_KEY,
13280 if ((previous = pm_static_literals_add(&parser->
newline_list, parser->
start_line, literals, node,
false)) != NULL) {
13281 pm_diagnostic_list_append_format(
13285 PM_WARN_DUPLICATED_WHEN_CLAUSE,
13297 assert(PM_NODE_TYPE_P(node, PM_HASH_NODE) || PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE));
13298 bool contains_keyword_splat =
false;
13303 switch (parser->
current.type) {
13304 case PM_TOKEN_USTAR_STAR: {
13305 parser_lex(parser);
13309 if (match1(parser, PM_TOKEN_BRACE_LEFT)) {
13315 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
13316 }
else if (token_begins_expression_p(parser->
current.type)) {
13317 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
13319 pm_parser_scope_forwarding_keywords_check(parser, &
operator);
13322 element = UP(pm_assoc_splat_node_create(parser, value, &
operator));
13323 contains_keyword_splat =
true;
13326 case PM_TOKEN_LABEL: {
13328 parser_lex(parser);
13330 pm_node_t *key = UP(pm_symbol_node_label_create(parser, &label));
13331 pm_hash_key_static_literals_add(parser, literals, key);
13336 if (token_begins_expression_p(parser->
current.type)) {
13337 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_EXPRESSION_AFTER_LABEL, (uint16_t) (depth + 1));
13340 pm_token_t constant = { .type = PM_TOKEN_CONSTANT, .start = label.
start, .end = label.
end - 1 };
13341 value = UP(pm_constant_read_node_create(parser, &constant));
13346 if (identifier.
end[-1] ==
'!' || identifier.
end[-1] ==
'?') {
13347 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, identifier, PM_ERR_INVALID_LOCAL_VARIABLE_READ);
13349 depth = pm_parser_local_depth(parser, &identifier);
13353 value = UP(pm_call_node_variable_call_create(parser, &identifier));
13355 value = UP(pm_local_variable_read_node_create(parser, &identifier, (uint32_t) depth));
13360 value = UP(pm_implicit_node_create(parser, value));
13363 element = UP(pm_assoc_node_create(parser, key, &
operator, value));
13367 pm_node_t *key = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_HASH_KEY, (uint16_t) (depth + 1));
13371 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
13372 pm_node_flag_set(key, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
13375 pm_hash_key_static_literals_add(parser, literals, key);
13378 if (pm_symbol_node_label_p(key)) {
13379 operator = not_provided(parser);
13381 expect1(parser, PM_TOKEN_EQUAL_GREATER, PM_ERR_HASH_ROCKET);
13385 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
13386 element = UP(pm_assoc_node_create(parser, key, &
operator, value));
13391 if (PM_NODE_TYPE_P(node, PM_HASH_NODE)) {
13398 if (!accept1(parser, PM_TOKEN_COMMA))
break;
13402 if (match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL))
continue;
13406 if (token_begins_expression_p(parser->
current.type))
continue;
13412 return contains_keyword_splat;
13417 if (pm_symbol_node_label_p(argument)) {
13421 switch (PM_NODE_TYPE(argument)) {
13422 case PM_CALL_NODE: {
13425 if (PM_NODE_FLAG_P(cast->
arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS | PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
13428 if (cast->
block != NULL) {
13436 return accept1(parser, PM_TOKEN_EQUAL_GREATER);
13445 arguments->
arguments = pm_arguments_node_create(parser);
13448 pm_arguments_node_arguments_append(arguments->
arguments, argument);
13455parse_arguments(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_forwarding, pm_token_type_t terminator, uint16_t depth) {
13456 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].
left;
13461 match2(parser, terminator, PM_TOKEN_EOF) ||
13462 (binding_power != PM_BINDING_POWER_UNSET && binding_power < PM_BINDING_POWER_RANGE) ||
13468 bool parsed_first_argument =
false;
13469 bool parsed_bare_hash =
false;
13470 bool parsed_block_argument =
false;
13471 bool parsed_forwarding_arguments =
false;
13473 while (!match1(parser, PM_TOKEN_EOF)) {
13474 if (parsed_forwarding_arguments) {
13475 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES);
13480 switch (parser->
current.type) {
13481 case PM_TOKEN_USTAR_STAR:
13482 case PM_TOKEN_LABEL: {
13483 if (parsed_bare_hash) {
13484 pm_parser_err_current(parser, PM_ERR_ARGUMENT_BARE_HASH);
13488 argument = UP(hash);
13491 bool contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(hash), (uint16_t) (depth + 1));
13493 parse_arguments_append(parser, arguments, argument);
13495 pm_node_flags_t flags = PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
13496 if (contains_keyword_splat) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
13497 pm_node_flag_set(UP(arguments->
arguments), flags);
13499 pm_static_literals_free(&hash_keys);
13500 parsed_bare_hash =
true;
13504 case PM_TOKEN_UAMPERSAND: {
13505 parser_lex(parser);
13509 if (token_begins_expression_p(parser->
current.type)) {
13510 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
13512 pm_parser_scope_forwarding_block_check(parser, &
operator);
13515 argument = UP(pm_block_argument_node_create(parser, &
operator, expression));
13516 if (parsed_block_argument) {
13517 parse_arguments_append(parser, arguments, argument);
13519 arguments->
block = argument;
13522 if (match1(parser, PM_TOKEN_COMMA)) {
13523 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK);
13526 parsed_block_argument =
true;
13529 case PM_TOKEN_USTAR: {
13530 parser_lex(parser);
13533 if (match4(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_SEMICOLON, PM_TOKEN_BRACKET_RIGHT)) {
13534 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
13535 argument = UP(pm_splat_node_create(parser, &
operator, NULL));
13536 if (parsed_bare_hash) {
13537 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
13540 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT, (uint16_t) (depth + 1));
13542 if (parsed_bare_hash) {
13543 pm_parser_err(parser,
operator.start, expression->
location.
end, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
13546 argument = UP(pm_splat_node_create(parser, &
operator, expression));
13549 parse_arguments_append(parser, arguments, argument);
13552 case PM_TOKEN_UDOT_DOT_DOT: {
13553 if (accepts_forwarding) {
13554 parser_lex(parser);
13556 if (token_begins_expression_p(parser->
current.type)) {
13561 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_RANGE,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
13566 if (PM_NODE_TYPE_P(right, PM_RANGE_NODE)) {
13568 pm_parser_err(parser, range->operator_loc.start, range->operator_loc.end, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
13571 argument = UP(pm_range_node_create(parser, NULL, &
operator, right));
13573 pm_parser_scope_forwarding_all_check(parser, &parser->
previous);
13574 if (parsed_first_argument && terminator == PM_TOKEN_EOF) {
13575 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORWARDING_UNBOUND);
13578 argument = UP(pm_forwarding_arguments_node_create(parser, &parser->
previous));
13579 parse_arguments_append(parser, arguments, argument);
13580 pm_node_flag_set(UP(arguments->
arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING);
13582 parsed_forwarding_arguments =
true;
13589 if (argument == NULL) {
13590 argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, !parsed_first_argument,
true, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
13593 bool contains_keywords =
false;
13594 bool contains_keyword_splat =
false;
13596 if (argument_allowed_for_bare_hash(parser, argument)){
13597 if (parsed_bare_hash) {
13598 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
13602 if (parser->
previous.
type == PM_TOKEN_EQUAL_GREATER) {
13605 operator = not_provided(parser);
13609 contains_keywords =
true;
13613 pm_hash_key_static_literals_add(parser, &hash_keys, argument);
13616 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
13617 argument = UP(pm_assoc_node_create(parser, argument, &
operator, value));
13619 pm_keyword_hash_node_elements_append(bare_hash, argument);
13620 argument = UP(bare_hash);
13623 if (accept1(parser, PM_TOKEN_COMMA) && (
13624 token_begins_expression_p(parser->
current.type) ||
13625 match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL)
13627 contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(bare_hash), (uint16_t) (depth + 1));
13630 pm_static_literals_free(&hash_keys);
13631 parsed_bare_hash =
true;
13634 parse_arguments_append(parser, arguments, argument);
13636 pm_node_flags_t flags = 0;
13637 if (contains_keywords) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
13638 if (contains_keyword_splat) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
13639 pm_node_flag_set(UP(arguments->
arguments), flags);
13645 parsed_first_argument =
true;
13648 if (PM_NODE_TYPE_P(argument, PM_MISSING_NODE) || parser->
recovering)
break;
13653 bool accepted_newline =
false;
13654 if (terminator != PM_TOKEN_EOF) {
13655 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
13658 if (parser->
previous.
type == PM_TOKEN_COMMA && parsed_bare_hash) {
13662 }
else if (accept1(parser, PM_TOKEN_COMMA)) {
13665 if (accepted_newline) {
13666 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
13672 if (PM_NODE_TYPE_P(argument, PM_CALL_NODE)) {
13675 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
13687 if (match1(parser, terminator))
break;
13702parse_required_destructured_parameter(
pm_parser_t *parser) {
13703 expect1(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_ERR_EXPECT_LPAREN_REQ_PARAMETER);
13706 pm_multi_target_node_opening_set(node, &parser->
previous);
13715 if (node->
lefts.
size > 0 && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
13716 param = UP(pm_implicit_rest_node_create(parser, &parser->
previous));
13717 pm_multi_target_node_targets_append(parser, node, param);
13718 pm_parser_err_current(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
13722 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
13723 param = UP(parse_required_destructured_parameter(parser));
13724 }
else if (accept1(parser, PM_TOKEN_USTAR)) {
13728 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
13730 value = UP(pm_required_parameter_node_create(parser, &name));
13731 if (pm_parser_parameter_name_check(parser, &name)) {
13732 pm_node_flag_set_repeated_parameter(value);
13734 pm_parser_local_add_token(parser, &name, 1);
13737 param = UP(pm_splat_node_create(parser, &star, value));
13739 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EXPECT_IDENT_REQ_PARAMETER);
13742 param = UP(pm_required_parameter_node_create(parser, &name));
13743 if (pm_parser_parameter_name_check(parser, &name)) {
13744 pm_node_flag_set_repeated_parameter(param);
13746 pm_parser_local_add_token(parser, &name, 1);
13749 pm_multi_target_node_targets_append(parser, node, param);
13750 }
while (accept1(parser, PM_TOKEN_COMMA));
13752 accept1(parser, PM_TOKEN_NEWLINE);
13753 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN_REQ_PARAMETER);
13754 pm_multi_target_node_closing_set(node, &parser->
previous);
13764 PM_PARAMETERS_NO_CHANGE = 0,
13765 PM_PARAMETERS_ORDER_NOTHING_AFTER = 1,
13766 PM_PARAMETERS_ORDER_KEYWORDS_REST,
13767 PM_PARAMETERS_ORDER_KEYWORDS,
13768 PM_PARAMETERS_ORDER_REST,
13769 PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
13770 PM_PARAMETERS_ORDER_OPTIONAL,
13771 PM_PARAMETERS_ORDER_NAMED,
13772 PM_PARAMETERS_ORDER_NONE,
13773} pm_parameters_order_t;
13778static pm_parameters_order_t parameters_ordering[PM_TOKEN_MAXIMUM] = {
13779 [0] = PM_PARAMETERS_NO_CHANGE,
13780 [PM_TOKEN_UAMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
13781 [PM_TOKEN_AMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
13782 [PM_TOKEN_UDOT_DOT_DOT] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
13783 [PM_TOKEN_IDENTIFIER] = PM_PARAMETERS_ORDER_NAMED,
13784 [PM_TOKEN_PARENTHESIS_LEFT] = PM_PARAMETERS_ORDER_NAMED,
13785 [PM_TOKEN_EQUAL] = PM_PARAMETERS_ORDER_OPTIONAL,
13786 [PM_TOKEN_LABEL] = PM_PARAMETERS_ORDER_KEYWORDS,
13787 [PM_TOKEN_USTAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
13788 [PM_TOKEN_STAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
13789 [PM_TOKEN_USTAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST,
13790 [PM_TOKEN_STAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST
13802 pm_parameters_order_t state = parameters_ordering[token->type];
13803 if (state == PM_PARAMETERS_NO_CHANGE)
return true;
13807 if (*current == PM_PARAMETERS_ORDER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
13808 *current = PM_PARAMETERS_ORDER_AFTER_OPTIONAL;
13810 }
else if (*current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
13814 if (token->type == PM_TOKEN_USTAR && *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
13815 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_STAR);
13817 }
else if (token->type == PM_TOKEN_UDOT_DOT_DOT && (*current >= PM_PARAMETERS_ORDER_KEYWORDS_REST && *current <= PM_PARAMETERS_ORDER_AFTER_OPTIONAL)) {
13818 pm_parser_err_token(parser, token, *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL ? PM_ERR_PARAMETER_FORWARDING_AFTER_REST : PM_ERR_PARAMETER_ORDER);
13820 }
else if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
13822 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_ORDER);
13826 if (state < *current) *current = state;
13836 pm_binding_power_t binding_power,
13837 bool uses_parentheses,
13838 bool allows_trailing_comma,
13839 bool allows_forwarding_parameters,
13840 bool accepts_blocks_in_defaults,
13844 pm_do_loop_stack_push(parser,
false);
13847 pm_parameters_order_t order = PM_PARAMETERS_ORDER_NONE;
13850 bool parsing =
true;
13852 switch (parser->
current.type) {
13853 case PM_TOKEN_PARENTHESIS_LEFT: {
13854 update_parameter_state(parser, &parser->
current, &order);
13855 pm_node_t *param = UP(parse_required_destructured_parameter(parser));
13857 if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
13858 pm_parameters_node_requireds_append(params, param);
13860 pm_parameters_node_posts_append(params, param);
13864 case PM_TOKEN_UAMPERSAND:
13865 case PM_TOKEN_AMPERSAND: {
13866 update_parameter_state(parser, &parser->
current, &order);
13867 parser_lex(parser);
13872 bool repeated =
false;
13873 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
13875 repeated = pm_parser_parameter_name_check(parser, &name);
13876 pm_parser_local_add_token(parser, &name, 1);
13878 name = not_provided(parser);
13884 pm_node_flag_set_repeated_parameter(UP(param));
13886 if (params->
block == NULL) {
13887 pm_parameters_node_block_set(params, param);
13889 pm_parser_err_node(parser, UP(param), PM_ERR_PARAMETER_BLOCK_MULTI);
13890 pm_parameters_node_posts_append(params, UP(param));
13895 case PM_TOKEN_UDOT_DOT_DOT: {
13896 if (!allows_forwarding_parameters) {
13897 pm_parser_err_current(parser, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
13900 bool succeeded = update_parameter_state(parser, &parser->
current, &order);
13901 parser_lex(parser);
13910 pm_parameters_node_posts_append(params, keyword_rest);
13911 if (succeeded) pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD);
13915 pm_parameters_node_keyword_rest_set(params, UP(param));
13918 case PM_TOKEN_CLASS_VARIABLE:
13919 case PM_TOKEN_IDENTIFIER:
13920 case PM_TOKEN_CONSTANT:
13921 case PM_TOKEN_INSTANCE_VARIABLE:
13922 case PM_TOKEN_GLOBAL_VARIABLE:
13923 case PM_TOKEN_METHOD_NAME: {
13924 parser_lex(parser);
13926 case PM_TOKEN_CONSTANT:
13927 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
13929 case PM_TOKEN_INSTANCE_VARIABLE:
13930 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
13932 case PM_TOKEN_GLOBAL_VARIABLE:
13933 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
13935 case PM_TOKEN_CLASS_VARIABLE:
13936 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
13938 case PM_TOKEN_METHOD_NAME:
13939 pm_parser_err_previous(parser, PM_ERR_PARAMETER_METHOD_NAME);
13944 if (parser->
current.type == PM_TOKEN_EQUAL) {
13945 update_parameter_state(parser, &parser->
current, &order);
13947 update_parameter_state(parser, &parser->
previous, &order);
13951 bool repeated = pm_parser_parameter_name_check(parser, &name);
13952 pm_parser_local_add_token(parser, &name, 1);
13954 if (match1(parser, PM_TOKEN_EQUAL)) {
13957 parser_lex(parser);
13962 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
13963 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
13964 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
13969 pm_node_flag_set_repeated_parameter(UP(param));
13971 pm_parameters_node_optionals_append(params, param);
13977 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, name, PM_ERR_PARAMETER_CIRCULAR);
13980 context_pop(parser);
13989 }
else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
13992 pm_node_flag_set_repeated_parameter(UP(param));
13994 pm_parameters_node_requireds_append(params, UP(param));
13998 pm_node_flag_set_repeated_parameter(UP(param));
14000 pm_parameters_node_posts_append(params, UP(param));
14005 case PM_TOKEN_LABEL: {
14006 if (!uses_parentheses && !in_block) parser->
in_keyword_arg =
true;
14007 update_parameter_state(parser, &parser->
current, &order);
14010 parser_lex(parser);
14017 pm_parser_err(parser, local.
start, local.
end, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14018 }
else if (local.
end[-1] ==
'!' || local.
end[-1] ==
'?') {
14019 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
14022 bool repeated = pm_parser_parameter_name_check(parser, &local);
14023 pm_parser_local_add_token(parser, &local, 1);
14025 switch (parser->
current.type) {
14026 case PM_TOKEN_COMMA:
14027 case PM_TOKEN_PARENTHESIS_RIGHT:
14028 case PM_TOKEN_PIPE: {
14029 context_pop(parser);
14031 pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14033 pm_node_flag_set_repeated_parameter(param);
14036 pm_parameters_node_keywords_append(params, param);
14039 case PM_TOKEN_SEMICOLON:
14040 case PM_TOKEN_NEWLINE: {
14041 context_pop(parser);
14043 if (uses_parentheses) {
14048 pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14050 pm_node_flag_set_repeated_parameter(param);
14053 pm_parameters_node_keywords_append(params, param);
14059 if (token_begins_expression_p(parser->
current.type)) {
14063 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14064 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT_KW, (uint16_t) (depth + 1));
14065 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14068 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_PARAMETER_CIRCULAR);
14071 param = UP(pm_optional_keyword_parameter_node_create(parser, &name, value));
14074 param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14078 pm_node_flag_set_repeated_parameter(param);
14081 context_pop(parser);
14082 pm_parameters_node_keywords_append(params, param);
14097 case PM_TOKEN_USTAR:
14098 case PM_TOKEN_STAR: {
14099 update_parameter_state(parser, &parser->
current, &order);
14100 parser_lex(parser);
14104 bool repeated =
false;
14106 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14108 repeated = pm_parser_parameter_name_check(parser, &name);
14109 pm_parser_local_add_token(parser, &name, 1);
14111 name = not_provided(parser);
14115 pm_node_t *param = UP(pm_rest_parameter_node_create(parser, &
operator, &name));
14117 pm_node_flag_set_repeated_parameter(param);
14120 if (params->
rest == NULL) {
14121 pm_parameters_node_rest_set(params, param);
14123 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_SPLAT_MULTI);
14124 pm_parameters_node_posts_append(params, param);
14129 case PM_TOKEN_STAR_STAR:
14130 case PM_TOKEN_USTAR_STAR: {
14131 pm_parameters_order_t previous_order = order;
14132 update_parameter_state(parser, &parser->
current, &order);
14133 parser_lex(parser);
14138 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
14139 if (previous_order <= PM_PARAMETERS_ORDER_KEYWORDS) {
14140 pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_NO_KW);
14143 param = UP(pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous));
14147 bool repeated =
false;
14148 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14150 repeated = pm_parser_parameter_name_check(parser, &name);
14151 pm_parser_local_add_token(parser, &name, 1);
14153 name = not_provided(parser);
14157 param = UP(pm_keyword_rest_parameter_node_create(parser, &
operator, &name));
14159 pm_node_flag_set_repeated_parameter(param);
14164 pm_parameters_node_keyword_rest_set(params, param);
14166 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI);
14167 pm_parameters_node_posts_append(params, param);
14174 if (allows_trailing_comma && order >= PM_PARAMETERS_ORDER_NAMED) {
14177 pm_node_t *param = UP(pm_implicit_rest_node_create(parser, &parser->
previous));
14179 if (params->
rest == NULL) {
14180 pm_parameters_node_rest_set(params, param);
14182 pm_parser_err_node(parser, UP(param), PM_ERR_PARAMETER_SPLAT_MULTI);
14183 pm_parameters_node_posts_append(params, UP(param));
14186 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14197 if (!parsing)
break;
14199 bool accepted_newline =
false;
14200 if (uses_parentheses) {
14201 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
14204 if (accept1(parser, PM_TOKEN_COMMA)) {
14207 if (accepted_newline) {
14208 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14216 pm_do_loop_stack_pop(parser);
14220 pm_node_destroy(parser, UP(params));
14252token_column(
const pm_parser_t *parser,
size_t newline_index,
const pm_token_t *token,
bool break_on_non_space) {
14254 const uint8_t *end = token->start;
14258 newline_index == 0 &&
14259 parser->
start[0] == 0xef &&
14260 parser->
start[1] == 0xbb &&
14261 parser->
start[2] == 0xbf
14264 int64_t column = 0;
14265 for (; cursor < end; cursor++) {
14268 column = ((column / PM_TAB_WHITESPACE_SIZE) + 1) * PM_TAB_WHITESPACE_SIZE;
14275 if (break_on_non_space)
return -1;
14288parser_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) {
14293 size_t closing_newline_index = token_newline_index(parser);
14294 if (opening_newline_index == closing_newline_index)
return;
14299 int64_t opening_column = token_column(parser, opening_newline_index, opening_token, !if_after_else);
14300 if (!if_after_else && (opening_column == -1))
return;
14307 int64_t closing_column = token_column(parser, closing_newline_index, closing_token,
true);
14308 if ((closing_column == -1) || (opening_column == closing_column))
return;
14312 if (allow_indent && (closing_column > opening_column))
return;
14315 PM_PARSER_WARN_FORMAT(
14317 closing_token->
start,
14318 closing_token->
end,
14319 PM_WARN_INDENTATION_MISMATCH,
14320 (
int) (closing_token->
end - closing_token->
start),
14321 (
const char *) closing_token->
start,
14322 (
int) (opening_token->
end - opening_token->
start),
14323 (
const char *) opening_token->
start,
14324 ((int32_t) opening_newline_index) + parser->
start_line
14329 PM_RESCUES_BEGIN = 1,
14336} pm_rescues_type_t;
14346 while (match1(parser, PM_TOKEN_KEYWORD_RESCUE)) {
14347 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14348 parser_lex(parser);
14352 switch (parser->
current.type) {
14353 case PM_TOKEN_EQUAL_GREATER: {
14357 parser_lex(parser);
14358 pm_rescue_node_operator_set(rescue, &parser->
previous);
14360 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
14361 reference = parse_target(parser, reference,
false,
false);
14363 pm_rescue_node_reference_set(rescue, reference);
14366 case PM_TOKEN_NEWLINE:
14367 case PM_TOKEN_SEMICOLON:
14368 case PM_TOKEN_KEYWORD_THEN:
14373 if (token_begins_expression_p(parser->
current.type) || match1(parser, PM_TOKEN_USTAR)) {
14378 pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED,
false, PM_ERR_RESCUE_EXPRESSION, (uint16_t) (depth + 1));
14379 pm_rescue_node_exceptions_append(rescue, expression);
14383 if (match3(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_THEN))
break;
14387 if (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
14388 pm_rescue_node_operator_set(rescue, &parser->
previous);
14390 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
14391 reference = parse_target(parser, reference,
false,
false);
14393 pm_rescue_node_reference_set(rescue, reference);
14396 }
while (accept1(parser, PM_TOKEN_COMMA));
14401 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
14402 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
14406 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_RESCUE_TERM);
14410 if (!match3(parser, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_END)) {
14411 pm_accepts_block_stack_push(parser,
true);
14426 if (statements != NULL) pm_rescue_node_statements_set(rescue, statements);
14428 pm_accepts_block_stack_pop(parser);
14429 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14432 if (current == NULL) {
14433 pm_begin_node_rescue_clause_set(parent_node, rescue);
14435 pm_rescue_node_subsequent_set(current, rescue);
14444 if (current != NULL) {
14448 while (clause != NULL) {
14455 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
14456 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14457 opening_newline_index = token_newline_index(parser);
14459 else_keyword = parser->
current;
14460 opening = &else_keyword;
14462 parser_lex(parser);
14463 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14466 if (!match2(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_ENSURE)) {
14467 pm_accepts_block_stack_push(parser,
true);
14481 else_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
14482 pm_accepts_block_stack_pop(parser);
14484 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14487 pm_else_node_t *else_clause = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
current);
14488 pm_begin_node_else_clause_set(parent_node, else_clause);
14492 if (current == NULL) pm_parser_err_node(parser, UP(else_clause), PM_ERR_BEGIN_LONELY_ELSE);
14495 if (match1(parser, PM_TOKEN_KEYWORD_ENSURE)) {
14496 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14499 parser_lex(parser);
14500 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14503 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
14504 pm_accepts_block_stack_push(parser,
true);
14518 ensure_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
14519 pm_accepts_block_stack_pop(parser);
14521 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14524 pm_ensure_node_t *ensure_clause = pm_ensure_node_create(parser, &ensure_keyword, ensure_statements, &parser->
current);
14525 pm_begin_node_ensure_clause_set(parent_node, ensure_clause);
14528 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
14529 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14530 pm_begin_node_end_keyword_set(parent_node, &parser->
current);
14533 pm_begin_node_end_keyword_set(parent_node, &end_keyword);
14543 pm_token_t begin_keyword = not_provided(parser);
14544 pm_begin_node_t *node = pm_begin_node_create(parser, &begin_keyword, statements);
14546 parse_rescues(parser, opening_newline_index, opening, node,
type, (uint16_t) (depth + 1));
14556parse_block_parameters(
14558 bool allows_trailing_comma,
14560 bool is_lambda_literal,
14561 bool accepts_blocks_in_defaults,
14565 if (!match1(parser, PM_TOKEN_SEMICOLON)) {
14566 if (!is_lambda_literal) {
14569 parameters = parse_parameters(
14571 is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
14573 allows_trailing_comma,
14575 accepts_blocks_in_defaults,
14577 (uint16_t) (depth + 1)
14579 if (!is_lambda_literal) {
14580 context_pop(parser);
14585 if ((opening->
type != PM_TOKEN_NOT_PROVIDED)) {
14586 accept1(parser, PM_TOKEN_NEWLINE);
14588 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
14590 switch (parser->
current.type) {
14591 case PM_TOKEN_CONSTANT:
14592 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14593 parser_lex(parser);
14595 case PM_TOKEN_INSTANCE_VARIABLE:
14596 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
14597 parser_lex(parser);
14599 case PM_TOKEN_GLOBAL_VARIABLE:
14600 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
14601 parser_lex(parser);
14603 case PM_TOKEN_CLASS_VARIABLE:
14604 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
14605 parser_lex(parser);
14608 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_BLOCK_PARAM_LOCAL_VARIABLE);
14612 bool repeated = pm_parser_parameter_name_check(parser, &parser->
previous);
14613 pm_parser_local_add_token(parser, &parser->
previous, 1);
14616 if (repeated) pm_node_flag_set_repeated_parameter(UP(local));
14618 pm_block_parameters_node_append_local(block_parameters, local);
14619 }
while (accept1(parser, PM_TOKEN_COMMA));
14623 return block_parameters;
14631outer_scope_using_numbered_parameters_p(
pm_parser_t *parser) {
14633 if (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND)
return true;
14644static const char *
const pm_numbered_parameter_names[] = {
14645 "_1",
"_2",
"_3",
"_4",
"_5",
"_6",
"_7",
"_8",
"_9"
14659 if (parameters != NULL) {
14661 if (implicit_parameters->
size > 0) {
14664 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
14665 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_ORDINARY);
14666 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
14667 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_ORDINARY);
14669 assert(
false &&
"unreachable");
14678 if (implicit_parameters->
size == 0) {
14685 uint8_t numbered_parameter = 0;
14686 bool it_parameter =
false;
14688 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
14691 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
14692 if (it_parameter) {
14693 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_IT);
14694 }
else if (outer_scope_using_numbered_parameters_p(parser)) {
14695 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_OUTER_BLOCK);
14697 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK);
14699 numbered_parameter = MAX(numbered_parameter, (uint8_t) (node->
location.
start[1] -
'0'));
14701 assert(
false &&
"unreachable");
14703 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
14704 if (numbered_parameter > 0) {
14705 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_NUMBERED);
14707 it_parameter =
true;
14712 if (numbered_parameter > 0) {
14716 scope->
parameters |= PM_SCOPE_PARAMETERS_NUMBERED_INNER;
14720 return UP(pm_numbered_parameters_node_create(parser, &location, numbered_parameter));
14723 if (it_parameter) {
14724 return UP(pm_it_parameters_node_create(parser, opening, closing));
14734parse_block(
pm_parser_t *parser, uint16_t depth) {
14736 accept1(parser, PM_TOKEN_NEWLINE);
14738 pm_accepts_block_stack_push(parser,
true);
14739 pm_parser_scope_push(parser,
false);
14743 if (accept1(parser, PM_TOKEN_PIPE)) {
14745 if (match1(parser, PM_TOKEN_PIPE)) {
14746 block_parameters = pm_block_parameters_node_create(parser, NULL, &block_parameters_opening);
14748 parser_lex(parser);
14750 block_parameters = parse_block_parameters(parser,
true, &block_parameters_opening,
false,
true, (uint16_t) (depth + 1));
14751 accept1(parser, PM_TOKEN_NEWLINE);
14753 expect1(parser, PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM);
14756 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
14759 accept1(parser, PM_TOKEN_NEWLINE);
14762 if (opening.
type == PM_TOKEN_BRACE_LEFT) {
14763 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
14767 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE);
14769 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
14770 if (!match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE)) {
14771 pm_accepts_block_stack_push(parser,
true);
14773 pm_accepts_block_stack_pop(parser);
14776 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
14777 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
14778 statements = UP(parse_rescues_implicit_begin(parser, 0, NULL, opening.
start, (
pm_statements_node_t *) statements, PM_RESCUES_BLOCK, (uint16_t) (depth + 1)));
14782 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END);
14786 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
14787 pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &opening, &parser->
previous);
14789 pm_parser_scope_pop(parser);
14790 pm_accepts_block_stack_pop(parser);
14792 return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->
previous);
14801parse_arguments_list(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_block,
bool accepts_command_call, uint16_t depth) {
14802 bool found =
false;
14804 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
14808 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
14811 pm_accepts_block_stack_push(parser,
true);
14812 parse_arguments(parser, arguments, accepts_block, PM_TOKEN_PARENTHESIS_RIGHT, (uint16_t) (depth + 1));
14814 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
14820 pm_accepts_block_stack_pop(parser);
14823 }
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)) {
14825 pm_accepts_block_stack_push(parser,
false);
14830 parse_arguments(parser, arguments, accepts_block, PM_TOKEN_EOF, (uint16_t) (depth + 1));
14835 if (parser->
previous.
type == PM_TOKEN_COMMA && !match1(parser, PM_TOKEN_SEMICOLON)) {
14839 pm_accepts_block_stack_pop(parser);
14845 if (accepts_block) {
14848 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
14850 block = parse_block(parser, (uint16_t) (depth + 1));
14851 pm_arguments_validate_block(parser, arguments, block);
14852 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
14854 block = parse_block(parser, (uint16_t) (depth + 1));
14857 if (block != NULL) {
14859 arguments->
block = UP(block);
14861 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_BLOCK_MULTI);
14863 if (arguments->
block != NULL) {
14865 arguments->
arguments = pm_arguments_node_create(parser);
14867 pm_arguments_node_arguments_append(arguments->
arguments, arguments->
block);
14869 arguments->
block = UP(block);
14883 bool in_sclass =
false;
14885 switch (context_node->
context) {
14930 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
14953 assert(
false &&
"unreachable");
14958 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
14969 switch (context_node->
context) {
15044 assert(
false &&
"unreachable");
15058 return previous_block_exits;
15072 switch (PM_NODE_TYPE(block_exit)) {
15073 case PM_BREAK_NODE:
type =
"break";
break;
15074 case PM_NEXT_NODE:
type =
"next";
break;
15075 case PM_REDO_NODE:
type =
"redo";
break;
15076 default: assert(
false &&
"unreachable");
type =
"";
break;
15079 PM_PARSER_ERR_NODE_FORMAT(parser, block_exit, PM_ERR_INVALID_BLOCK_EXIT,
type);
15091 if (match2(parser, PM_TOKEN_KEYWORD_WHILE_MODIFIER, PM_TOKEN_KEYWORD_UNTIL_MODIFIER)) {
15096 }
else if (previous_block_exits != NULL) {
15108 flush_block_exits(parser, previous_block_exits);
15116 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, error_id, (uint16_t) (depth + 1));
15119 bool predicate_closed = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15121 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
15122 predicate_closed =
true;
15126 if (!predicate_closed) {
15127 pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
15130 context_pop(parser);
15135parse_conditional(
pm_parser_t *parser,
pm_context_t context,
size_t opening_newline_index,
bool if_after_else, uint16_t depth) {
15137 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
15140 pm_token_t then_keyword = not_provided(parser);
15142 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context, &then_keyword, (uint16_t) (depth + 1));
15145 if (!match3(parser, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
15146 pm_accepts_block_stack_push(parser,
true);
15147 statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15148 pm_accepts_block_stack_pop(parser);
15149 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15152 pm_token_t end_keyword = not_provided(parser);
15157 parent = UP(pm_if_node_create(parser, &keyword, predicate, &then_keyword, statements, NULL, &end_keyword));
15160 parent = UP(pm_unless_node_create(parser, &keyword, predicate, &then_keyword, statements));
15163 assert(
false &&
"unreachable");
15172 while (match1(parser, PM_TOKEN_KEYWORD_ELSIF)) {
15173 if (parser_end_of_line_p(parser)) {
15174 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
15177 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15179 parser_lex(parser);
15181 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER,
PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1));
15182 pm_accepts_block_stack_push(parser,
true);
15185 pm_accepts_block_stack_pop(parser);
15186 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15188 pm_node_t *elsif = UP(pm_if_node_create(parser, &elsif_keyword, predicate, &then_keyword, statements, NULL, &end_keyword));
15194 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
15195 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15196 opening_newline_index = token_newline_index(parser);
15198 parser_lex(parser);
15201 pm_accepts_block_stack_push(parser,
true);
15203 pm_accepts_block_stack_pop(parser);
15205 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15206 parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword,
false,
false);
15207 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE);
15209 pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
previous);
15213 ((
pm_if_node_t *) current)->subsequent = UP(else_node);
15219 assert(
false &&
"unreachable");
15223 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else,
false);
15224 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM);
15231 bool recursing =
true;
15233 while (recursing) {
15234 switch (PM_NODE_TYPE(current)) {
15238 recursing = current != NULL;
15256 assert(
false &&
"unreachable");
15260 pop_block_exits(parser, previous_block_exits);
15261 pm_node_list_free(¤t_block_exits);
15270#define PM_CASE_KEYWORD PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15271 case PM_TOKEN_KEYWORD_ALIAS: case PM_TOKEN_KEYWORD_AND: case PM_TOKEN_KEYWORD_BEGIN: case PM_TOKEN_KEYWORD_BEGIN_UPCASE: \
15272 case PM_TOKEN_KEYWORD_BREAK: case PM_TOKEN_KEYWORD_CASE: case PM_TOKEN_KEYWORD_CLASS: case PM_TOKEN_KEYWORD_DEF: \
15273 case PM_TOKEN_KEYWORD_DEFINED: case PM_TOKEN_KEYWORD_DO: case PM_TOKEN_KEYWORD_DO_LOOP: case PM_TOKEN_KEYWORD_ELSE: \
15274 case PM_TOKEN_KEYWORD_ELSIF: case PM_TOKEN_KEYWORD_END: case PM_TOKEN_KEYWORD_END_UPCASE: case PM_TOKEN_KEYWORD_ENSURE: \
15275 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD_FOR: case PM_TOKEN_KEYWORD_IF: case PM_TOKEN_KEYWORD_IN: \
15276 case PM_TOKEN_KEYWORD_MODULE: case PM_TOKEN_KEYWORD_NEXT: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_NOT: \
15277 case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_KEYWORD_REDO: case PM_TOKEN_KEYWORD_RESCUE: case PM_TOKEN_KEYWORD_RETRY: \
15278 case PM_TOKEN_KEYWORD_RETURN: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_SUPER: case PM_TOKEN_KEYWORD_THEN: \
15279 case PM_TOKEN_KEYWORD_TRUE: case PM_TOKEN_KEYWORD_UNDEF: case PM_TOKEN_KEYWORD_UNLESS: case PM_TOKEN_KEYWORD_UNTIL: \
15280 case PM_TOKEN_KEYWORD_WHEN: case PM_TOKEN_KEYWORD_WHILE: case PM_TOKEN_KEYWORD_YIELD
15286#define PM_CASE_OPERATOR PM_TOKEN_AMPERSAND: case PM_TOKEN_BACKTICK: case PM_TOKEN_BANG_EQUAL: \
15287 case PM_TOKEN_BANG_TILDE: case PM_TOKEN_BANG: case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL: \
15288 case PM_TOKEN_BRACKET_LEFT_RIGHT: case PM_TOKEN_CARET: case PM_TOKEN_EQUAL_EQUAL_EQUAL: case PM_TOKEN_EQUAL_EQUAL: \
15289 case PM_TOKEN_EQUAL_TILDE: case PM_TOKEN_GREATER_EQUAL: case PM_TOKEN_GREATER_GREATER: case PM_TOKEN_GREATER: \
15290 case PM_TOKEN_LESS_EQUAL_GREATER: case PM_TOKEN_LESS_EQUAL: case PM_TOKEN_LESS_LESS: case PM_TOKEN_LESS: \
15291 case PM_TOKEN_MINUS: case PM_TOKEN_PERCENT: case PM_TOKEN_PIPE: case PM_TOKEN_PLUS: case PM_TOKEN_SLASH: \
15292 case PM_TOKEN_STAR_STAR: case PM_TOKEN_STAR: case PM_TOKEN_TILDE: case PM_TOKEN_UAMPERSAND: case PM_TOKEN_UMINUS: \
15293 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_UPLUS: case PM_TOKEN_USTAR: case PM_TOKEN_USTAR_STAR
15300#define PM_CASE_PRIMITIVE PM_TOKEN_INTEGER: case PM_TOKEN_INTEGER_IMAGINARY: case PM_TOKEN_INTEGER_RATIONAL: \
15301 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: case PM_TOKEN_FLOAT: case PM_TOKEN_FLOAT_IMAGINARY: \
15302 case PM_TOKEN_FLOAT_RATIONAL: case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY: case PM_TOKEN_SYMBOL_BEGIN: \
15303 case PM_TOKEN_REGEXP_BEGIN: case PM_TOKEN_BACKTICK: case PM_TOKEN_PERCENT_LOWER_X: case PM_TOKEN_PERCENT_LOWER_I: \
15304 case PM_TOKEN_PERCENT_LOWER_W: case PM_TOKEN_PERCENT_UPPER_I: case PM_TOKEN_PERCENT_UPPER_W: \
15305 case PM_TOKEN_STRING_BEGIN: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_TRUE: \
15306 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15307 case PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_MINUS_GREATER: case PM_TOKEN_HEREDOC_START: \
15308 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_CHARACTER_LITERAL
15314#define PM_CASE_PARAMETER PM_TOKEN_UAMPERSAND: case PM_TOKEN_AMPERSAND: case PM_TOKEN_UDOT_DOT_DOT: \
15315 case PM_TOKEN_IDENTIFIER: case PM_TOKEN_LABEL: case PM_TOKEN_USTAR: case PM_TOKEN_STAR: case PM_TOKEN_STAR_STAR: \
15316 case PM_TOKEN_USTAR_STAR: case PM_TOKEN_CONSTANT: case PM_TOKEN_INSTANCE_VARIABLE: case PM_TOKEN_GLOBAL_VARIABLE: \
15317 case PM_TOKEN_CLASS_VARIABLE
15323#define PM_CASE_WRITABLE PM_CLASS_VARIABLE_READ_NODE: case PM_CONSTANT_PATH_NODE: \
15324 case PM_CONSTANT_READ_NODE: case PM_GLOBAL_VARIABLE_READ_NODE: case PM_LOCAL_VARIABLE_READ_NODE: \
15325 case PM_INSTANCE_VARIABLE_READ_NODE: case PM_MULTI_TARGET_NODE: case PM_BACK_REFERENCE_READ_NODE: \
15326 case PM_NUMBERED_REFERENCE_READ_NODE: case PM_IT_LOCAL_VARIABLE_READ_NODE
15330PM_STATIC_ASSERT(__LINE__, ((
int) PM_STRING_FLAGS_FORCED_UTF8_ENCODING) == ((
int) PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING),
"Expected the flags to match.");
15336static inline pm_node_flags_t
15337parse_unescaped_encoding(
const pm_parser_t *parser) {
15342 return PM_STRING_FLAGS_FORCED_UTF8_ENCODING;
15348 return PM_STRING_FLAGS_FORCED_BINARY_ENCODING;
15359parse_string_part(
pm_parser_t *parser, uint16_t depth) {
15360 switch (parser->
current.type) {
15367 case PM_TOKEN_STRING_CONTENT: {
15371 pm_node_t *node = UP(pm_string_node_create_current_string(parser, &opening, &parser->
current, &closing));
15372 pm_node_flag_set(node, parse_unescaped_encoding(parser));
15374 parser_lex(parser);
15383 case PM_TOKEN_EMBEXPR_BEGIN: {
15392 lex_state_set(parser, PM_LEX_STATE_BEG);
15393 parser_lex(parser);
15398 if (!match1(parser, PM_TOKEN_EMBEXPR_END)) {
15399 pm_accepts_block_stack_push(parser,
true);
15401 pm_accepts_block_stack_pop(parser);
15405 lex_state_set(parser, state);
15407 expect1(parser, PM_TOKEN_EMBEXPR_END, PM_ERR_EMBEXPR_END);
15413 if (statements != NULL && statements->
body.
size == 1) {
15414 pm_node_flag_unset(statements->
body.
nodes[0], PM_NODE_FLAG_NEWLINE);
15417 return UP(pm_embedded_statements_node_create(parser, &opening, statements, &closing));
15426 case PM_TOKEN_EMBVAR: {
15431 lex_state_set(parser, PM_LEX_STATE_BEG);
15432 parser_lex(parser);
15437 switch (parser->
current.type) {
15440 case PM_TOKEN_BACK_REFERENCE:
15441 parser_lex(parser);
15442 variable = UP(pm_back_reference_read_node_create(parser, &parser->
previous));
15446 case PM_TOKEN_NUMBERED_REFERENCE:
15447 parser_lex(parser);
15448 variable = UP(pm_numbered_reference_read_node_create(parser, &parser->
previous));
15452 case PM_TOKEN_GLOBAL_VARIABLE:
15453 parser_lex(parser);
15454 variable = UP(pm_global_variable_read_node_create(parser, &parser->
previous));
15458 case PM_TOKEN_INSTANCE_VARIABLE:
15459 parser_lex(parser);
15460 variable = UP(pm_instance_variable_read_node_create(parser, &parser->
previous));
15464 case PM_TOKEN_CLASS_VARIABLE:
15465 parser_lex(parser);
15466 variable = UP(pm_class_variable_read_node_create(parser, &parser->
previous));
15472 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EMBVAR_INVALID);
15473 variable = UP(pm_missing_node_create(parser, parser->
current.start, parser->
current.end));
15477 return UP(pm_embedded_variable_node_create(parser, &
operator, variable));
15480 parser_lex(parser);
15481 pm_parser_err_previous(parser, PM_ERR_CANNOT_PARSE_STRING_PART);
15491static const uint8_t *
15492parse_operator_symbol_name(
const pm_token_t *name) {
15493 switch (name->
type) {
15494 case PM_TOKEN_TILDE:
15495 case PM_TOKEN_BANG:
15496 if (name->
end[-1] ==
'@')
return name->
end - 1;
15508 const uint8_t *end = parse_operator_symbol_name(&parser->
current);
15510 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15511 parser_lex(parser);
15514 pm_node_flag_set(UP(symbol), PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING);
15528 if (lex_mode->
mode != PM_LEX_STRING) {
15529 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15531 switch (parser->
current.type) {
15532 case PM_CASE_OPERATOR:
15533 return parse_operator_symbol(parser, &opening, next_state == PM_LEX_STATE_NONE ? PM_LEX_STATE_ENDFN : next_state);
15534 case PM_TOKEN_IDENTIFIER:
15535 case PM_TOKEN_CONSTANT:
15536 case PM_TOKEN_INSTANCE_VARIABLE:
15537 case PM_TOKEN_METHOD_NAME:
15538 case PM_TOKEN_CLASS_VARIABLE:
15539 case PM_TOKEN_GLOBAL_VARIABLE:
15540 case PM_TOKEN_NUMBERED_REFERENCE:
15541 case PM_TOKEN_BACK_REFERENCE:
15542 case PM_CASE_KEYWORD:
15543 parser_lex(parser);
15546 expect2(parser, PM_TOKEN_IDENTIFIER, PM_TOKEN_METHOD_NAME, PM_ERR_SYMBOL_INVALID);
15554 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->
previous, &symbol->
unescaped,
false));
15561 if (match1(parser, PM_TOKEN_STRING_END)) {
15562 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15563 parser_lex(parser);
15567 return UP(pm_symbol_node_create(parser, &opening, &content, &closing));
15571 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
15575 if (part && PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
15576 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15577 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
15583 if (part) pm_interpolated_symbol_node_append(symbol, part);
15585 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
15586 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
15587 pm_interpolated_symbol_node_append(symbol, part);
15591 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15592 if (match1(parser, PM_TOKEN_EOF)) {
15593 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_INTERPOLATED);
15595 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
15598 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
15605 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
15608 parser_lex(parser);
15619 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
15623 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &unescaped));
15624 pm_interpolated_symbol_node_append(symbol, part);
15626 part = UP(pm_string_node_create_unescaped(parser, &bounds, &parser->
current, &bounds, &parser->
current_string));
15627 pm_interpolated_symbol_node_append(symbol, part);
15629 if (next_state != PM_LEX_STATE_NONE) {
15630 lex_state_set(parser, next_state);
15633 parser_lex(parser);
15634 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
15636 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
15641 pm_string_shared_init(&unescaped, content.
start, content.
end);
15644 if (next_state != PM_LEX_STATE_NONE) {
15645 lex_state_set(parser, next_state);
15648 if (match1(parser, PM_TOKEN_EOF)) {
15649 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_DYNAMIC);
15651 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
15654 return UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
false)));
15662parse_undef_argument(
pm_parser_t *parser, uint16_t depth) {
15663 switch (parser->
current.type) {
15664 case PM_CASE_OPERATOR: {
15665 const pm_token_t opening = not_provided(parser);
15666 return parse_operator_symbol(parser, &opening, PM_LEX_STATE_NONE);
15668 case PM_CASE_KEYWORD:
15669 case PM_TOKEN_CONSTANT:
15670 case PM_TOKEN_IDENTIFIER:
15671 case PM_TOKEN_METHOD_NAME: {
15672 parser_lex(parser);
15679 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->
previous, &symbol->
unescaped,
false));
15683 case PM_TOKEN_SYMBOL_BEGIN: {
15685 parser_lex(parser);
15687 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
15690 pm_parser_err_current(parser, PM_ERR_UNDEF_ARGUMENT);
15691 return UP(pm_missing_node_create(parser, parser->
current.start, parser->
current.end));
15702parse_alias_argument(
pm_parser_t *parser,
bool first, uint16_t depth) {
15703 switch (parser->
current.type) {
15704 case PM_CASE_OPERATOR: {
15705 const pm_token_t opening = not_provided(parser);
15706 return parse_operator_symbol(parser, &opening, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
15708 case PM_CASE_KEYWORD:
15709 case PM_TOKEN_CONSTANT:
15710 case PM_TOKEN_IDENTIFIER:
15711 case PM_TOKEN_METHOD_NAME: {
15712 if (first) lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
15713 parser_lex(parser);
15720 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->
previous, &symbol->
unescaped,
false));
15724 case PM_TOKEN_SYMBOL_BEGIN: {
15726 parser_lex(parser);
15728 return parse_symbol(parser, &lex_mode, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
15730 case PM_TOKEN_BACK_REFERENCE:
15731 parser_lex(parser);
15732 return UP(pm_back_reference_read_node_create(parser, &parser->
previous));
15733 case PM_TOKEN_NUMBERED_REFERENCE:
15734 parser_lex(parser);
15735 return UP(pm_numbered_reference_read_node_create(parser, &parser->
previous));
15736 case PM_TOKEN_GLOBAL_VARIABLE:
15737 parser_lex(parser);
15738 return UP(pm_global_variable_read_node_create(parser, &parser->
previous));
15740 pm_parser_err_current(parser, PM_ERR_ALIAS_ARGUMENT);
15741 return UP(pm_missing_node_create(parser, parser->
current.start, parser->
current.end));
15755 if (!is_numbered_param && ((depth = pm_parser_local_depth_constant_id(parser, name_id)) != -1)) {
15756 return UP(pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, (uint32_t) depth,
false));
15760 if (!current_scope->
closed && !(current_scope->
parameters & PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED)) {
15761 if (is_numbered_param) {
15766 uint8_t maximum = (uint8_t) (parser->
previous.
start[1] -
'0');
15767 for (uint8_t number = 1; number <= maximum; number++) {
15768 pm_parser_local_add_constant(parser, pm_numbered_parameter_names[number - 1], 2);
15771 if (!match1(parser, PM_TOKEN_EQUAL)) {
15775 pm_node_t *node = UP(pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, 0,
false));
15780 pm_node_t *node = UP(pm_it_local_variable_read_node_create(parser, &parser->
previous));
15795 pm_node_flags_t flags = 0;
15797 if (!match1(parser, PM_TOKEN_PARENTHESIS_LEFT) && (parser->
previous.
end[-1] !=
'!') && (parser->
previous.
end[-1] !=
'?')) {
15798 pm_node_t *node = parse_variable(parser);
15799 if (node != NULL)
return node;
15800 flags |= PM_CALL_NODE_FLAGS_VARIABLE_CALL;
15804 pm_node_flag_set(UP(node), flags);
15815parse_method_definition_name(
pm_parser_t *parser) {
15816 switch (parser->
current.type) {
15817 case PM_CASE_KEYWORD:
15818 case PM_TOKEN_CONSTANT:
15819 case PM_TOKEN_METHOD_NAME:
15820 parser_lex(parser);
15822 case PM_TOKEN_IDENTIFIER:
15823 pm_refute_numbered_parameter(parser, parser->
current.start, parser->
current.end);
15824 parser_lex(parser);
15826 case PM_CASE_OPERATOR:
15827 lex_state_set(parser, PM_LEX_STATE_ENDFN);
15828 parser_lex(parser);
15837parse_heredoc_dedent_string(
pm_string_t *
string,
size_t common_whitespace) {
15840 pm_string_ensure_owned(
string);
15846 const uint8_t *source_cursor = (uint8_t *) string->
source;
15847 const uint8_t *source_end = source_cursor + dest_length;
15852 size_t trimmed_whitespace = 0;
15858 while ((source_cursor < source_end) && pm_char_is_inline_whitespace(*source_cursor) && trimmed_whitespace < common_whitespace) {
15859 if (*source_cursor ==
'\t') {
15860 trimmed_whitespace = (trimmed_whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
15861 if (trimmed_whitespace > common_whitespace)
break;
15863 trimmed_whitespace++;
15870 memmove((uint8_t *) string->source, source_cursor, (
size_t) (source_end - source_cursor));
15871 string->length = dest_length;
15881 bool dedent_next =
true;
15886 size_t write_index = 0;
15893 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE)) {
15894 nodes->
nodes[write_index++] = node;
15895 dedent_next =
false;
15901 parse_heredoc_dedent_string(&string_node->
unescaped, common_whitespace);
15905 pm_node_destroy(parser, node);
15907 nodes->
nodes[write_index++] = node;
15911 dedent_next =
true;
15914 nodes->
size = write_index;
15921parse_strings_empty_content(
const uint8_t *location) {
15922 return (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = location, .end = location };
15930 assert(parser->
current.type == PM_TOKEN_STRING_BEGIN);
15931 bool concating =
false;
15933 while (match1(parser, PM_TOKEN_STRING_BEGIN)) {
15939 assert(lex_mode->
mode == PM_LEX_STRING);
15941 bool label_allowed = lex_mode->
as.string.
label_allowed && accepts_label;
15944 parser_lex(parser);
15946 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
15947 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
15956 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
15966 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
15967 }
else if (!lex_interpolation) {
15973 if (match1(parser, PM_TOKEN_EOF)) {
15975 content = not_provided(parser);
15978 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_EXPECT_STRING_CONTENT);
15993 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
15996 pm_token_t delimiters = not_provided(parser);
15997 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, &delimiters, &content, &delimiters, &unescaped));
15998 pm_node_list_append(&parts, part);
16001 part = UP(pm_string_node_create_current_string(parser, &delimiters, &parser->
current, &delimiters));
16002 pm_node_list_append(&parts, part);
16003 parser_lex(parser);
16004 }
while (match1(parser, PM_TOKEN_STRING_CONTENT));
16006 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16007 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous));
16009 pm_node_list_free(&parts);
16010 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16011 node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true)));
16012 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16013 }
else if (match1(parser, PM_TOKEN_EOF)) {
16014 pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
16015 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped));
16016 }
else if (accept1(parser, PM_TOKEN_STRING_END)) {
16017 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped));
16022 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped));
16024 }
else if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16031 parser_lex(parser);
16033 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16034 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped));
16035 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16041 if (!accept1(parser, PM_TOKEN_STRING_END)) {
16043 if (location > parser->
start && location[-1] ==
'\n') location--;
16044 pm_parser_err(parser, location, location, PM_ERR_STRING_LITERAL_EOF);
16049 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16050 node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true)));
16051 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16056 pm_token_t string_opening = not_provided(parser);
16057 pm_token_t string_closing = not_provided(parser);
16059 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, &string_opening, &parser->
previous, &string_closing, &unescaped));
16060 pm_node_flag_set(part, parse_unescaped_encoding(parser));
16061 pm_node_list_append(&parts, part);
16063 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16064 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16065 pm_node_list_append(&parts, part);
16069 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16070 node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous));
16071 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16072 }
else if (match1(parser, PM_TOKEN_EOF)) {
16073 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16074 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current));
16076 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16077 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous));
16080 pm_node_list_free(&parts);
16089 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16090 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16091 pm_node_list_append(&parts, part);
16095 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16096 node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous));
16097 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16098 }
else if (match1(parser, PM_TOKEN_EOF)) {
16099 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16100 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current));
16102 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16103 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous));
16106 pm_node_list_free(&parts);
16109 if (current == NULL) {
16113 if (PM_NODE_TYPE_P(node, PM_SYMBOL_NODE) || PM_NODE_TYPE_P(node, PM_INTERPOLATED_SYMBOL_NODE)) {
16124 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE) && !PM_NODE_TYPE_P(node, PM_INTERPOLATED_STRING_NODE)) {
16125 pm_parser_err_node(parser, node, PM_ERR_STRING_CONCATENATION);
16131 if (!PM_NODE_TYPE_P(current, PM_STRING_NODE) && !PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
16132 pm_parser_err_node(parser, current, PM_ERR_STRING_CONCATENATION);
16139 pm_interpolated_string_node_append(container, current);
16140 current = UP(container);
16150#define PM_PARSE_PATTERN_SINGLE 0
16151#define PM_PARSE_PATTERN_TOP 1
16152#define PM_PARSE_PATTERN_MULTI 2
16165 if (peek_at(parser, location->
start) ==
'_')
return;
16167 if (pm_constant_id_list_includes(captures, capture)) {
16168 pm_parser_err(parser, location->
start, location->
end, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
16170 pm_constant_id_list_append(captures, capture);
16181 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
16183 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
16184 node = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous));
16190 if (!match2(parser, PM_TOKEN_BRACKET_LEFT, PM_TOKEN_PARENTHESIS_LEFT)) {
16198 if (accept1(parser, PM_TOKEN_BRACKET_LEFT)) {
16200 accept1(parser, PM_TOKEN_NEWLINE);
16202 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
16203 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16204 accept1(parser, PM_TOKEN_NEWLINE);
16205 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET);
16210 parser_lex(parser);
16212 accept1(parser, PM_TOKEN_NEWLINE);
16214 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
16215 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
16216 accept1(parser, PM_TOKEN_NEWLINE);
16217 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
16226 return UP(pm_array_pattern_node_constant_create(parser, node, &opening, &closing));
16233 switch (PM_NODE_TYPE(inner)) {
16234 case PM_ARRAY_PATTERN_NODE: {
16242 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16243 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16245 return UP(pattern_node);
16250 case PM_FIND_PATTERN_NODE: {
16258 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16259 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16261 return UP(pattern_node);
16266 case PM_HASH_PATTERN_NODE: {
16274 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16275 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16277 return UP(pattern_node);
16289 pm_array_pattern_node_t *pattern_node = pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
16290 pm_array_pattern_node_requireds_append(pattern_node, inner);
16291 return UP(pattern_node);
16306 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
16308 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &identifier);
16311 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16312 pm_parser_local_add(parser, constant_id, identifier.
start, identifier.
end, 0);
16315 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&identifier));
16316 name = UP(pm_local_variable_target_node_create(
16318 &PM_LOCATION_TOKEN_VALUE(&identifier),
16320 (uint32_t) (depth == -1 ? 0 : depth)
16325 return pm_splat_node_create(parser, &
operator, name);
16333 assert(parser->
current.type == PM_TOKEN_USTAR_STAR);
16334 parser_lex(parser);
16339 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
16340 return UP(pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous));
16343 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
16347 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16351 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
16352 value = UP(pm_local_variable_target_node_create(
16354 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
16356 (uint32_t) (depth == -1 ? 0 : depth)
16360 return UP(pm_assoc_splat_node_create(parser, value, &
operator));
16368pm_slice_is_valid_local(
const pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
16369 ptrdiff_t length = end - start;
16370 if (length == 0)
return false;
16373 size_t width = char_is_identifier_start(parser, start, end - start);
16374 if (width == 0)
return false;
16380 if (pm_encoding_utf_8_isupper_char(start, length))
return false;
16385 const uint8_t *cursor = start + width;
16386 while ((width = char_is_identifier(parser, cursor, end - cursor))) cursor += width;
16387 return cursor == end;
16401 if (pm_slice_is_valid_local(parser, value_loc->
start, value_loc->
end)) {
16402 depth = pm_parser_local_depth_constant_id(parser, constant_id);
16404 pm_parser_err(parser, key->base.location.start, key->base.location.end, PM_ERR_PATTERN_HASH_KEY_LOCALS);
16406 if ((value_loc->
end > value_loc->
start) && ((value_loc->
end[-1] ==
'!') || (value_loc->
end[-1] ==
'?'))) {
16407 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);
16412 pm_parser_local_add(parser, constant_id, value_loc->
start, value_loc->
end, 0);
16415 parse_pattern_capture(parser, captures, constant_id, value_loc);
16420 (uint32_t) (depth == -1 ? 0 : depth)
16423 return UP(pm_implicit_node_create(parser, UP(target)));
16433 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
16446 switch (PM_NODE_TYPE(first_node)) {
16447 case PM_ASSOC_SPLAT_NODE:
16448 case PM_NO_KEYWORDS_PARAMETER_NODE:
16451 case PM_SYMBOL_NODE: {
16452 if (pm_symbol_node_label_p(first_node)) {
16453 parse_pattern_hash_key(parser, &keys, first_node);
16456 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)) {
16459 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) first_node);
16463 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
16467 pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, &
operator, value));
16469 pm_node_list_append(&assocs, assoc);
16478 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;
16479 pm_parser_err_node(parser, first_node, diag_id);
16483 pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, &
operator, value));
16485 pm_node_list_append(&assocs, assoc);
16491 while (accept1(parser, PM_TOKEN_COMMA)) {
16493 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)) {
16495 if (rest != NULL) {
16496 pm_parser_err_token(parser, &parser->
current, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
16502 if (match1(parser, PM_TOKEN_USTAR_STAR)) {
16503 pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures);
16505 if (rest == NULL) {
16508 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
16509 pm_node_list_append(&assocs, assoc);
16514 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
16515 key = parse_strings(parser, NULL,
true, (uint16_t) (depth + 1));
16517 if (PM_NODE_TYPE_P(key, PM_INTERPOLATED_SYMBOL_NODE)) {
16518 pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
16519 }
else if (!pm_symbol_node_label_p(key)) {
16520 pm_parser_err_node(parser, key, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
16523 expect1(parser, PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
16524 key = UP(pm_symbol_node_label_create(parser, &parser->
previous));
16527 parse_pattern_hash_key(parser, &keys, key);
16530 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)) {
16531 if (PM_NODE_TYPE_P(key, PM_SYMBOL_NODE)) {
16532 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) key);
16534 value = UP(pm_missing_node_create(parser, key->location.end, key->location.end));
16537 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
16541 pm_node_t *assoc = UP(pm_assoc_node_create(parser, key, &
operator, value));
16543 if (rest != NULL) {
16544 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
16547 pm_node_list_append(&assocs, assoc);
16554 pm_static_literals_free(&keys);
16563 switch (parser->
current.type) {
16564 case PM_TOKEN_IDENTIFIER:
16565 case PM_TOKEN_METHOD_NAME: {
16566 parser_lex(parser);
16570 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16574 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
16575 return UP(pm_local_variable_target_node_create(
16577 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
16579 (uint32_t) (depth == -1 ? 0 : depth)
16582 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
16584 parser_lex(parser);
16586 if (accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
16589 return UP(pm_array_pattern_node_empty_create(parser, &opening, &parser->
previous));
16594 pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16596 accept1(parser, PM_TOKEN_NEWLINE);
16597 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET);
16600 switch (PM_NODE_TYPE(inner)) {
16601 case PM_ARRAY_PATTERN_NODE: {
16607 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16608 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16610 return UP(pattern_node);
16615 case PM_FIND_PATTERN_NODE: {
16621 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16622 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16624 return UP(pattern_node);
16634 pm_array_pattern_node_requireds_append(node, inner);
16637 case PM_TOKEN_BRACE_LEFT: {
16643 parser_lex(parser);
16645 if (accept1(parser, PM_TOKEN_BRACE_RIGHT)) {
16648 node = pm_hash_pattern_node_empty_create(parser, &opening, &parser->
previous);
16652 switch (parser->
current.type) {
16653 case PM_TOKEN_LABEL:
16654 parser_lex(parser);
16655 first_node = UP(pm_symbol_node_label_create(parser, &parser->
previous));
16657 case PM_TOKEN_USTAR_STAR:
16658 first_node = parse_pattern_keyword_rest(parser, captures);
16660 case PM_TOKEN_STRING_BEGIN:
16661 first_node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, PM_ERR_PATTERN_HASH_KEY_LABEL, (uint16_t) (depth + 1));
16665 parser_lex(parser);
16672 node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
16674 accept1(parser, PM_TOKEN_NEWLINE);
16675 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE);
16681 node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16682 node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16688 case PM_TOKEN_UDOT_DOT:
16689 case PM_TOKEN_UDOT_DOT_DOT: {
16691 parser_lex(parser);
16695 switch (parser->
current.type) {
16696 case PM_CASE_PRIMITIVE: {
16697 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
16698 return UP(pm_range_node_create(parser, NULL, &
operator, right));
16701 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
16702 pm_node_t *right = UP(pm_missing_node_create(parser,
operator.start,
operator.end));
16703 return UP(pm_range_node_create(parser, NULL, &
operator, right));
16707 case PM_CASE_PRIMITIVE: {
16708 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, diag_id, (uint16_t) (depth + 1));
16711 if (pm_symbol_node_label_p(node))
return node;
16714 if (PM_NODE_TYPE(node) == PM_CALL_NODE) {
16715 pm_parser_err_node(parser, node, diag_id);
16718 pm_node_unreference(parser, node);
16719 pm_node_destroy(parser, node);
16720 return UP(missing_node);
16724 if (accept2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
16730 switch (parser->
current.type) {
16731 case PM_CASE_PRIMITIVE: {
16732 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
16733 return UP(pm_range_node_create(parser, node, &
operator, right));
16736 return UP(pm_range_node_create(parser, node, &
operator, NULL));
16742 case PM_TOKEN_CARET: {
16743 parser_lex(parser);
16748 switch (parser->
current.type) {
16749 case PM_TOKEN_IDENTIFIER: {
16750 parser_lex(parser);
16751 pm_node_t *variable = UP(parse_variable(parser));
16753 if (variable == NULL) {
16754 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
previous, PM_ERR_NO_LOCAL_VARIABLE);
16755 variable = UP(pm_local_variable_read_node_missing_create(parser, &parser->
previous, 0));
16758 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16760 case PM_TOKEN_INSTANCE_VARIABLE: {
16761 parser_lex(parser);
16762 pm_node_t *variable = UP(pm_instance_variable_read_node_create(parser, &parser->
previous));
16764 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16766 case PM_TOKEN_CLASS_VARIABLE: {
16767 parser_lex(parser);
16768 pm_node_t *variable = UP(pm_class_variable_read_node_create(parser, &parser->
previous));
16770 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16772 case PM_TOKEN_GLOBAL_VARIABLE: {
16773 parser_lex(parser);
16774 pm_node_t *variable = UP(pm_global_variable_read_node_create(parser, &parser->
previous));
16776 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16778 case PM_TOKEN_NUMBERED_REFERENCE: {
16779 parser_lex(parser);
16780 pm_node_t *variable = UP(pm_numbered_reference_read_node_create(parser, &parser->
previous));
16782 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16784 case PM_TOKEN_BACK_REFERENCE: {
16785 parser_lex(parser);
16786 pm_node_t *variable = UP(pm_back_reference_read_node_create(parser, &parser->
previous));
16788 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16790 case PM_TOKEN_PARENTHESIS_LEFT: {
16795 parser_lex(parser);
16797 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN, (uint16_t) (depth + 1));
16800 accept1(parser, PM_TOKEN_NEWLINE);
16801 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
16802 return UP(pm_pinned_expression_node_create(parser, expression, &
operator, &lparen, &parser->
previous));
16807 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
16808 pm_node_t *variable = UP(pm_missing_node_create(parser,
operator.start,
operator.end));
16809 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16813 case PM_TOKEN_UCOLON_COLON: {
16815 parser_lex(parser);
16817 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
16820 return parse_pattern_constant_path(parser, captures, UP(node), (uint16_t) (depth + 1));
16822 case PM_TOKEN_CONSTANT: {
16824 parser_lex(parser);
16826 pm_node_t *node = UP(pm_constant_read_node_create(parser, &constant));
16827 return parse_pattern_constant_path(parser, captures, node, (uint16_t) (depth + 1));
16830 pm_parser_err_current(parser, diag_id);
16831 return UP(pm_missing_node_create(parser, parser->
current.start, parser->
current.end));
16836parse_pattern_alternation_error_each(
const pm_node_t *node,
void *data) {
16837 switch (PM_NODE_TYPE(node)) {
16838 case PM_LOCAL_VARIABLE_TARGET_NODE:
16852 pm_visit_node(node, parse_pattern_alternation_error_each, parser);
16862 bool alternation =
false;
16864 while ((node == NULL) || (alternation = accept1(parser, PM_TOKEN_PIPE))) {
16865 if (alternation && !PM_NODE_TYPE_P(node, PM_ALTERNATION_PATTERN_NODE) && captures->
size) {
16866 parse_pattern_alternation_error(parser, node);
16869 switch (parser->
current.type) {
16870 case PM_TOKEN_IDENTIFIER:
16871 case PM_TOKEN_BRACKET_LEFT_ARRAY:
16872 case PM_TOKEN_BRACE_LEFT:
16873 case PM_TOKEN_CARET:
16874 case PM_TOKEN_CONSTANT:
16875 case PM_TOKEN_UCOLON_COLON:
16876 case PM_TOKEN_UDOT_DOT:
16877 case PM_TOKEN_UDOT_DOT_DOT:
16878 case PM_CASE_PRIMITIVE: {
16879 if (!alternation) {
16880 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
16883 pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
16885 if (captures->
size) parse_pattern_alternation_error(parser, right);
16886 node = UP(pm_alternation_pattern_node_create(parser, node, right, &
operator));
16891 case PM_TOKEN_PARENTHESIS_LEFT:
16892 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
16895 parser_lex(parser);
16897 pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
16898 accept1(parser, PM_TOKEN_NEWLINE);
16899 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
16900 pm_node_t *right = UP(pm_parentheses_node_create(parser, &opening, body, &parser->
previous, 0));
16902 if (!alternation) {
16905 if (captures->
size) parse_pattern_alternation_error(parser, right);
16906 node = UP(pm_alternation_pattern_node_create(parser, node, right, &
operator));
16912 pm_parser_err_current(parser, diag_id);
16915 if (!alternation) {
16918 if (captures->
size) parse_pattern_alternation_error(parser, right);
16919 node = UP(pm_alternation_pattern_node_create(parser, node, right, &parser->
previous));
16929 while (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
16931 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_PATTERN_IDENT_AFTER_HROCKET);
16936 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16940 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
16943 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
16945 (uint32_t) (depth == -1 ? 0 : depth)
16948 node = UP(pm_capture_pattern_node_create(parser, node, target, &
operator));
16961 bool leading_rest =
false;
16962 bool trailing_rest =
false;
16964 switch (parser->
current.type) {
16965 case PM_TOKEN_LABEL: {
16966 parser_lex(parser);
16968 node = UP(parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1)));
16970 if (!(flags & PM_PARSE_PATTERN_TOP)) {
16971 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
16976 case PM_TOKEN_USTAR_STAR: {
16977 node = parse_pattern_keyword_rest(parser, captures);
16978 node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
16980 if (!(flags & PM_PARSE_PATTERN_TOP)) {
16981 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
16986 case PM_TOKEN_STRING_BEGIN: {
16989 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
16991 if (pm_symbol_node_label_p(node)) {
16992 node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
16994 if (!(flags & PM_PARSE_PATTERN_TOP)) {
16995 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17001 node = parse_pattern_primitives(parser, captures, node, diag_id, (uint16_t) (depth + 1));
17004 case PM_TOKEN_USTAR: {
17005 if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
17006 parser_lex(parser);
17007 node = UP(parse_pattern_rest(parser, captures));
17008 leading_rest =
true;
17014 node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1));
17020 if (pm_symbol_node_label_p(node)) {
17021 return UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17024 if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser, PM_TOKEN_COMMA)) {
17029 pm_node_list_append(&nodes, node);
17032 while (accept1(parser, PM_TOKEN_COMMA)) {
17034 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)) {
17035 node = UP(pm_implicit_rest_node_create(parser, &parser->
previous));
17036 pm_node_list_append(&nodes, node);
17037 trailing_rest =
true;
17041 if (accept1(parser, PM_TOKEN_USTAR)) {
17042 node = UP(parse_pattern_rest(parser, captures));
17047 if (trailing_rest) {
17048 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
17051 trailing_rest =
true;
17053 node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
17056 pm_node_list_append(&nodes, node);
17063 if (leading_rest && PM_NODE_TYPE_P(nodes.
nodes[nodes.
size - 1], PM_SPLAT_NODE)) {
17064 node = UP(pm_find_pattern_node_create(parser, &nodes));
17066 if (nodes.
size == 2) {
17067 pm_parser_err_node(parser, node, PM_ERR_PATTERN_FIND_MISSING_INNER);
17070 node = UP(pm_array_pattern_node_node_list_create(parser, &nodes));
17072 if (leading_rest && trailing_rest) {
17073 pm_parser_err_node(parser, node, PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS);
17078 }
else if (leading_rest) {
17081 node = UP(pm_array_pattern_node_rest_create(parser, node));
17093parse_negative_numeric(
pm_node_t *node) {
17094 switch (PM_NODE_TYPE(node)) {
17095 case PM_INTEGER_NODE: {
17101 case PM_FLOAT_NODE: {
17107 case PM_RATIONAL_NODE: {
17113 case PM_IMAGINARY_NODE:
17118 assert(
false &&
"unreachable");
17131 case PM_ERR_HASH_KEY: {
17135 case PM_ERR_HASH_VALUE:
17136 case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: {
17140 case PM_ERR_UNARY_RECEIVER: {
17145 case PM_ERR_UNARY_DISALLOWED:
17146 case PM_ERR_EXPECT_ARGUMENT: {
17151 pm_parser_err_previous(parser, diag_id);
17161#define CONTEXT_NONE 0
17162#define CONTEXT_THROUGH_ENSURE 1
17163#define CONTEXT_THROUGH_ELSE 2
17166 int context = CONTEXT_NONE;
17168 while (context_node != NULL) {
17169 switch (context_node->
context) {
17190 if (context == CONTEXT_NONE) {
17191 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_WITHOUT_RESCUE);
17192 }
else if (context == CONTEXT_THROUGH_ENSURE) {
17193 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ENSURE);
17194 }
else if (context == CONTEXT_THROUGH_ELSE) {
17195 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ELSE);
17207 context = CONTEXT_THROUGH_ELSE;
17218 context = CONTEXT_THROUGH_ENSURE;
17222 assert(
false &&
"unreachable");
17253 context_node = context_node->
prev;
17257#undef CONTEXT_ENSURE
17268 while (context_node != NULL) {
17269 switch (context_node->
context) {
17294 pm_parser_err_node(parser, node, PM_ERR_INVALID_YIELD);
17298 assert(
false &&
"unreachable");
17340 context_node = context_node->
prev;
17372parse_regular_expression_error(
const uint8_t *start,
const uint8_t *end,
const char *message,
void *data) {
17376 if (callback_data->
shared) {
17382 PM_PARSER_ERR_FORMAT(callback_data->
parser, location.
start, location.
end, PM_ERR_REGEXP_PARSE_ERROR, message);
17395 .shared = unescaped->
type == PM_STRING_SHARED
17398 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);
17405parse_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) {
17406 switch (parser->
current.type) {
17407 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
17408 parser_lex(parser);
17411 pm_accepts_block_stack_push(parser,
true);
17412 bool parsed_bare_hash =
false;
17414 while (!match2(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_EOF)) {
17415 bool accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
17419 if (accepted_newline && match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17425 if (accept1(parser, PM_TOKEN_COMMA)) {
17428 if (accepted_newline) {
17429 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
17445 if (match1(parser, PM_TOKEN_BRACKET_RIGHT))
break;
17449 if (accept1(parser, PM_TOKEN_USTAR)) {
17453 if (match3(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_EOF)) {
17454 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
17456 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
17459 element = UP(pm_splat_node_create(parser, &
operator, expression));
17460 }
else if (match2(parser, PM_TOKEN_LABEL, PM_TOKEN_USTAR_STAR)) {
17461 if (parsed_bare_hash) {
17462 pm_parser_err_current(parser, PM_ERR_EXPRESSION_BARE_HASH);
17465 element = UP(pm_keyword_hash_node_create(parser));
17468 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)) {
17469 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
17472 pm_static_literals_free(&hash_keys);
17473 parsed_bare_hash =
true;
17475 element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_ARRAY_EXPRESSION, (uint16_t) (depth + 1));
17477 if (pm_symbol_node_label_p(element) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
17478 if (parsed_bare_hash) {
17479 pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
17484 pm_hash_key_static_literals_add(parser, &hash_keys, element);
17487 if (parser->
previous.
type == PM_TOKEN_EQUAL_GREATER) {
17490 operator = not_provided(parser);
17493 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
17494 pm_node_t *assoc = UP(pm_assoc_node_create(parser, element, &
operator, value));
17495 pm_keyword_hash_node_elements_append(hash, assoc);
17497 element = UP(hash);
17498 if (accept1(parser, PM_TOKEN_COMMA) && !match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17499 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
17502 pm_static_literals_free(&hash_keys);
17503 parsed_bare_hash =
true;
17507 pm_array_node_elements_append(array, element);
17508 if (PM_NODE_TYPE_P(element, PM_MISSING_NODE))
break;
17511 accept1(parser, PM_TOKEN_NEWLINE);
17513 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17519 pm_array_node_close_set(array, &parser->
previous);
17520 pm_accepts_block_stack_pop(parser);
17524 case PM_TOKEN_PARENTHESIS_LEFT:
17525 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
17527 pm_node_flags_t flags = 0;
17530 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
17532 parser_lex(parser);
17534 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
17535 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
17536 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
17543 if (match2(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_EOF)) {
17544 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
17546 pop_block_exits(parser, previous_block_exits);
17547 pm_node_list_free(¤t_block_exits);
17549 return UP(pm_parentheses_node_create(parser, &opening, NULL, &parser->
previous, flags));
17554 pm_accepts_block_stack_push(parser,
true);
17556 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
17557 context_pop(parser);
17562 bool terminator_found =
false;
17564 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
17565 terminator_found =
true;
17566 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
17567 }
else if (accept1(parser, PM_TOKEN_NEWLINE)) {
17568 terminator_found =
true;
17571 if (terminator_found) {
17573 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
17574 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
17575 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
17584 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
17585 if (opening.
type == PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
17586 lex_state_set(parser, PM_LEX_STATE_ENDARG);
17589 parser_lex(parser);
17590 pm_accepts_block_stack_pop(parser);
17592 pop_block_exits(parser, previous_block_exits);
17593 pm_node_list_free(¤t_block_exits);
17595 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) || PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
17601 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) && ((
pm_multi_target_node_t *) statement)->lparen_loc.start == NULL) {
17604 multi_target = pm_multi_target_node_create(parser);
17605 pm_multi_target_node_targets_append(parser, multi_target, statement);
17608 pm_location_t lparen_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17617 if (match1(parser, PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
17618 result = parse_targets(parser, UP(multi_target), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17619 accept1(parser, PM_TOKEN_NEWLINE);
17621 result = UP(multi_target);
17630 }
else if (binding_power != PM_BINDING_POWER_STATEMENT) {
17633 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
17634 }
else if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
17638 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
17648 pm_statements_node_body_append(parser, statements, statement,
true);
17650 return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->
previous, flags));
17657 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
17660 pm_statements_node_body_append(parser, statements, statement,
true);
17664 if (!terminator_found && !match1(parser, PM_TOKEN_EOF)) {
17670 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
17671 pm_statements_node_body_append(parser, statements, node,
true);
17678 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) parser->
recovering =
false;
17684 if (PM_NODE_TYPE_P(node, PM_MISSING_NODE))
break;
17688 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
17689 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
17690 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
break;
17691 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
17693 }
else if (!match1(parser, PM_TOKEN_EOF)) {
17700 context_pop(parser);
17701 pm_accepts_block_stack_pop(parser);
17702 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
17711 if (PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
17713 pm_multi_target_node_targets_append(parser, multi_target, statement);
17715 statement = UP(multi_target);
17719 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE)) {
17721 pm_token_t operator = { .
type = PM_TOKEN_EQUAL, .start = offset, .end = offset };
17722 pm_node_t *value = UP(pm_missing_node_create(parser, offset, offset));
17724 statement = UP(pm_multi_write_node_create(parser, (
pm_multi_target_node_t *) statement, &
operator, value));
17727 pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
17731 pop_block_exits(parser, previous_block_exits);
17732 pm_node_list_free(¤t_block_exits);
17734 pm_void_statements_check(parser, statements,
true);
17735 return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->
previous, flags));
17737 case PM_TOKEN_BRACE_LEFT: {
17748 pm_accepts_block_stack_push(parser,
true);
17749 parser_lex(parser);
17753 if (!match2(parser, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_EOF)) {
17754 if (current_hash_keys != NULL) {
17755 parse_assocs(parser, current_hash_keys, UP(node), (uint16_t) (depth + 1));
17758 parse_assocs(parser, &hash_keys, UP(node), (uint16_t) (depth + 1));
17759 pm_static_literals_free(&hash_keys);
17762 accept1(parser, PM_TOKEN_NEWLINE);
17765 pm_accepts_block_stack_pop(parser);
17766 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM);
17767 pm_hash_node_closing_loc_set(node, &parser->
previous);
17771 case PM_TOKEN_CHARACTER_LITERAL: {
17773 pm_node_t *node = UP(pm_string_node_create_current_string(
17776 .type = PM_TOKEN_STRING_BEGIN,
17777 .start = parser->
current.start,
17778 .end = parser->
current.start + 1
17781 .type = PM_TOKEN_STRING_CONTENT,
17782 .start = parser->
current.start + 1,
17788 pm_node_flag_set(node, parse_unescaped_encoding(parser));
17792 parser_lex(parser);
17796 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
17797 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
17802 case PM_TOKEN_CLASS_VARIABLE: {
17803 parser_lex(parser);
17804 pm_node_t *node = UP(pm_class_variable_read_node_create(parser, &parser->
previous));
17806 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
17807 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17812 case PM_TOKEN_CONSTANT: {
17813 parser_lex(parser);
17819 match1(parser, PM_TOKEN_PARENTHESIS_LEFT) ||
17820 (accepts_command_call && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
17821 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
17822 match1(parser, PM_TOKEN_BRACE_LEFT)
17825 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
17826 return UP(pm_call_node_fcall_create(parser, &constant, &arguments));
17831 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
17834 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17839 case PM_TOKEN_UCOLON_COLON: {
17840 parser_lex(parser);
17843 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
17844 pm_node_t *node = UP(pm_constant_path_node_create(parser, NULL, &delimiter, &parser->
previous));
17846 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
17847 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17852 case PM_TOKEN_UDOT_DOT:
17853 case PM_TOKEN_UDOT_DOT_DOT: {
17855 parser_lex(parser);
17857 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));
17863 if (match2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
17864 pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
17867 return UP(pm_range_node_create(parser, NULL, &
operator, right));
17869 case PM_TOKEN_FLOAT:
17870 parser_lex(parser);
17871 return UP(pm_float_node_create(parser, &parser->
previous));
17872 case PM_TOKEN_FLOAT_IMAGINARY:
17873 parser_lex(parser);
17874 return UP(pm_float_node_imaginary_create(parser, &parser->
previous));
17875 case PM_TOKEN_FLOAT_RATIONAL:
17876 parser_lex(parser);
17877 return UP(pm_float_node_rational_create(parser, &parser->
previous));
17878 case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY:
17879 parser_lex(parser);
17880 return UP(pm_float_node_rational_imaginary_create(parser, &parser->
previous));
17881 case PM_TOKEN_NUMBERED_REFERENCE: {
17882 parser_lex(parser);
17883 pm_node_t *node = UP(pm_numbered_reference_read_node_create(parser, &parser->
previous));
17885 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
17886 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17891 case PM_TOKEN_GLOBAL_VARIABLE: {
17892 parser_lex(parser);
17893 pm_node_t *node = UP(pm_global_variable_read_node_create(parser, &parser->
previous));
17895 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
17896 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17901 case PM_TOKEN_BACK_REFERENCE: {
17902 parser_lex(parser);
17903 pm_node_t *node = UP(pm_back_reference_read_node_create(parser, &parser->
previous));
17905 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
17906 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17911 case PM_TOKEN_IDENTIFIER:
17912 case PM_TOKEN_METHOD_NAME: {
17913 parser_lex(parser);
17915 pm_node_t *node = parse_variable_call(parser);
17917 if (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
17925 if (parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1))) {
17928 pm_node_flag_unset(UP(call), PM_CALL_NODE_FLAGS_VARIABLE_CALL);
17935 const uint8_t *end = pm_arguments_end(&arguments);
17946 (accepts_command_call && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
17947 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
17948 match1(parser, PM_TOKEN_BRACE_LEFT)
17951 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
17952 pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
17954 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
17958 pm_node_unreference(parser, node);
17964 assert(PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE));
17966 if (pm_token_is_numbered_parameter(identifier.
start, identifier.
end)) {
17967 pm_node_unreference(parser, node);
17970 pm_locals_unread(&pm_parser_scope_find(parser, cast->
depth)->
locals, cast->
name);
17974 pm_node_destroy(parser, node);
17979 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
17980 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17985 case PM_TOKEN_HEREDOC_START: {
17991 size_t common_whitespace = (size_t) -1;
17994 parser_lex(parser);
18000 if (match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18006 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18007 node = UP(pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->
previous, &
PM_STRING_EMPTY));
18013 }
else if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) == NULL) {
18021 }
else if (PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18026 pm_node_flag_set(part, parse_unescaped_encoding(parser));
18029 cast->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
18033 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18035 cast->
base.
type = PM_X_STRING_NODE;
18038 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18039 parse_heredoc_dedent_string(&cast->
unescaped, common_whitespace);
18049 pm_node_list_append(&parts, part);
18051 while (!match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18052 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
18053 pm_node_list_append(&parts, part);
18059 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18061 cast->
parts = parts;
18064 pm_interpolated_xstring_node_closing_set(cast, &parser->
previous);
18070 pm_node_list_free(&parts);
18073 pm_interpolated_string_node_closing_set(cast, &parser->
previous);
18081 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18083 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18089 parse_heredoc_dedent(parser, nodes, common_whitespace);
18093 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
18094 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18099 case PM_TOKEN_INSTANCE_VARIABLE: {
18100 parser_lex(parser);
18101 pm_node_t *node = UP(pm_instance_variable_read_node_create(parser, &parser->
previous));
18103 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18104 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18109 case PM_TOKEN_INTEGER: {
18111 parser_lex(parser);
18112 return UP(pm_integer_node_create(parser, base, &parser->
previous));
18114 case PM_TOKEN_INTEGER_IMAGINARY: {
18116 parser_lex(parser);
18117 return UP(pm_integer_node_imaginary_create(parser, base, &parser->
previous));
18119 case PM_TOKEN_INTEGER_RATIONAL: {
18121 parser_lex(parser);
18122 return UP(pm_integer_node_rational_create(parser, base, &parser->
previous));
18124 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: {
18126 parser_lex(parser);
18127 return UP(pm_integer_node_rational_imaginary_create(parser, base, &parser->
previous));
18129 case PM_TOKEN_KEYWORD___ENCODING__:
18130 parser_lex(parser);
18131 return UP(pm_source_encoding_node_create(parser, &parser->
previous));
18132 case PM_TOKEN_KEYWORD___FILE__:
18133 parser_lex(parser);
18134 return UP(pm_source_file_node_create(parser, &parser->
previous));
18135 case PM_TOKEN_KEYWORD___LINE__:
18136 parser_lex(parser);
18137 return UP(pm_source_line_node_create(parser, &parser->
previous));
18138 case PM_TOKEN_KEYWORD_ALIAS: {
18139 if (binding_power != PM_BINDING_POWER_STATEMENT) {
18140 pm_parser_err_current(parser, PM_ERR_STATEMENT_ALIAS);
18143 parser_lex(parser);
18146 pm_node_t *new_name = parse_alias_argument(parser,
true, (uint16_t) (depth + 1));
18147 pm_node_t *old_name = parse_alias_argument(parser,
false, (uint16_t) (depth + 1));
18149 switch (PM_NODE_TYPE(new_name)) {
18150 case PM_BACK_REFERENCE_READ_NODE:
18151 case PM_NUMBERED_REFERENCE_READ_NODE:
18152 case PM_GLOBAL_VARIABLE_READ_NODE: {
18153 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)) {
18154 if (PM_NODE_TYPE_P(old_name, PM_NUMBERED_REFERENCE_READ_NODE)) {
18155 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE);
18158 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18161 return UP(pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name));
18163 case PM_SYMBOL_NODE:
18164 case PM_INTERPOLATED_SYMBOL_NODE: {
18165 if (!PM_NODE_TYPE_P(old_name, PM_SYMBOL_NODE) && !PM_NODE_TYPE_P(old_name, PM_INTERPOLATED_SYMBOL_NODE)) {
18166 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18171 return UP(pm_alias_method_node_create(parser, &keyword, new_name, old_name));
18174 case PM_TOKEN_KEYWORD_CASE: {
18175 size_t opening_newline_index = token_newline_index(parser);
18176 parser_lex(parser);
18182 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18184 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18185 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18187 }
else if (match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_END)) {
18189 }
else if (!token_begins_expression_p(parser->
current.type)) {
18192 predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CASE_EXPRESSION_AFTER_CASE, (uint16_t) (depth + 1));
18193 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18196 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
18197 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18198 parser_lex(parser);
18200 pop_block_exits(parser, previous_block_exits);
18201 pm_node_list_free(¤t_block_exits);
18203 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18204 return UP(pm_case_node_create(parser, &case_keyword, predicate, &parser->
previous));
18209 pm_token_t end_keyword = not_provided(parser);
18212 if (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18213 pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, &end_keyword);
18219 while (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18220 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18221 parser_lex(parser);
18224 pm_when_node_t *when_node = pm_when_node_create(parser, &when_keyword);
18227 if (accept1(parser, PM_TOKEN_USTAR)) {
18229 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
18231 pm_splat_node_t *splat_node = pm_splat_node_create(parser, &
operator, expression);
18232 pm_when_node_conditions_append(when_node, UP(splat_node));
18234 if (PM_NODE_TYPE_P(expression, PM_MISSING_NODE))
break;
18236 pm_node_t *condition = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_CASE_EXPRESSION_AFTER_WHEN, (uint16_t) (depth + 1));
18237 pm_when_node_conditions_append(when_node, condition);
18241 if (PM_NODE_TYPE_P(condition, PM_MISSING_NODE))
break;
18245 if (PM_NODE_TYPE_P(condition, PM_STRING_NODE)) {
18246 pm_node_flag_set(condition, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
18247 }
else if (PM_NODE_TYPE_P(condition, PM_SOURCE_FILE_NODE)) {
18248 pm_node_flag_set(condition, PM_NODE_FLAG_STATIC_LITERAL);
18251 pm_when_clause_static_literals_add(parser, &literals, condition);
18253 }
while (accept1(parser, PM_TOKEN_COMMA));
18255 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18256 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
18257 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
18260 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_WHEN_DELIMITER);
18261 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
18264 if (!match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18266 if (statements != NULL) {
18267 pm_when_node_statements_set(when_node, statements);
18271 pm_case_node_condition_append(case_node, UP(when_node));
18277 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18280 pm_static_literals_free(&literals);
18281 node = UP(case_node);
18283 pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate, &end_keyword);
18287 if (predicate == NULL) {
18288 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MATCH_MISSING_PREDICATE);
18294 while (match1(parser, PM_TOKEN_KEYWORD_IN)) {
18295 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18300 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
18302 parser_lex(parser);
18307 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));
18310 pm_constant_id_list_free(&captures);
18315 if (accept1(parser, PM_TOKEN_KEYWORD_IF_MODIFIER)) {
18317 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
18318 pattern = UP(pm_if_node_modifier_create(parser, pattern, &keyword, predicate));
18319 }
else if (accept1(parser, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) {
18321 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
18322 pattern = UP(pm_unless_node_modifier_create(parser, pattern, &keyword, predicate));
18329 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18330 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
18333 then_keyword = not_provided(parser);
18336 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_IN_DELIMITER);
18343 if (match3(parser, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18351 pm_node_t *condition = UP(pm_in_node_create(parser, pattern, statements, &in_keyword, &then_keyword));
18352 pm_case_match_node_condition_append(case_node, condition);
18358 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18361 node = UP(case_node);
18364 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18365 if (accept1(parser, PM_TOKEN_KEYWORD_ELSE)) {
18369 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
18370 else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser,
PM_CONTEXT_ELSE, (uint16_t) (depth + 1)), &parser->
current);
18372 else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->
current);
18375 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
18376 pm_case_node_else_clause_set((
pm_case_node_t *) node, else_node);
18382 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18383 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM);
18385 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
18391 pop_block_exits(parser, previous_block_exits);
18392 pm_node_list_free(¤t_block_exits);
18396 case PM_TOKEN_KEYWORD_BEGIN: {
18397 size_t opening_newline_index = token_newline_index(parser);
18398 parser_lex(parser);
18401 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18404 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18407 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18408 pm_accepts_block_stack_push(parser,
true);
18409 begin_statements = parse_statements(parser,
PM_CONTEXT_BEGIN, (uint16_t) (depth + 1));
18410 pm_accepts_block_stack_pop(parser);
18411 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18414 pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
18415 parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
18416 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM);
18419 pm_begin_node_end_keyword_set(begin_node, &parser->
previous);
18421 pop_block_exits(parser, previous_block_exits);
18422 pm_node_list_free(¤t_block_exits);
18424 return UP(begin_node);
18426 case PM_TOKEN_KEYWORD_BEGIN_UPCASE: {
18428 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18430 if (binding_power != PM_BINDING_POWER_STATEMENT) {
18431 pm_parser_err_current(parser, PM_ERR_STATEMENT_PREEXE_BEGIN);
18434 parser_lex(parser);
18437 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_BEGIN_UPCASE_BRACE);
18441 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM);
18444 pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
18447 flush_block_exits(parser, previous_block_exits);
18448 pm_node_list_free(¤t_block_exits);
18450 return UP(pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous));
18452 case PM_TOKEN_KEYWORD_BREAK:
18453 case PM_TOKEN_KEYWORD_NEXT:
18454 case PM_TOKEN_KEYWORD_RETURN: {
18455 parser_lex(parser);
18461 token_begins_expression_p(parser->
current.type) ||
18462 match2(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)
18464 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].
left;
18466 if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
18468 parse_arguments(parser, &arguments,
false, PM_TOKEN_EOF, (uint16_t) (depth + 1));
18471 if (!accepts_command_call && arguments.
arguments != NULL) {
18477 switch (keyword.
type) {
18478 case PM_TOKEN_KEYWORD_BREAK: {
18483 case PM_TOKEN_KEYWORD_NEXT: {
18488 case PM_TOKEN_KEYWORD_RETURN: {
18490 parse_return(parser, node);
18494 assert(
false &&
"unreachable");
18498 case PM_TOKEN_KEYWORD_SUPER: {
18499 parser_lex(parser);
18503 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18508 ((arguments.
block == NULL) || PM_NODE_TYPE_P(arguments.
block, PM_BLOCK_NODE))
18510 return UP(pm_forwarding_super_node_create(parser, &keyword, &arguments));
18513 return UP(pm_super_node_create(parser, &keyword, &arguments));
18515 case PM_TOKEN_KEYWORD_YIELD: {
18516 parser_lex(parser);
18520 parse_arguments_list(parser, &arguments,
false, accepts_command_call, (uint16_t) (depth + 1));
18526 if (arguments.
block != NULL) {
18527 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
18528 pm_node_unreference(parser, arguments.
block);
18529 pm_node_destroy(parser, arguments.
block);
18530 arguments.
block = NULL;
18538 case PM_TOKEN_KEYWORD_CLASS: {
18539 size_t opening_newline_index = token_newline_index(parser);
18540 parser_lex(parser);
18543 pm_do_loop_stack_push(parser,
false);
18546 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18548 if (accept1(parser, PM_TOKEN_LESS_LESS)) {
18550 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));
18552 pm_parser_scope_push(parser,
true);
18553 if (!match2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18558 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18559 pm_accepts_block_stack_push(parser,
true);
18560 statements = UP(parse_statements(parser,
PM_CONTEXT_SCLASS, (uint16_t) (depth + 1)));
18561 pm_accepts_block_stack_pop(parser);
18564 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
18565 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18566 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)));
18568 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
18571 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
18576 pm_parser_scope_pop(parser);
18577 pm_do_loop_stack_pop(parser);
18579 flush_block_exits(parser, previous_block_exits);
18580 pm_node_list_free(¤t_block_exits);
18582 return UP(pm_singleton_class_node_create(parser, &locals, &class_keyword, &
operator, expression, statements, &parser->
previous));
18585 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_CLASS_NAME, (uint16_t) (depth + 1));
18587 if (name.
type != PM_TOKEN_CONSTANT) {
18588 pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME);
18594 if (match1(parser, PM_TOKEN_LESS)) {
18595 inheritance_operator = parser->
current;
18596 lex_state_set(parser, PM_LEX_STATE_BEG);
18599 parser_lex(parser);
18601 superclass = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CLASS_SUPERCLASS, (uint16_t) (depth + 1));
18603 inheritance_operator = not_provided(parser);
18607 pm_parser_scope_push(parser,
true);
18609 if (inheritance_operator.
type != PM_TOKEN_NOT_PROVIDED) {
18610 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CLASS_UNEXPECTED_END);
18612 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18616 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18617 pm_accepts_block_stack_push(parser,
true);
18618 statements = UP(parse_statements(parser,
PM_CONTEXT_CLASS, (uint16_t) (depth + 1)));
18619 pm_accepts_block_stack_pop(parser);
18622 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
18623 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18624 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)));
18626 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
18629 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
18631 if (context_def_p(parser)) {
18632 pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
18638 pm_parser_scope_pop(parser);
18639 pm_do_loop_stack_pop(parser);
18641 if (!PM_NODE_TYPE_P(constant_path, PM_CONSTANT_PATH_NODE) && !(PM_NODE_TYPE_P(constant_path, PM_CONSTANT_READ_NODE))) {
18642 pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
18645 pop_block_exits(parser, previous_block_exits);
18646 pm_node_list_free(¤t_block_exits);
18648 return UP(pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, &inheritance_operator, superclass, statements, &parser->
previous));
18650 case PM_TOKEN_KEYWORD_DEF: {
18652 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18655 size_t opening_newline_index = token_newline_index(parser);
18665 parser_lex(parser);
18669 bool valid_name =
true;
18671 switch (parser->
current.type) {
18672 case PM_CASE_OPERATOR:
18673 pm_parser_scope_push(parser,
true);
18674 lex_state_set(parser, PM_LEX_STATE_ENDFN);
18675 parser_lex(parser);
18679 case PM_TOKEN_IDENTIFIER: {
18680 parser_lex(parser);
18682 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
18683 receiver = parse_variable_call(parser);
18685 pm_parser_scope_push(parser,
true);
18686 lex_state_set(parser, PM_LEX_STATE_FNAME);
18687 parser_lex(parser);
18690 name = parse_method_definition_name(parser);
18693 pm_parser_scope_push(parser,
true);
18700 case PM_TOKEN_INSTANCE_VARIABLE:
18701 case PM_TOKEN_CLASS_VARIABLE:
18702 case PM_TOKEN_GLOBAL_VARIABLE:
18703 valid_name =
false;
18705 case PM_TOKEN_CONSTANT:
18706 case PM_TOKEN_KEYWORD_NIL:
18707 case PM_TOKEN_KEYWORD_SELF:
18708 case PM_TOKEN_KEYWORD_TRUE:
18709 case PM_TOKEN_KEYWORD_FALSE:
18710 case PM_TOKEN_KEYWORD___FILE__:
18711 case PM_TOKEN_KEYWORD___LINE__:
18712 case PM_TOKEN_KEYWORD___ENCODING__: {
18713 pm_parser_scope_push(parser,
true);
18714 parser_lex(parser);
18718 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
18719 lex_state_set(parser, PM_LEX_STATE_FNAME);
18720 parser_lex(parser);
18723 switch (identifier.
type) {
18724 case PM_TOKEN_CONSTANT:
18725 receiver = UP(pm_constant_read_node_create(parser, &identifier));
18727 case PM_TOKEN_INSTANCE_VARIABLE:
18728 receiver = UP(pm_instance_variable_read_node_create(parser, &identifier));
18730 case PM_TOKEN_CLASS_VARIABLE:
18731 receiver = UP(pm_class_variable_read_node_create(parser, &identifier));
18733 case PM_TOKEN_GLOBAL_VARIABLE:
18734 receiver = UP(pm_global_variable_read_node_create(parser, &identifier));
18736 case PM_TOKEN_KEYWORD_NIL:
18737 receiver = UP(pm_nil_node_create(parser, &identifier));
18739 case PM_TOKEN_KEYWORD_SELF:
18740 receiver = UP(pm_self_node_create(parser, &identifier));
18742 case PM_TOKEN_KEYWORD_TRUE:
18743 receiver = UP(pm_true_node_create(parser, &identifier));
18745 case PM_TOKEN_KEYWORD_FALSE:
18746 receiver = UP(pm_false_node_create(parser, &identifier));
18748 case PM_TOKEN_KEYWORD___FILE__:
18749 receiver = UP(pm_source_file_node_create(parser, &identifier));
18751 case PM_TOKEN_KEYWORD___LINE__:
18752 receiver = UP(pm_source_line_node_create(parser, &identifier));
18754 case PM_TOKEN_KEYWORD___ENCODING__:
18755 receiver = UP(pm_source_encoding_node_create(parser, &identifier));
18761 name = parse_method_definition_name(parser);
18771 case PM_TOKEN_PARENTHESIS_LEFT: {
18776 context_pop(parser);
18777 parser_lex(parser);
18780 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEF_RECEIVER, (uint16_t) (depth + 1));
18782 accept1(parser, PM_TOKEN_NEWLINE);
18783 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
18786 lex_state_set(parser, PM_LEX_STATE_FNAME);
18787 expect2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON, PM_ERR_DEF_RECEIVER_TERM);
18790 receiver = UP(pm_parentheses_node_create(parser, &lparen, expression, &rparen, 0));
18794 pm_parser_scope_push(parser,
true);
18796 name = parse_method_definition_name(parser);
18800 pm_parser_scope_push(parser,
true);
18801 name = parse_method_definition_name(parser);
18809 bool accept_endless_def =
true;
18810 switch (parser->
current.type) {
18811 case PM_TOKEN_PARENTHESIS_LEFT: {
18812 parser_lex(parser);
18815 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18818 params = parse_parameters(parser, PM_BINDING_POWER_DEFINED,
true,
false,
true,
true,
false, (uint16_t) (depth + 1));
18821 lex_state_set(parser, PM_LEX_STATE_BEG);
18824 context_pop(parser);
18825 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18834 case PM_CASE_PARAMETER: {
18837 if (parser->
current.type == PM_TOKEN_LABEL) {
18838 lex_state_set(parser, parser->
lex_state | PM_LEX_STATE_LABEL);
18841 lparen = not_provided(parser);
18842 rparen = not_provided(parser);
18843 params = parse_parameters(parser, PM_BINDING_POWER_DEFINED,
false,
false,
true,
true,
false, (uint16_t) (depth + 1));
18847 accept_endless_def =
false;
18849 context_pop(parser);
18853 lparen = not_provided(parser);
18854 rparen = not_provided(parser);
18857 context_pop(parser);
18866 if (accept1(parser, PM_TOKEN_EQUAL)) {
18867 if (token_is_setter_name(&name)) {
18868 pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
18870 if (!accept_endless_def) {
18871 pm_parser_err_previous(parser, PM_ERR_DEF_ENDLESS_PARAMETERS);
18877 PM_PARSER_ERR_FORMAT(parser, def_keyword.
start, parser->
previous.
end, PM_ERR_UNEXPECTED_PARAMETER_DEFAULT_VALUE,
"endless method definition");
18882 pm_do_loop_stack_push(parser,
false);
18883 statements = UP(pm_statements_node_create(parser));
18885 bool allow_command_call;
18887 allow_command_call = accepts_command_call;
18890 allow_command_call = binding_power == PM_BINDING_POWER_ASSIGNMENT || binding_power < PM_BINDING_POWER_COMPOSITION;
18893 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_DEFINED + 1, allow_command_call,
false, PM_ERR_DEF_ENDLESS, (uint16_t) (depth + 1));
18895 if (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
18899 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));
18900 context_pop(parser);
18902 statement = UP(pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value));
18905 pm_statements_node_body_append(parser, (
pm_statements_node_t *) statements, statement,
false);
18906 pm_do_loop_stack_pop(parser);
18907 context_pop(parser);
18908 end_keyword = not_provided(parser);
18910 equal = not_provided(parser);
18912 if (lparen.
type == PM_TOKEN_NOT_PROVIDED) {
18913 lex_state_set(parser, PM_LEX_STATE_BEG);
18915 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_DEF_PARAMS_TERM);
18917 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18920 pm_accepts_block_stack_push(parser,
true);
18921 pm_do_loop_stack_push(parser,
false);
18923 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18924 pm_accepts_block_stack_push(parser,
true);
18925 statements = UP(parse_statements(parser,
PM_CONTEXT_DEF, (uint16_t) (depth + 1)));
18926 pm_accepts_block_stack_pop(parser);
18929 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
18930 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18931 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)));
18933 parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword,
false,
false);
18936 pm_accepts_block_stack_pop(parser);
18937 pm_do_loop_stack_pop(parser);
18939 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_DEF_TERM);
18945 pm_parser_scope_pop(parser);
18952 pm_constant_id_t name_id = pm_parser_constant_id_location(parser, name.
start, parse_operator_symbol_name(&name));
18954 flush_block_exits(parser, previous_block_exits);
18955 pm_node_list_free(¤t_block_exits);
18957 return UP(pm_def_node_create(
18973 case PM_TOKEN_KEYWORD_DEFINED: {
18974 parser_lex(parser);
18982 bool newline = accept1(parser, PM_TOKEN_NEWLINE);
18984 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
18987 if (newline && accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18988 expression = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->
previous, 0));
18989 lparen = not_provided(parser);
18990 rparen = not_provided(parser);
18992 expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
18995 rparen = not_provided(parser);
18997 accept1(parser, PM_TOKEN_NEWLINE);
18998 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19003 lparen = not_provided(parser);
19004 rparen = not_provided(parser);
19005 expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19008 context_pop(parser);
19009 return UP(pm_defined_node_create(
19017 case PM_TOKEN_KEYWORD_END_UPCASE: {
19018 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19019 pm_parser_err_current(parser, PM_ERR_STATEMENT_POSTEXE_END);
19022 parser_lex(parser);
19025 if (context_def_p(parser)) {
19026 pm_parser_warn_token(parser, &keyword, PM_WARN_END_IN_METHOD);
19029 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_END_UPCASE_BRACE);
19033 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM);
19034 return UP(pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous));
19036 case PM_TOKEN_KEYWORD_FALSE:
19037 parser_lex(parser);
19038 return UP(pm_false_node_create(parser, &parser->
previous));
19039 case PM_TOKEN_KEYWORD_FOR: {
19040 size_t opening_newline_index = token_newline_index(parser);
19041 parser_lex(parser);
19049 if (accept1(parser, PM_TOKEN_USTAR)) {
19053 if (token_begins_expression_p(parser->
current.type)) {
19054 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19057 index = UP(pm_splat_node_create(parser, &star_operator, name));
19058 }
else if (token_begins_expression_p(parser->
current.type)) {
19059 index = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
19061 pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX);
19062 index = UP(pm_missing_node_create(parser, for_keyword.
start, for_keyword.
end));
19066 if (match1(parser, PM_TOKEN_COMMA)) {
19067 index = parse_targets(parser, index, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19069 index = parse_target(parser, index,
false,
false);
19072 context_pop(parser);
19073 pm_do_loop_stack_push(parser,
true);
19075 expect1(parser, PM_TOKEN_KEYWORD_IN, PM_ERR_FOR_IN);
19078 pm_node_t *collection = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_FOR_COLLECTION, (uint16_t) (depth + 1));
19079 pm_do_loop_stack_pop(parser);
19082 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19085 do_keyword = not_provided(parser);
19086 if (!match2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE)) {
19092 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19093 statements = parse_statements(parser,
PM_CONTEXT_FOR, (uint16_t) (depth + 1));
19096 parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword,
false,
false);
19097 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM);
19099 return UP(pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, &do_keyword, &parser->
previous));
19101 case PM_TOKEN_KEYWORD_IF:
19102 if (parser_end_of_line_p(parser)) {
19103 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
19106 size_t opening_newline_index = token_newline_index(parser);
19107 bool if_after_else = parser->
previous.
type == PM_TOKEN_KEYWORD_ELSE;
19108 parser_lex(parser);
19110 return parse_conditional(parser,
PM_CONTEXT_IF, opening_newline_index, if_after_else, (uint16_t) (depth + 1));
19111 case PM_TOKEN_KEYWORD_UNDEF: {
19112 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19113 pm_parser_err_current(parser, PM_ERR_STATEMENT_UNDEF);
19116 parser_lex(parser);
19118 pm_node_t *name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19120 if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) {
19121 pm_node_destroy(parser, name);
19123 pm_undef_node_append(undef, name);
19125 while (match1(parser, PM_TOKEN_COMMA)) {
19126 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
19127 parser_lex(parser);
19128 name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19130 if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) {
19131 pm_node_destroy(parser, name);
19135 pm_undef_node_append(undef, name);
19141 case PM_TOKEN_KEYWORD_NOT: {
19142 parser_lex(parser);
19151 if (!accepts_command_call && !match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19152 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES)) {
19153 pm_parser_err(parser, parser->
previous.
end, parser->
previous.
end + 1, PM_ERR_EXPECT_LPAREN_AFTER_NOT_LPAREN);
19155 accept1(parser, PM_TOKEN_NEWLINE);
19156 pm_parser_err_current(parser, PM_ERR_EXPECT_LPAREN_AFTER_NOT_OTHER);
19159 return UP(pm_missing_node_create(parser, parser->
current.start, parser->
current.end));
19162 accept1(parser, PM_TOKEN_NEWLINE);
19164 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19167 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19168 receiver = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->
previous, 0));
19170 arguments.
opening_loc = PM_LOCATION_TOKEN_VALUE(&lparen);
19171 receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19174 accept1(parser, PM_TOKEN_NEWLINE);
19175 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19180 receiver = parse_expression(parser, PM_BINDING_POWER_NOT,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19183 return UP(pm_call_node_not_create(parser, receiver, &message, &arguments));
19185 case PM_TOKEN_KEYWORD_UNLESS: {
19186 size_t opening_newline_index = token_newline_index(parser);
19187 parser_lex(parser);
19189 return parse_conditional(parser,
PM_CONTEXT_UNLESS, opening_newline_index,
false, (uint16_t) (depth + 1));
19191 case PM_TOKEN_KEYWORD_MODULE: {
19193 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19195 size_t opening_newline_index = token_newline_index(parser);
19196 parser_lex(parser);
19199 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_MODULE_NAME, (uint16_t) (depth + 1));
19204 if (PM_NODE_TYPE_P(constant_path, PM_MISSING_NODE)) {
19205 pop_block_exits(parser, previous_block_exits);
19206 pm_node_list_free(¤t_block_exits);
19209 return UP(pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing));
19212 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
19215 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
19216 constant_path = UP(pm_constant_path_node_create(parser, constant_path, &double_colon, &parser->
previous));
19223 if (name.
type != PM_TOKEN_CONSTANT) {
19224 pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
19227 pm_parser_scope_push(parser,
true);
19228 accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE);
19231 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19232 pm_accepts_block_stack_push(parser,
true);
19233 statements = UP(parse_statements(parser,
PM_CONTEXT_MODULE, (uint16_t) (depth + 1)));
19234 pm_accepts_block_stack_pop(parser);
19237 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
19238 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
19239 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)));
19241 parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword,
false,
false);
19247 pm_parser_scope_pop(parser);
19248 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM);
19250 if (context_def_p(parser)) {
19251 pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
19254 pop_block_exits(parser, previous_block_exits);
19255 pm_node_list_free(¤t_block_exits);
19257 return UP(pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->
previous));
19259 case PM_TOKEN_KEYWORD_NIL:
19260 parser_lex(parser);
19261 return UP(pm_nil_node_create(parser, &parser->
previous));
19262 case PM_TOKEN_KEYWORD_REDO: {
19263 parser_lex(parser);
19270 case PM_TOKEN_KEYWORD_RETRY: {
19271 parser_lex(parser);
19274 parse_retry(parser, node);
19278 case PM_TOKEN_KEYWORD_SELF:
19279 parser_lex(parser);
19280 return UP(pm_self_node_create(parser, &parser->
previous));
19281 case PM_TOKEN_KEYWORD_TRUE:
19282 parser_lex(parser);
19283 return UP(pm_true_node_create(parser, &parser->
previous));
19284 case PM_TOKEN_KEYWORD_UNTIL: {
19285 size_t opening_newline_index = token_newline_index(parser);
19288 pm_do_loop_stack_push(parser,
true);
19290 parser_lex(parser);
19292 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
19294 pm_do_loop_stack_pop(parser);
19295 context_pop(parser);
19298 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19301 do_keyword = not_provided(parser);
19302 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
19306 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19307 pm_accepts_block_stack_push(parser,
true);
19308 statements = parse_statements(parser,
PM_CONTEXT_UNTIL, (uint16_t) (depth + 1));
19309 pm_accepts_block_stack_pop(parser);
19310 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19313 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19314 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM);
19316 return UP(pm_until_node_create(parser, &keyword, &do_keyword, &parser->
previous, predicate, statements, 0));
19318 case PM_TOKEN_KEYWORD_WHILE: {
19319 size_t opening_newline_index = token_newline_index(parser);
19322 pm_do_loop_stack_push(parser,
true);
19324 parser_lex(parser);
19326 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
19328 pm_do_loop_stack_pop(parser);
19329 context_pop(parser);
19332 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19335 do_keyword = not_provided(parser);
19336 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
19340 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19341 pm_accepts_block_stack_push(parser,
true);
19342 statements = parse_statements(parser,
PM_CONTEXT_WHILE, (uint16_t) (depth + 1));
19343 pm_accepts_block_stack_pop(parser);
19344 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19347 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19348 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM);
19350 return UP(pm_while_node_create(parser, &keyword, &do_keyword, &parser->
previous, predicate, statements, 0));
19352 case PM_TOKEN_PERCENT_LOWER_I: {
19353 parser_lex(parser);
19358 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19359 accept1(parser, PM_TOKEN_WORDS_SEP);
19360 if (match1(parser, PM_TOKEN_STRING_END))
break;
19364 while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19369 if (current == NULL) {
19370 current = UP(pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing));
19371 parser_lex(parser);
19372 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
19373 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, &opening, &parser->
current, &closing));
19374 parser_lex(parser);
19376 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19381 pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &cast->
unescaped));
19382 pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, &opening, &parser->
previous, &closing));
19383 parser_lex(parser);
19386 pm_interpolated_symbol_node_append(interpolated, first_string);
19387 pm_interpolated_symbol_node_append(interpolated, second_string);
19390 current = UP(interpolated);
19392 assert(
false &&
"unreachable");
19397 pm_array_node_elements_append(array, current);
19400 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_LOWER_ELEMENT);
19405 if (match1(parser, PM_TOKEN_EOF)) {
19406 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
19409 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_LOWER_TERM);
19411 pm_array_node_close_set(array, &closing);
19415 case PM_TOKEN_PERCENT_UPPER_I: {
19416 parser_lex(parser);
19424 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19425 switch (parser->
current.type) {
19426 case PM_TOKEN_WORDS_SEP: {
19427 if (current == NULL) {
19433 pm_array_node_elements_append(array, current);
19437 parser_lex(parser);
19440 case PM_TOKEN_STRING_CONTENT: {
19444 if (current == NULL) {
19448 current = UP(pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing));
19449 parser_lex(parser);
19450 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
19454 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, &opening, &parser->
current, &closing));
19455 parser_lex(parser);
19458 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19466 pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &cast->
unescaped));
19467 pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, &opening, &parser->
previous, &closing));
19468 parser_lex(parser);
19471 pm_interpolated_symbol_node_append(interpolated, first_string);
19472 pm_interpolated_symbol_node_append(interpolated, second_string);
19475 current = UP(interpolated);
19477 assert(
false &&
"unreachable");
19482 case PM_TOKEN_EMBVAR: {
19483 bool start_location_set =
false;
19484 if (current == NULL) {
19490 current = UP(pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing));
19491 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19499 current = UP(pm_symbol_node_to_string_node(parser, (
pm_symbol_node_t *) current));
19500 pm_interpolated_symbol_node_append(interpolated, current);
19502 start_location_set =
true;
19503 current = UP(interpolated);
19509 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19511 if (!start_location_set) {
19516 case PM_TOKEN_EMBEXPR_BEGIN: {
19517 bool start_location_set =
false;
19518 if (current == NULL) {
19524 current = UP(pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing));
19525 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19534 current = UP(pm_symbol_node_to_string_node(parser, (
pm_symbol_node_t *) current));
19535 pm_interpolated_symbol_node_append(interpolated, current);
19537 start_location_set =
true;
19538 current = UP(interpolated);
19539 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
19543 assert(
false &&
"unreachable");
19546 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19548 if (!start_location_set) {
19554 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_UPPER_ELEMENT);
19555 parser_lex(parser);
19562 pm_array_node_elements_append(array, current);
19566 if (match1(parser, PM_TOKEN_EOF)) {
19567 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_UPPER_TERM);
19570 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_UPPER_TERM);
19572 pm_array_node_close_set(array, &closing);
19576 case PM_TOKEN_PERCENT_LOWER_W: {
19577 parser_lex(parser);
19582 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19583 accept1(parser, PM_TOKEN_WORDS_SEP);
19584 if (match1(parser, PM_TOKEN_STRING_END))
break;
19588 while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19592 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, &opening, &parser->
current, &closing));
19595 if (current == NULL) {
19597 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
19599 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19601 pm_interpolated_string_node_append(interpolated, current);
19602 pm_interpolated_string_node_append(interpolated,
string);
19603 current = UP(interpolated);
19605 assert(
false &&
"unreachable");
19607 parser_lex(parser);
19611 pm_array_node_elements_append(array, current);
19614 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_LOWER_ELEMENT);
19619 if (match1(parser, PM_TOKEN_EOF)) {
19620 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_LOWER_TERM);
19623 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_LOWER_TERM);
19626 pm_array_node_close_set(array, &closing);
19629 case PM_TOKEN_PERCENT_UPPER_W: {
19630 parser_lex(parser);
19638 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19639 switch (parser->
current.type) {
19640 case PM_TOKEN_WORDS_SEP: {
19645 if (current == NULL) {
19652 pm_array_node_elements_append(array, current);
19656 parser_lex(parser);
19659 case PM_TOKEN_STRING_CONTENT: {
19663 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, &opening, &parser->
current, &closing));
19664 pm_node_flag_set(
string, parse_unescaped_encoding(parser));
19665 parser_lex(parser);
19667 if (current == NULL) {
19673 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
19678 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19684 pm_interpolated_string_node_append(interpolated, current);
19685 pm_interpolated_string_node_append(interpolated,
string);
19686 current = UP(interpolated);
19688 assert(
false &&
"unreachable");
19693 case PM_TOKEN_EMBVAR: {
19694 if (current == NULL) {
19701 current = UP(pm_interpolated_string_node_create(parser, &opening, NULL, &closing));
19702 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19710 pm_interpolated_string_node_append(interpolated, current);
19711 current = UP(interpolated);
19718 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19722 case PM_TOKEN_EMBEXPR_BEGIN: {
19723 if (current == NULL) {
19730 current = UP(pm_interpolated_string_node_create(parser, &opening, NULL, &closing));
19731 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19739 pm_interpolated_string_node_append(interpolated, current);
19740 current = UP(interpolated);
19741 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
19746 assert(
false &&
"unreachable");
19749 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19754 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_UPPER_ELEMENT);
19755 parser_lex(parser);
19762 pm_array_node_elements_append(array, current);
19766 if (match1(parser, PM_TOKEN_EOF)) {
19767 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_UPPER_TERM);
19770 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_UPPER_TERM);
19773 pm_array_node_close_set(array, &closing);
19776 case PM_TOKEN_REGEXP_BEGIN: {
19778 parser_lex(parser);
19780 if (match1(parser, PM_TOKEN_REGEXP_END)) {
19785 .
type = PM_TOKEN_STRING_CONTENT,
19790 parser_lex(parser);
19792 pm_node_t *node = UP(pm_regular_expression_node_create(parser, &opening, &content, &parser->
previous));
19793 pm_node_flag_set(node, PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING);
19800 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19808 parser_lex(parser);
19813 if (accept1(parser, PM_TOKEN_REGEXP_END)) {
19820 if (!match1(parser, PM_TOKEN_EQUAL_TILDE)) {
19821 parse_regular_expression_errors(parser, node);
19824 pm_node_flag_set(UP(node), parse_and_validate_regular_expression_encoding(parser, &unescaped, ascii_only, FL(node)));
19830 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
19834 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, &opening, &parser->
previous, &closing, &unescaped));
19840 pm_node_flag_set(part, PM_STRING_FLAGS_FORCED_BINARY_ENCODING);
19843 pm_interpolated_regular_expression_node_append(interpolated, part);
19848 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
19854 while (!match2(parser, PM_TOKEN_REGEXP_END, PM_TOKEN_EOF)) {
19855 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
19856 pm_interpolated_regular_expression_node_append(interpolated, part);
19861 if (match1(parser, PM_TOKEN_EOF)) {
19862 pm_parser_err_token(parser, &opening, PM_ERR_REGEXP_TERM);
19865 expect1(parser, PM_TOKEN_REGEXP_END, PM_ERR_REGEXP_TERM);
19868 pm_interpolated_regular_expression_node_closing_set(parser, interpolated, &closing);
19869 return UP(interpolated);
19871 case PM_TOKEN_BACKTICK:
19872 case PM_TOKEN_PERCENT_LOWER_X: {
19873 parser_lex(parser);
19880 if (match1(parser, PM_TOKEN_STRING_END)) {
19885 .
type = PM_TOKEN_STRING_CONTENT,
19890 parser_lex(parser);
19891 return UP(pm_xstring_node_create(parser, &opening, &content, &parser->
previous));
19896 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19903 parser_lex(parser);
19905 if (match1(parser, PM_TOKEN_STRING_END)) {
19906 pm_node_t *node = UP(pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped));
19907 pm_node_flag_set(node, parse_unescaped_encoding(parser));
19908 parser_lex(parser);
19914 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
19919 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, &opening, &parser->
previous, &closing, &unescaped));
19920 pm_node_flag_set(part, parse_unescaped_encoding(parser));
19922 pm_interpolated_xstring_node_append(node, part);
19927 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
19931 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19932 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
19933 pm_interpolated_xstring_node_append(node, part);
19938 if (match1(parser, PM_TOKEN_EOF)) {
19939 pm_parser_err_token(parser, &opening, PM_ERR_XSTRING_TERM);
19942 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_XSTRING_TERM);
19944 pm_interpolated_xstring_node_closing_set(node, &closing);
19948 case PM_TOKEN_USTAR: {
19949 parser_lex(parser);
19954 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19955 pm_parser_err_prefix(parser, diag_id);
19962 if (token_begins_expression_p(parser->
current.type)) {
19963 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19966 pm_node_t *splat = UP(pm_splat_node_create(parser, &
operator, name));
19968 if (match1(parser, PM_TOKEN_COMMA)) {
19969 return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19971 return parse_target_validate(parser, splat,
true);
19974 case PM_TOKEN_BANG: {
19975 if (binding_power > PM_BINDING_POWER_UNARY) {
19976 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
19979 parser_lex(parser);
19982 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));
19983 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"!");
19985 pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
19988 case PM_TOKEN_TILDE: {
19989 if (binding_power > PM_BINDING_POWER_UNARY) {
19990 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
19992 parser_lex(parser);
19995 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
19996 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"~");
20000 case PM_TOKEN_UMINUS: {
20001 if (binding_power > PM_BINDING_POWER_UNARY) {
20002 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20004 parser_lex(parser);
20007 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20008 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"-@");
20012 case PM_TOKEN_UMINUS_NUM: {
20013 parser_lex(parser);
20016 pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20018 if (accept1(parser, PM_TOKEN_STAR_STAR)) {
20020 pm_node_t *exponent = parse_expression(parser, pm_binding_powers[exponent_operator.
type].right,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
20021 node = UP(pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0));
20022 node = UP(pm_call_node_unary_create(parser, &
operator, node,
"-@"));
20024 switch (PM_NODE_TYPE(node)) {
20025 case PM_INTEGER_NODE:
20026 case PM_FLOAT_NODE:
20027 case PM_RATIONAL_NODE:
20028 case PM_IMAGINARY_NODE:
20029 parse_negative_numeric(node);
20032 node = UP(pm_call_node_unary_create(parser, &
operator, node,
"-@"));
20039 case PM_TOKEN_MINUS_GREATER: {
20043 size_t opening_newline_index = token_newline_index(parser);
20044 pm_accepts_block_stack_push(parser,
true);
20045 parser_lex(parser);
20048 pm_parser_scope_push(parser,
false);
20052 switch (parser->
current.type) {
20053 case PM_TOKEN_PARENTHESIS_LEFT: {
20055 parser_lex(parser);
20057 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
20058 block_parameters = pm_block_parameters_node_create(parser, NULL, &opening);
20060 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
true, (uint16_t) (depth + 1));
20063 accept1(parser, PM_TOKEN_NEWLINE);
20064 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
20066 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
20069 case PM_CASE_PARAMETER: {
20070 pm_accepts_block_stack_push(parser,
false);
20072 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
false, (uint16_t) (depth + 1));
20073 pm_accepts_block_stack_pop(parser);
20077 block_parameters = NULL;
20086 if (accept1(parser, PM_TOKEN_LAMBDA_BEGIN)) {
20089 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
20093 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20094 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE);
20096 expect1(parser, PM_TOKEN_KEYWORD_DO, PM_ERR_LAMBDA_OPEN);
20099 if (!match3(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20100 pm_accepts_block_stack_push(parser,
true);
20102 pm_accepts_block_stack_pop(parser);
20105 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20106 assert(body == NULL || PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE));
20107 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)));
20109 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20112 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END);
20116 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
20117 pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &
operator, &parser->
previous);
20119 pm_parser_scope_pop(parser);
20120 pm_accepts_block_stack_pop(parser);
20122 return UP(pm_lambda_node_create(parser, &locals, &
operator, &opening, &parser->
previous, parameters, body));
20124 case PM_TOKEN_UPLUS: {
20125 if (binding_power > PM_BINDING_POWER_UNARY) {
20126 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20128 parser_lex(parser);
20131 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20132 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"+@");
20136 case PM_TOKEN_STRING_BEGIN:
20137 return parse_strings(parser, NULL, accepts_label, (uint16_t) (depth + 1));
20138 case PM_TOKEN_SYMBOL_BEGIN: {
20140 parser_lex(parser);
20142 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_END, (uint16_t) (depth + 1));
20153 if (diag_id != PM_ERR_CANNOT_PARSE_EXPRESSION) {
20154 pm_parser_err_prefix(parser, diag_id);
20160 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT,
pm_token_type_human(parser->
current.type), context_human(recoverable));
20161 }
else if (diag_id == PM_ERR_CANNOT_PARSE_EXPRESSION) {
20167 pm_parser_err_prefix(parser, diag_id);
20185parse_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) {
20186 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));
20190 if (match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
20194 parser_lex(parser);
20196 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));
20197 context_pop(parser);
20199 return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
20211 switch (PM_NODE_TYPE(node)) {
20212 case PM_BEGIN_NODE: {
20217 case PM_LOCAL_VARIABLE_WRITE_NODE: {
20219 pm_locals_read(&pm_parser_scope_find(parser, cast->
depth)->
locals, cast->
name);
20222 case PM_PARENTHESES_NODE: {
20224 if (cast->
body != NULL) parse_assignment_value_local(parser, cast->
body);
20227 case PM_STATEMENTS_NODE: {
20232 parse_assignment_value_local(parser, statement);
20254parse_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) {
20255 bool permitted =
true;
20256 if (previous_binding_power != PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_USTAR)) permitted =
false;
20258 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));
20259 if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE);
20261 parse_assignment_value_local(parser, value);
20262 bool single_value =
true;
20264 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && (PM_NODE_TYPE_P(value, PM_SPLAT_NODE) || match1(parser, PM_TOKEN_COMMA))) {
20265 single_value =
false;
20270 pm_array_node_elements_append(array, value);
20273 while (accept1(parser, PM_TOKEN_COMMA)) {
20274 pm_node_t *element = parse_starred_expression(parser, binding_power,
false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1));
20276 pm_array_node_elements_append(array, element);
20277 if (PM_NODE_TYPE_P(element, PM_MISSING_NODE))
break;
20279 parse_assignment_value_local(parser, element);
20285 if ((single_value || (binding_power == (PM_BINDING_POWER_MULTI_ASSIGNMENT + 1))) && match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
20289 parser_lex(parser);
20291 bool accepts_command_call_inner =
false;
20295 if (PM_NODE_TYPE_P(value, PM_CALL_NODE)) {
20298 accepts_command_call_inner =
true;
20302 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));
20303 context_pop(parser);
20305 return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
20321 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_ARGUMENTS);
20322 pm_node_unreference(parser, UP(call_node->
arguments));
20323 pm_node_destroy(parser, UP(call_node->
arguments));
20327 if (call_node->
block != NULL) {
20328 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_BLOCK);
20329 pm_node_unreference(parser, UP(call_node->
block));
20330 pm_node_destroy(parser, UP(call_node->
block));
20331 call_node->
block = NULL;
20360static inline const uint8_t *
20361pm_named_capture_escape_hex(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
20364 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
20365 uint8_t value = escape_hexadecimal_digit(*cursor);
20368 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
20369 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(*cursor));
20373 pm_buffer_append_byte(unescaped, value);
20375 pm_buffer_append_string(unescaped,
"\\x", 2);
20381static inline const uint8_t *
20382pm_named_capture_escape_octal(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
20383 uint8_t value = (uint8_t) (*cursor -
'0');
20386 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
20387 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
20390 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
20391 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
20396 pm_buffer_append_byte(unescaped, value);
20400static inline const uint8_t *
20402 const uint8_t *start = cursor - 1;
20405 if (cursor >= end) {
20406 pm_buffer_append_string(unescaped,
"\\u", 2);
20410 if (*cursor !=
'{') {
20411 size_t length = pm_strspn_hexadecimal_digit(cursor, MIN(end - cursor, 4));
20412 uint32_t value = escape_unicode(parser, cursor, length, error_location);
20414 if (!pm_buffer_append_unicode_codepoint(unescaped, value)) {
20415 pm_buffer_append_string(unescaped, (
const char *) start, (
size_t) ((cursor + length) - start));
20418 return cursor + length;
20423 while (cursor < end && *cursor ==
' ') cursor++;
20425 if (cursor >= end)
break;
20426 if (*cursor ==
'}') {
20431 size_t length = pm_strspn_hexadecimal_digit(cursor, end - cursor);
20435 uint32_t value = escape_unicode(parser, cursor, length, error_location);
20437 (void) pm_buffer_append_unicode_codepoint(unescaped, value);
20445pm_named_capture_escape(
pm_parser_t *parser,
pm_buffer_t *unescaped,
const uint8_t *source,
const size_t length,
const uint8_t *cursor,
const pm_location_t *error_location) {
20446 const uint8_t *end = source + length;
20447 pm_buffer_append_string(unescaped, (
const char *) source, (
size_t) (cursor - source));
20450 if (++cursor >= end) {
20451 pm_buffer_append_byte(unescaped,
'\\');
20457 cursor = pm_named_capture_escape_hex(unescaped, cursor, end);
20459 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
20460 cursor = pm_named_capture_escape_octal(unescaped, cursor, end);
20463 cursor = pm_named_capture_escape_unicode(parser, unescaped, cursor, end, error_location);
20466 pm_buffer_append_byte(unescaped,
'\\');
20470 const uint8_t *next_cursor = pm_memchr(cursor,
'\\', (
size_t) (end - cursor), parser->
encoding_changed, parser->
encoding);
20471 if (next_cursor == NULL)
break;
20473 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (next_cursor - cursor));
20474 cursor = next_cursor;
20477 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (end - cursor));
20485parse_regular_expression_named_capture(
const pm_string_t *capture,
void *data) {
20506 pm_named_capture_escape(parser, &unescaped, source, length, cursor, callback_data->
shared ? NULL : &call->receiver->location);
20516 if (!pm_slice_is_valid_local(parser, source, source + length)) {
20521 if (callback_data->
shared) {
20525 name = pm_parser_constant_id_location(parser, location.
start, location.
end);
20531 void *memory =
xmalloc(length);
20532 if (memory == NULL) abort();
20534 memcpy(memory, source, length);
20535 name = pm_parser_constant_id_owned(parser, (uint8_t *) memory, length);
20540 if (name != 0 && !pm_constant_id_list_includes(names, name)) {
20541 pm_constant_id_list_append(names, name);
20544 if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
20547 if (pm_local_is_keyword((
const char *) source, length)) {
20554 pm_parser_local_add(parser, name, location.
start, location.
end, 0);
20559 if (callback_data->
match == NULL) {
20560 callback_data->
match = pm_match_write_node_create(parser, call);
20565 pm_node_t *target = UP(pm_local_variable_target_node_create(parser, &location, name, depth == -1 ? 0 : (uint32_t) depth));
20566 pm_node_list_append(&callback_data->
match->
targets, target);
20582 .shared = content->
type == PM_STRING_SHARED
20589 .shared = content->
type == PM_STRING_SHARED
20592 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);
20593 pm_constant_id_list_free(&callback_data.
names);
20595 if (callback_data.
match != NULL) {
20596 return UP(callback_data.
match);
20603parse_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) {
20606 switch (token.type) {
20607 case PM_TOKEN_EQUAL: {
20608 switch (PM_NODE_TYPE(node)) {
20609 case PM_CALL_NODE: {
20615 if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
20620 case PM_CASE_WRITABLE: {
20624 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
20628 parser_lex(parser);
20629 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));
20631 if (PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) && previous_binding_power != PM_BINDING_POWER_STATEMENT) {
20632 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_MULTI_WRITE);
20635 return parse_write(parser, node, &token, value);
20637 case PM_SPLAT_NODE: {
20639 pm_multi_target_node_targets_append(parser, multi_target, node);
20641 parser_lex(parser);
20642 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));
20643 return parse_write(parser, UP(multi_target), &token, value);
20645 case PM_SOURCE_ENCODING_NODE:
20646 case PM_FALSE_NODE:
20647 case PM_SOURCE_FILE_NODE:
20648 case PM_SOURCE_LINE_NODE:
20651 case PM_TRUE_NODE: {
20654 parser_lex(parser);
20655 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));
20656 return parse_unwriteable_write(parser, node, &token, value);
20662 parser_lex(parser);
20663 pm_parser_err_token(parser, &token, PM_ERR_EXPRESSION_NOT_WRITABLE);
20667 case PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL: {
20668 switch (PM_NODE_TYPE(node)) {
20669 case PM_BACK_REFERENCE_READ_NODE:
20670 case PM_NUMBERED_REFERENCE_READ_NODE:
20671 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
20673 case PM_GLOBAL_VARIABLE_READ_NODE: {
20674 parser_lex(parser);
20676 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));
20677 pm_node_t *result = UP(pm_global_variable_and_write_node_create(parser, node, &token, value));
20679 pm_node_destroy(parser, node);
20682 case PM_CLASS_VARIABLE_READ_NODE: {
20683 parser_lex(parser);
20685 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_destroy(parser, node);
20691 case PM_CONSTANT_PATH_NODE: {
20692 parser_lex(parser);
20694 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));
20697 return parse_shareable_constant_write(parser, write);
20699 case PM_CONSTANT_READ_NODE: {
20700 parser_lex(parser);
20702 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));
20705 pm_node_destroy(parser, node);
20706 return parse_shareable_constant_write(parser, write);
20708 case PM_INSTANCE_VARIABLE_READ_NODE: {
20709 parser_lex(parser);
20711 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));
20714 pm_node_destroy(parser, node);
20717 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
20719 parser_lex(parser);
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 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &token, value, name, 0));
20724 pm_node_unreference(parser, node);
20725 pm_node_destroy(parser, node);
20728 case PM_LOCAL_VARIABLE_READ_NODE: {
20731 pm_node_unreference(parser, node);
20735 parser_lex(parser);
20737 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));
20738 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
20740 pm_node_destroy(parser, node);
20743 case PM_CALL_NODE: {
20749 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
20751 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
20754 parser_lex(parser);
20756 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));
20757 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
20759 pm_node_destroy(parser, UP(cast));
20765 parser_lex(parser);
20770 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
20771 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));
20772 return UP(pm_index_and_write_node_create(parser, cast, &token, value));
20776 if (pm_call_node_writable_p(parser, cast)) {
20777 parse_write_name(parser, &cast->
name);
20779 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
20782 parse_call_operator_write(parser, cast, &token);
20783 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));
20784 return UP(pm_call_and_write_node_create(parser, cast, &token, value));
20786 case PM_MULTI_WRITE_NODE: {
20787 parser_lex(parser);
20788 pm_parser_err_token(parser, &token, PM_ERR_AMPAMPEQ_MULTI_ASSIGN);
20792 parser_lex(parser);
20797 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
20801 case PM_TOKEN_PIPE_PIPE_EQUAL: {
20802 switch (PM_NODE_TYPE(node)) {
20803 case PM_BACK_REFERENCE_READ_NODE:
20804 case PM_NUMBERED_REFERENCE_READ_NODE:
20805 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
20807 case PM_GLOBAL_VARIABLE_READ_NODE: {
20808 parser_lex(parser);
20810 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));
20811 pm_node_t *result = UP(pm_global_variable_or_write_node_create(parser, node, &token, value));
20813 pm_node_destroy(parser, node);
20816 case PM_CLASS_VARIABLE_READ_NODE: {
20817 parser_lex(parser);
20819 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_destroy(parser, node);
20825 case PM_CONSTANT_PATH_NODE: {
20826 parser_lex(parser);
20828 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));
20831 return parse_shareable_constant_write(parser, write);
20833 case PM_CONSTANT_READ_NODE: {
20834 parser_lex(parser);
20836 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));
20839 pm_node_destroy(parser, node);
20840 return parse_shareable_constant_write(parser, write);
20842 case PM_INSTANCE_VARIABLE_READ_NODE: {
20843 parser_lex(parser);
20845 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));
20848 pm_node_destroy(parser, node);
20851 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
20853 parser_lex(parser);
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 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &token, value, name, 0));
20858 pm_node_unreference(parser, node);
20859 pm_node_destroy(parser, node);
20862 case PM_LOCAL_VARIABLE_READ_NODE: {
20865 pm_node_unreference(parser, node);
20869 parser_lex(parser);
20871 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));
20872 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
20874 pm_node_destroy(parser, node);
20877 case PM_CALL_NODE: {
20883 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
20885 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
20888 parser_lex(parser);
20890 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));
20891 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
20893 pm_node_destroy(parser, UP(cast));
20899 parser_lex(parser);
20904 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
20905 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));
20906 return UP(pm_index_or_write_node_create(parser, cast, &token, value));
20910 if (pm_call_node_writable_p(parser, cast)) {
20911 parse_write_name(parser, &cast->
name);
20913 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
20916 parse_call_operator_write(parser, cast, &token);
20917 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));
20918 return UP(pm_call_or_write_node_create(parser, cast, &token, value));
20920 case PM_MULTI_WRITE_NODE: {
20921 parser_lex(parser);
20922 pm_parser_err_token(parser, &token, PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN);
20926 parser_lex(parser);
20931 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
20935 case PM_TOKEN_AMPERSAND_EQUAL:
20936 case PM_TOKEN_CARET_EQUAL:
20937 case PM_TOKEN_GREATER_GREATER_EQUAL:
20938 case PM_TOKEN_LESS_LESS_EQUAL:
20939 case PM_TOKEN_MINUS_EQUAL:
20940 case PM_TOKEN_PERCENT_EQUAL:
20941 case PM_TOKEN_PIPE_EQUAL:
20942 case PM_TOKEN_PLUS_EQUAL:
20943 case PM_TOKEN_SLASH_EQUAL:
20944 case PM_TOKEN_STAR_EQUAL:
20945 case PM_TOKEN_STAR_STAR_EQUAL: {
20946 switch (PM_NODE_TYPE(node)) {
20947 case PM_BACK_REFERENCE_READ_NODE:
20948 case PM_NUMBERED_REFERENCE_READ_NODE:
20949 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
20951 case PM_GLOBAL_VARIABLE_READ_NODE: {
20952 parser_lex(parser);
20954 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));
20955 pm_node_t *result = UP(pm_global_variable_operator_write_node_create(parser, node, &token, value));
20957 pm_node_destroy(parser, node);
20960 case PM_CLASS_VARIABLE_READ_NODE: {
20961 parser_lex(parser);
20963 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_destroy(parser, node);
20969 case PM_CONSTANT_PATH_NODE: {
20970 parser_lex(parser);
20972 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));
20975 return parse_shareable_constant_write(parser, write);
20977 case PM_CONSTANT_READ_NODE: {
20978 parser_lex(parser);
20980 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));
20983 pm_node_destroy(parser, node);
20984 return parse_shareable_constant_write(parser, write);
20986 case PM_INSTANCE_VARIABLE_READ_NODE: {
20987 parser_lex(parser);
20989 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));
20992 pm_node_destroy(parser, node);
20995 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
20997 parser_lex(parser);
20999 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));
21000 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &token, value, name, 0));
21002 pm_node_unreference(parser, node);
21003 pm_node_destroy(parser, node);
21006 case PM_LOCAL_VARIABLE_READ_NODE: {
21009 pm_node_unreference(parser, node);
21013 parser_lex(parser);
21015 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));
21016 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
21018 pm_node_destroy(parser, node);
21021 case PM_CALL_NODE: {
21022 parser_lex(parser);
21028 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21030 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21033 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));
21034 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
21036 pm_node_destroy(parser, UP(cast));
21043 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21044 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));
21045 return UP(pm_index_operator_write_node_create(parser, cast, &token, value));
21049 if (pm_call_node_writable_p(parser, cast)) {
21050 parse_write_name(parser, &cast->
name);
21052 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21055 parse_call_operator_write(parser, cast, &token);
21056 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));
21057 return UP(pm_call_operator_write_node_create(parser, cast, &token, value));
21059 case PM_MULTI_WRITE_NODE: {
21060 parser_lex(parser);
21061 pm_parser_err_token(parser, &token, PM_ERR_OPERATOR_MULTI_ASSIGN);
21065 parser_lex(parser);
21074 case PM_TOKEN_AMPERSAND_AMPERSAND:
21075 case PM_TOKEN_KEYWORD_AND: {
21076 parser_lex(parser);
21078 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));
21079 return UP(pm_and_node_create(parser, node, &token, right));
21081 case PM_TOKEN_KEYWORD_OR:
21082 case PM_TOKEN_PIPE_PIPE: {
21083 parser_lex(parser);
21085 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));
21086 return UP(pm_or_node_create(parser, node, &token, right));
21088 case PM_TOKEN_EQUAL_TILDE: {
21096 parser_lex(parser);
21097 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21100 pm_call_node_t *call = pm_call_node_binary_create(parser, node, &token, argument, 0);
21106 if (PM_NODE_TYPE_P(node, PM_INTERPOLATED_REGULAR_EXPRESSION_NODE)) {
21113 bool interpolated =
false;
21114 size_t total_length = 0;
21118 if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
21121 interpolated =
true;
21126 if (!interpolated && total_length > 0) {
21127 void *memory =
xmalloc(total_length);
21128 if (!memory) abort();
21130 uint8_t *cursor = memory;
21140 pm_string_owned_init(&owned, (uint8_t *) memory, total_length);
21142 result = parse_regular_expression_named_captures(parser, &owned, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
21145 }
else if (PM_NODE_TYPE_P(node, PM_REGULAR_EXPRESSION_NODE)) {
21149 result = parse_regular_expression_named_captures(parser, content, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
21154 case PM_TOKEN_UAMPERSAND:
21155 case PM_TOKEN_USTAR:
21156 case PM_TOKEN_USTAR_STAR:
21159 case PM_TOKEN_BANG_EQUAL:
21160 case PM_TOKEN_BANG_TILDE:
21161 case PM_TOKEN_EQUAL_EQUAL:
21162 case PM_TOKEN_EQUAL_EQUAL_EQUAL:
21163 case PM_TOKEN_LESS_EQUAL_GREATER:
21164 case PM_TOKEN_CARET:
21165 case PM_TOKEN_PIPE:
21166 case PM_TOKEN_AMPERSAND:
21167 case PM_TOKEN_GREATER_GREATER:
21168 case PM_TOKEN_LESS_LESS:
21169 case PM_TOKEN_MINUS:
21170 case PM_TOKEN_PLUS:
21171 case PM_TOKEN_PERCENT:
21172 case PM_TOKEN_SLASH:
21173 case PM_TOKEN_STAR:
21174 case PM_TOKEN_STAR_STAR: {
21175 parser_lex(parser);
21177 switch (PM_NODE_TYPE(node)) {
21178 case PM_RESCUE_MODIFIER_NODE: {
21181 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21185 case PM_AND_NODE: {
21187 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21188 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21194 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21195 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21203 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21204 return UP(pm_call_node_binary_create(parser, node, &token, argument, 0));
21206 case PM_TOKEN_GREATER:
21207 case PM_TOKEN_GREATER_EQUAL:
21208 case PM_TOKEN_LESS:
21209 case PM_TOKEN_LESS_EQUAL: {
21210 if (PM_NODE_TYPE_P(node, PM_CALL_NODE) && PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_COMPARISON)) {
21211 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_COMPARISON_AFTER_COMPARISON);
21214 parser_lex(parser);
21215 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21216 return UP(pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON));
21218 case PM_TOKEN_AMPERSAND_DOT:
21219 case PM_TOKEN_DOT: {
21220 parser_lex(parser);
21225 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
21226 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21227 return UP(pm_call_node_shorthand_create(parser, node, &
operator, &arguments));
21230 switch (PM_NODE_TYPE(node)) {
21231 case PM_RESCUE_MODIFIER_NODE: {
21234 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21238 case PM_AND_NODE: {
21240 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21241 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21247 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21248 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21258 switch (parser->
current.type) {
21259 case PM_CASE_OPERATOR:
21260 case PM_CASE_KEYWORD:
21261 case PM_TOKEN_CONSTANT:
21262 case PM_TOKEN_IDENTIFIER:
21263 case PM_TOKEN_METHOD_NAME: {
21264 parser_lex(parser);
21274 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21275 pm_call_node_t *call = pm_call_node_call_create(parser, node, &
operator, &message, &arguments);
21278 (previous_binding_power == PM_BINDING_POWER_STATEMENT) &&
21281 match1(parser, PM_TOKEN_COMMA)
21283 return parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21288 case PM_TOKEN_DOT_DOT:
21289 case PM_TOKEN_DOT_DOT_DOT: {
21290 parser_lex(parser);
21293 if (token_begins_expression_p(parser->
current.type)) {
21294 right = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21297 return UP(pm_range_node_create(parser, node, &token, right));
21299 case PM_TOKEN_KEYWORD_IF_MODIFIER: {
21301 parser_lex(parser);
21303 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
21304 return UP(pm_if_node_modifier_create(parser, node, &keyword, predicate));
21306 case PM_TOKEN_KEYWORD_UNLESS_MODIFIER: {
21308 parser_lex(parser);
21310 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
21311 return UP(pm_unless_node_modifier_create(parser, node, &keyword, predicate));
21313 case PM_TOKEN_KEYWORD_UNTIL_MODIFIER: {
21314 parser_lex(parser);
21316 pm_statements_node_body_append(parser, statements, node,
true);
21318 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
21319 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));
21321 case PM_TOKEN_KEYWORD_WHILE_MODIFIER: {
21322 parser_lex(parser);
21324 pm_statements_node_body_append(parser, statements, node,
true);
21326 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
21327 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));
21329 case PM_TOKEN_QUESTION_MARK: {
21332 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
21335 parser_lex(parser);
21337 pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_TRUE, (uint16_t) (depth + 1));
21347 pm_node_t *false_expression = UP(pm_missing_node_create(parser, colon.
start, colon.
end));
21349 context_pop(parser);
21350 pop_block_exits(parser, previous_block_exits);
21351 pm_node_list_free(¤t_block_exits);
21353 return UP(pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression));
21356 accept1(parser, PM_TOKEN_NEWLINE);
21357 expect1(parser, PM_TOKEN_COLON, PM_ERR_TERNARY_COLON);
21360 pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_FALSE, (uint16_t) (depth + 1));
21362 context_pop(parser);
21363 pop_block_exits(parser, previous_block_exits);
21364 pm_node_list_free(¤t_block_exits);
21366 return UP(pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression));
21368 case PM_TOKEN_COLON_COLON: {
21369 parser_lex(parser);
21372 switch (parser->
current.type) {
21373 case PM_TOKEN_CONSTANT: {
21374 parser_lex(parser);
21378 (parser->
current.type == PM_TOKEN_PARENTHESIS_LEFT) ||
21379 (accepts_command_call && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)))
21390 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21391 path = UP(pm_call_node_call_create(parser, node, &delimiter, &message, &arguments));
21394 path = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous));
21398 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
21399 return parse_targets_validate(parser, path, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21404 case PM_CASE_OPERATOR:
21405 case PM_CASE_KEYWORD:
21406 case PM_TOKEN_IDENTIFIER:
21407 case PM_TOKEN_METHOD_NAME: {
21408 parser_lex(parser);
21414 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21415 pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
21418 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
21419 return parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21424 case PM_TOKEN_PARENTHESIS_LEFT: {
21428 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21430 return UP(pm_call_node_shorthand_create(parser, node, &delimiter, &arguments));
21433 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
21434 return UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous));
21438 case PM_TOKEN_KEYWORD_RESCUE_MODIFIER: {
21440 parser_lex(parser);
21441 accept1(parser, PM_TOKEN_NEWLINE);
21443 pm_node_t *value = parse_expression(parser, binding_power,
true,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
21444 context_pop(parser);
21446 return UP(pm_rescue_modifier_node_create(parser, node, &token, value));
21448 case PM_TOKEN_BRACKET_LEFT: {
21449 parser_lex(parser);
21454 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
21455 pm_accepts_block_stack_push(parser,
true);
21456 parse_arguments(parser, &arguments,
false, PM_TOKEN_BRACKET_RIGHT, (uint16_t) (depth + 1));
21457 pm_accepts_block_stack_pop(parser);
21458 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_EXPECT_RBRACKET);
21465 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
21466 pm_call_node_t *aref = pm_call_node_aref_create(parser, node, &arguments);
21467 return parse_targets_validate(parser, UP(aref), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21474 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
21475 block = parse_block(parser, (uint16_t) (depth + 1));
21476 pm_arguments_validate_block(parser, &arguments, block);
21477 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
21478 block = parse_block(parser, (uint16_t) (depth + 1));
21481 if (block != NULL) {
21482 if (arguments.
block != NULL) {
21483 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_AFTER_BLOCK);
21485 arguments.
arguments = pm_arguments_node_create(parser);
21487 pm_arguments_node_arguments_append(arguments.
arguments, arguments.
block);
21490 arguments.
block = UP(block);
21493 return UP(pm_call_node_aref_create(parser, node, &arguments));
21495 case PM_TOKEN_KEYWORD_IN: {
21501 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
21502 parser_lex(parser);
21505 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));
21508 pm_constant_id_list_free(&captures);
21510 return UP(pm_match_predicate_node_create(parser, node, pattern, &
operator));
21512 case PM_TOKEN_EQUAL_GREATER: {
21518 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
21519 parser_lex(parser);
21522 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));
21525 pm_constant_id_list_free(&captures);
21527 return UP(pm_match_required_node_create(parser, node, pattern, &
operator));
21530 assert(
false &&
"unreachable");
21535#undef PM_PARSE_PATTERN_SINGLE
21536#undef PM_PARSE_PATTERN_TOP
21537#undef PM_PARSE_PATTERN_MULTI
21547 (node->
block == NULL || PM_NODE_TYPE_P(node->
block, PM_BLOCK_ARGUMENT_NODE)) &&
21561parse_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) {
21563 pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
21564 return UP(pm_missing_node_create(parser, parser->
current.start, parser->
current.end));
21567 pm_node_t *node = parse_expression_prefix(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
21569 switch (PM_NODE_TYPE(node)) {
21570 case PM_MISSING_NODE:
21574 case PM_PRE_EXECUTION_NODE:
21575 case PM_POST_EXECUTION_NODE:
21576 case PM_ALIAS_GLOBAL_VARIABLE_NODE:
21577 case PM_ALIAS_METHOD_NODE:
21578 case PM_MULTI_WRITE_NODE:
21579 case PM_UNDEF_NODE:
21582 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21592 if ((pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_COMPOSITION) && pm_call_node_command_p((
pm_call_node_t *) node)) {
21596 case PM_SYMBOL_NODE:
21600 if (pm_symbol_node_label_p(node)) {
21611 pm_token_type_t current_token_type;
21614 current_token_type = parser->
current.type,
21615 current_binding_powers = pm_binding_powers[current_token_type],
21616 binding_power <= current_binding_powers.
left &&
21617 current_binding_powers.
binary
21619 node = parse_expression_infix(parser, node, binding_power, current_binding_powers.
right, accepts_command_call, (uint16_t) (depth + 1));
21627 switch (PM_NODE_TYPE(node)) {
21628 case PM_MULTI_WRITE_NODE:
21631 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21635 case PM_CLASS_VARIABLE_WRITE_NODE:
21636 case PM_CONSTANT_PATH_WRITE_NODE:
21637 case PM_CONSTANT_WRITE_NODE:
21638 case PM_GLOBAL_VARIABLE_WRITE_NODE:
21639 case PM_INSTANCE_VARIABLE_WRITE_NODE:
21640 case PM_LOCAL_VARIABLE_WRITE_NODE:
21643 if (PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21651 if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21661 if (current_binding_powers.
nonassoc) {
21664 if (match1(parser, current_token_type)) {
21676 if (PM_NODE_TYPE_P(node, PM_RANGE_NODE) && ((
pm_range_node_t *) node)->right == NULL) {
21677 if (match4(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_DOT, PM_TOKEN_AMPERSAND_DOT)) {
21682 if (PM_BINDING_POWER_TERM <= pm_binding_powers[parser->
current.type].left) {
21685 }
else if (current_binding_powers.
left <= pm_binding_powers[parser->
current.type].left) {
21690 if (accepts_command_call) {
21699 switch (node->
type) {
21700 case PM_CALL_NODE: {
21714 cast->
block == NULL &&
21724 cast->
block != NULL && PM_NODE_TYPE_P(cast->
block, PM_BLOCK_NODE)
21727 accepts_command_call =
false;
21732 case PM_CONSTANT_PATH_NODE:
21735 accepts_command_call =
false;
21750 if (PM_PARSER_COMMAND_LINE_OPTION_P(parser)) {
21751 if (statements == NULL) {
21752 statements = pm_statements_node_create(parser);
21756 pm_arguments_node_arguments_append(
21758 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2)))
21761 pm_statements_node_body_append(parser, statements, UP(pm_call_node_fcall_synthesized_create(
21764 pm_parser_constant_id_constant(parser,
"print", 5)
21768 if (PM_PARSER_COMMAND_LINE_OPTION_N(parser)) {
21769 if (PM_PARSER_COMMAND_LINE_OPTION_A(parser)) {
21770 if (statements == NULL) {
21771 statements = pm_statements_node_create(parser);
21775 pm_arguments_node_arguments_append(
21777 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$;", 2)))
21780 pm_global_variable_read_node_t *receiver = pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2));
21781 pm_call_node_t *call = pm_call_node_call_synthesized_create(parser, UP(receiver),
"split", arguments);
21785 pm_parser_constant_id_constant(parser,
"$F", 2),
21789 pm_statements_node_body_prepend(statements, UP(write));
21793 pm_arguments_node_arguments_append(
21795 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$/", 2)))
21798 if (PM_PARSER_COMMAND_LINE_OPTION_L(parser)) {
21800 pm_keyword_hash_node_elements_append(keywords, UP(pm_assoc_node_create(
21802 UP(pm_symbol_node_synthesized_create(parser,
"chomp")),
21803 &(
pm_token_t) { .type = PM_TOKEN_NOT_PROVIDED, .start = parser->
start, .end = parser->
start },
21804 UP(pm_true_node_synthesized_create(parser))
21807 pm_arguments_node_arguments_append(arguments, UP(keywords));
21808 pm_node_flag_set(UP(arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS);
21812 pm_statements_node_body_append(parser, wrapped_statements, UP(pm_while_node_synthesized_create(
21814 UP(pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser,
"gets", 4))),
21818 statements = wrapped_statements;
21833 pm_parser_scope_push(parser,
true);
21837 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
21839 parser_lex(parser);
21846 assert(statements->
body.
size > 0);
21847 pm_void_statement_check(parser, statements->
body.
nodes[statements->
body.
size - 1]);
21852 pm_parser_scope_pop(parser);
21857 statements = wrap_statements(parser, statements);
21859 flush_block_exits(parser, previous_block_exits);
21862 pm_node_list_free(¤t_block_exits);
21867 if (statements == NULL) {
21868 statements = pm_statements_node_create(parser);
21869 pm_statements_node_location_set(statements, parser->
start, parser->
start);
21872 return UP(pm_program_node_create(parser, &locals, statements));
21889pm_strnstr(
const char *big,
const char *little,
size_t big_length) {
21890 size_t little_length = strlen(little);
21892 for (
const char *max = big + big_length - little_length; big <= max; big++) {
21893 if (*big == *little && memcmp(big, little, little_length) == 0)
return big;
21900#define pm_parser_warn_shebang_carriage_return(parser, start, length) ((void) 0)
21908pm_parser_warn_shebang_carriage_return(
pm_parser_t *parser,
const uint8_t *start,
size_t length) {
21909 if (length > 2 && start[length - 2] ==
'\r' && start[length - 1] ==
'\n') {
21910 pm_parser_warn(parser, start, start + length, PM_WARN_SHEBANG_CARRIAGE_RETURN);
21921 const char *switches = pm_strnstr(engine,
" -", length);
21922 if (switches == NULL)
return;
21927 (
const uint8_t *) (switches + 1),
21928 length - ((
size_t) (switches - engine)) - 1,
21932 size_t encoding_length;
21935 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
21947 assert(source != NULL);
21951 .lex_state = PM_LEX_STATE_BEG,
21952 .enclosure_nesting = 0,
21953 .lambda_enclosure_nesting = -1,
21954 .brace_nesting = 0,
21955 .do_loop_stack = 0,
21956 .accepts_block_stack = 0,
21959 .stack = {{ .mode = PM_LEX_DEFAULT }},
21963 .end = source + size,
21964 .previous = { .type = PM_TOKEN_EOF, .start = source, .end = source },
21965 .current = { .type = PM_TOKEN_EOF, .start = source, .end = source },
21966 .next_start = NULL,
21967 .heredoc_end = NULL,
21968 .data_loc = { .start = NULL, .end = NULL },
21969 .comment_list = { 0 },
21970 .magic_comment_list = { 0 },
21971 .warning_list = { 0 },
21972 .error_list = { 0 },
21973 .current_scope = NULL,
21974 .current_context = NULL,
21976 .encoding_changed_callback = NULL,
21977 .encoding_comment_start = source,
21978 .lex_callback = NULL,
21980 .constant_pool = { 0 },
21981 .newline_list = { 0 },
21985 .explicit_encoding = NULL,
21987 .parsing_eval =
false,
21988 .partial_script =
false,
21989 .command_start =
true,
21990 .recovering =
false,
21991 .encoding_locked =
false,
21992 .encoding_changed =
false,
21993 .pattern_matching_newlines =
false,
21994 .in_keyword_arg =
false,
21995 .current_block_exits = NULL,
21996 .semantic_token_seen =
false,
21998 .current_regular_expression_ascii_only =
false,
21999 .warn_mismatched_indentation =
true
22016 uint32_t constant_size = ((uint32_t) size) / 95;
22017 pm_constant_pool_init(&parser->
constant_pool, constant_size < 4 ? 4 : constant_size);
22022 size_t newline_size = size / 22;
22023 pm_newline_list_init(&parser->
newline_list, source, newline_size < 4 ? 4 : newline_size);
22026 if (options != NULL) {
22035 if (encoding_length > 0) {
22037 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22059 for (
size_t scope_index = 0; scope_index < options->
scopes_count; scope_index++) {
22061 pm_parser_scope_push(parser, scope_index == 0);
22067 for (
size_t local_index = 0; local_index < scope->
locals_count; local_index++) {
22073 void *allocated =
xmalloc(length);
22074 if (allocated == NULL)
continue;
22076 memcpy(allocated, source, length);
22077 pm_parser_local_add_owned(parser, (uint8_t *) allocated, length);
22088 pm_accepts_block_stack_push(parser,
true);
22091 if (size >= 3 && source[0] == 0xef && source[1] == 0xbb && source[2] == 0xbf) {
22104 bool search_shebang = PM_PARSER_COMMAND_LINE_OPTION_X(parser);
22121 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
22122 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - parser->
current.end);
22124 if (length > 2 && parser->
current.end[0] ==
'#' && parser->
current.end[1] ==
'!') {
22125 const char *engine;
22127 if ((engine = pm_strnstr((
const char *) parser->
start,
"ruby", length)) != NULL) {
22128 if (newline != NULL) {
22132 pm_parser_warn_shebang_carriage_return(parser, parser->
start, length + 1);
22137 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) parser->
start)));
22140 search_shebang =
false;
22142 search_shebang =
true;
22148 if (search_shebang) {
22151 bool found_shebang =
false;
22155 const uint8_t *cursor = parser->
start;
22159 const uint8_t *newline = next_newline(cursor, parser->
end - cursor);
22161 while (newline != NULL) {
22162 pm_newline_list_append(&parser->
newline_list, newline);
22164 cursor = newline + 1;
22165 newline = next_newline(cursor, parser->
end - cursor);
22167 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - cursor);
22168 if (length > 2 && cursor[0] ==
'#' && cursor[1] ==
'!') {
22169 const char *engine;
22170 if ((engine = pm_strnstr((
const char *) cursor,
"ruby", length)) != NULL) {
22171 found_shebang =
true;
22173 if (newline != NULL) {
22174 pm_parser_warn_shebang_carriage_return(parser, cursor, length + 1);
22179 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) cursor)));
22187 if (found_shebang) {
22189 parser->
current = (
pm_token_t) { .type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
22191 pm_parser_err(parser, parser->
start, parser->
start, PM_ERR_SCRIPT_NOT_FOUND);
22218 for (node = list->
head; node != NULL; node = next) {
22230pm_magic_comment_list_free(
pm_list_t *list) {
22233 for (node = list->
head; node != NULL; node = next) {
22247 pm_diagnostic_list_free(&parser->
error_list);
22259 pm_parser_scope_pop(parser);
22263 lex_mode_pop(parser);
22272 return parse_program(parser);
22282#define LINE_SIZE 4096
22283 char line[LINE_SIZE];
22285 while (memset(line,
'\n', LINE_SIZE), stream_fgets(line, LINE_SIZE, stream) != NULL) {
22286 size_t length = LINE_SIZE;
22287 while (length > 0 && line[length - 1] ==
'\n') length--;
22289 if (length == LINE_SIZE) {
22294 pm_buffer_append_string(buffer, line, length);
22300 pm_buffer_append_string(buffer, line, length);
22308 if (strncmp(line,
"__END__", 7) == 0)
return false;
22311 if (strncmp(line,
"__END__\n", 8) == 0)
return false;
22314 if (strncmp(line,
"__END__\r\n", 9) == 0)
return false;
22320 if (stream_feof(stream)) {
22339pm_parse_stream_unterminated_heredoc_p(
pm_parser_t *parser) {
22342 for (; diagnostic != NULL; diagnostic = (
pm_diagnostic_t *) diagnostic->node.next) {
22343 if (diagnostic->diag_id == PM_ERR_HEREDOC_TERM) {
22361 bool eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof);
22367 pm_node_destroy(parser, node);
22368 eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof);
22382pm_parse_success_p(
const uint8_t *source,
size_t size,
const char *data) {
22384 pm_options_read(&options, data);
22390 pm_node_destroy(&parser, node);
22399#undef PM_CASE_KEYWORD
22400#undef PM_CASE_OPERATOR
22401#undef PM_CASE_WRITABLE
22402#undef PM_STRING_EMPTY
22407#ifndef PRISM_EXCLUDE_SERIALIZATION
22411 pm_buffer_append_string(buffer,
"PRISM", 5);
22415 pm_buffer_append_byte(buffer, PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS ? 1 : 0);
22423 pm_serialize_header(buffer);
22425 pm_buffer_append_byte(buffer,
'\0');
22433pm_serialize_parse(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
22435 pm_options_read(&options, data);
22442 pm_serialize_header(buffer);
22444 pm_buffer_append_byte(buffer,
'\0');
22446 pm_node_destroy(&parser, node);
22459 pm_options_read(&options, data);
22463 pm_serialize_header(buffer);
22465 pm_buffer_append_byte(buffer,
'\0');
22467 pm_node_destroy(&parser, node);
22477pm_serialize_parse_comments(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
22479 pm_options_read(&options, data);
22485 pm_serialize_header(buffer);
22487 pm_buffer_append_varsint(buffer, parser.
start_line);
22490 pm_node_destroy(&parser, node);
22504 PM_SLICE_TYPE_ERROR = -1,
22507 PM_SLICE_TYPE_NONE,
22510 PM_SLICE_TYPE_LOCAL,
22513 PM_SLICE_TYPE_CONSTANT,
22516 PM_SLICE_TYPE_METHOD_NAME
22523pm_slice_type(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22525 const pm_encoding_t *encoding = pm_encoding_find((
const uint8_t *) encoding_name, (
const uint8_t *) (encoding_name + strlen(encoding_name)));
22526 if (encoding == NULL)
return PM_SLICE_TYPE_ERROR;
22529 if (length == 0)
return PM_SLICE_TYPE_NONE;
22532 if ((width = encoding->
alpha_char(source, (ptrdiff_t) length)) != 0) {
22534 }
else if (*source ==
'_') {
22537 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, (ptrdiff_t) length)) > 0)) {
22541 return PM_SLICE_TYPE_NONE;
22545 const uint8_t *end = source + length;
22546 pm_slice_type_t result = encoding->
isupper_char(source, end - source) ? PM_SLICE_TYPE_CONSTANT : PM_SLICE_TYPE_LOCAL;
22552 while (source < end) {
22553 if ((width = encoding->
alnum_char(source, end - source)) != 0) {
22556 }
else if (*source ==
'_') {
22559 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, end - source)) > 0)) {
22569 if (*source ==
'!' || *source ==
'?' || *source ==
'=') {
22571 result = PM_SLICE_TYPE_METHOD_NAME;
22575 return source == end ? result : PM_SLICE_TYPE_NONE;
22582pm_string_query_local(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22583 switch (pm_slice_type(source, length, encoding_name)) {
22584 case PM_SLICE_TYPE_ERROR:
22586 case PM_SLICE_TYPE_NONE:
22587 case PM_SLICE_TYPE_CONSTANT:
22588 case PM_SLICE_TYPE_METHOD_NAME:
22590 case PM_SLICE_TYPE_LOCAL:
22594 assert(
false &&
"unreachable");
22602pm_string_query_constant(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22603 switch (pm_slice_type(source, length, encoding_name)) {
22604 case PM_SLICE_TYPE_ERROR:
22606 case PM_SLICE_TYPE_NONE:
22607 case PM_SLICE_TYPE_LOCAL:
22608 case PM_SLICE_TYPE_METHOD_NAME:
22610 case PM_SLICE_TYPE_CONSTANT:
22614 assert(
false &&
"unreachable");
22622pm_string_query_method_name(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22623#define B(p) ((p) ? PM_STRING_QUERY_TRUE : PM_STRING_QUERY_FALSE)
22624#define C1(c) (*source == c)
22625#define C2(s) (memcmp(source, s, 2) == 0)
22626#define C3(s) (memcmp(source, s, 3) == 0)
22628 switch (pm_slice_type(source, length, encoding_name)) {
22629 case PM_SLICE_TYPE_ERROR:
22631 case PM_SLICE_TYPE_NONE:
22633 case PM_SLICE_TYPE_LOCAL:
22635 return B((length != 2) || (source[0] !=
'_') || (source[1] ==
'0') || !pm_char_is_decimal_digit(source[1]));
22636 case PM_SLICE_TYPE_CONSTANT:
22638 case PM_SLICE_TYPE_METHOD_NAME:
22645 return B(C1(
'&') || C1(
'`') || C1(
'!') || C1(
'^') || C1(
'>') || C1(
'<') || C1(
'-') || C1(
'%') || C1(
'|') || C1(
'+') || C1(
'/') || C1(
'*') || C1(
'~'));
22647 return B(C2(
"!=") || C2(
"!~") || C2(
"[]") || C2(
"==") || C2(
"=~") || C2(
">=") || C2(
">>") || C2(
"<=") || C2(
"<<") || C2(
"**"));
22649 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 (),...
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.
union pm_lex_mode::@98 as
The data associated with this type of lex mode.
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 ...
enum pm_lex_mode::@97 mode
The type of this lex mode.
const uint8_t * next_start
This is the pointer to the character where lexing should resume once the heredoc has been completely ...
size_t * common_whitespace
This is used to track the amount of common whitespace on each line so that we know how much to dedent...
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.
struct pm_parser::@103 lex_modes
A stack of lex modes.
const uint8_t * next_start
This is a special field set on the parser when we need the parser to jump to a specific location when...
pm_static_literals_t * current_hash_keys
The hash keys for the hash that is currently being parsed.
pm_list_t magic_comment_list
The list of magic comments that have been found while parsing.
int lambda_enclosure_nesting
Used to temporarily track the nesting of enclosures to determine if a { is the beginning of a lambda ...
pm_lex_callback_t * lex_callback
This is an optional callback that can be attached to the parser that will be called whenever a new to...
pm_options_version_t version
The version of prism that we should use to parse.
pm_token_t previous
The previous token we were considering.
pm_string_t current_string
This string is used to pass information from the lexer to the parser.
bool parsing_eval
Whether or not we are parsing an eval string.
bool current_regular_expression_ascii_only
True if the current regular expression being lexed contains only ASCII characters.
bool encoding_changed
Whether or not the encoding has been changed by a magic comment.
pm_location_t data_loc
An optional location that represents the location of the END marker and the rest of the content of th...
pm_context_node_t * current_context
The current parsing context.
const uint8_t * start
The pointer to the start of the source.
int enclosure_nesting
Tracks the current nesting of (), [], and {}.
pm_list_t error_list
The list of errors that have been found while parsing.
int8_t frozen_string_literal
Whether or not we have found a frozen_string_literal magic comment with a true or false value.
pm_node_list_t * current_block_exits
When parsing block exits (e.g., break, next, redo), we need to validate that they are in correct cont...
const uint8_t * encoding_comment_start
This pointer indicates where a comment must start if it is to be considered an encoding comment.
pm_lex_mode_t stack[PM_LEX_STACK_SIZE]
The stack of lexer modes.
pm_list_t warning_list
The list of warnings that have been found while parsing.
const uint8_t * heredoc_end
This field indicates the end of a heredoc whose identifier was found on the current line.
int brace_nesting
Used to track the nesting of braces to ensure we get the correct value when we are interpolating bloc...
pm_encoding_changed_callback_t encoding_changed_callback
When the encoding that is being used to parse the source is changed by prism, we provide the ability ...
int32_t start_line
The line number at the start of the parse.
bool encoding_locked
This is very specialized behavior for when you want to parse in a context that does not respect encod...
pm_lex_mode_t * current
The current mode of the lexer.
pm_list_t comment_list
The list of comments that have been found while parsing.
size_t index
The current index into the lexer mode stack.
pm_string_t filepath
This is the path of the file being parsed.
pm_scope_t * current_scope
The current local scope.
bool command_start
Whether or not we're at the beginning of a command.
pm_newline_list_t newline_list
This is the list of newline offsets in the source file.
bool semantic_token_seen
Whether or not the parser has seen a token that has semantic meaning (i.e., a token that is not a com...
uint32_t node_id
The next node identifier that will be assigned.
struct pm_node * right
RangeNode::right.
struct pm_node * left
RangeNode::left.
pm_node_t base
The embedded base node.
pm_integer_t numerator
RationalNode::numerator.
In order to properly set a regular expression's encoding and to validate the byte sequence for the un...
pm_buffer_t regexp_buffer
The buffer holding the regexp source.
pm_token_buffer_t base
The embedded base buffer.
pm_node_t base
The embedded base node.
pm_string_t unescaped
RegularExpressionNode::unescaped.
struct pm_node * rescue_expression
RescueModifierNode::rescue_expression.
struct pm_rescue_node * subsequent
RescueNode::subsequent.
pm_location_t then_keyword_loc
RescueNode::then_keyword_loc.
pm_node_t base
The embedded base node.
This struct represents a node in a linked list of scopes.
struct pm_scope * previous
A pointer to the previous scope in the linked list.
pm_node_list_t implicit_parameters
This is a list of the implicit parameters contained within the block.
pm_shareable_constant_value_t shareable_constant
The current state of constant shareability for this scope.
pm_locals_t locals
The IDs of the locals in the given scope.
pm_scope_parameters_t parameters
This is a bitfield that indicates the parameters that are being used in this scope.
bool closed
A boolean indicating whether or not this scope can see into its parent.
struct pm_node * expression
SplatNode::expression.
struct pm_node_list body
StatementsNode::body.
Certain sets of nodes (hash keys and when clauses) check for duplicate nodes to alert the user of pot...
pm_node_t base
The embedded base node.
pm_string_t unescaped
StringNode::unescaped.
pm_location_t closing_loc
StringNode::closing_loc.
pm_location_t opening_loc
StringNode::opening_loc.
A generic string type that can have various ownership semantics.
const uint8_t * source
A pointer to the start of the string.
size_t length
The length of the string in bytes of memory.
enum pm_string_t::@104 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.