15#define PM_TAB_WHITESPACE_SIZE 8
18#define MIN(a,b) (((a)<(b))?(a):(b))
19#define MAX(a,b) (((a)>(b))?(a):(b))
30lex_mode_incrementor(
const uint8_t start) {
47lex_mode_terminator(
const uint8_t start) {
89lex_mode_push_list(
pm_parser_t *parser,
bool interpolation, uint8_t delimiter) {
90 uint8_t incrementor = lex_mode_incrementor(delimiter);
91 uint8_t terminator = lex_mode_terminator(delimiter);
97 .interpolation = interpolation,
98 .incrementor = incrementor,
99 .terminator = terminator
106 memcpy(breakpoints,
"\\ \t\f\r\v\n\0\0\0",
sizeof(lex_mode.
as.list.
breakpoints));
111 if (terminator !=
'\0') {
112 breakpoints[index++] = terminator;
118 breakpoints[index++] =
'#';
122 if (incrementor !=
'\0') {
123 breakpoints[index++] = incrementor;
127 return lex_mode_push(parser, lex_mode);
137 return lex_mode_push_list(parser,
false,
'\0');
144lex_mode_push_regexp(
pm_parser_t *parser, uint8_t incrementor, uint8_t terminator) {
146 .mode = PM_LEX_REGEXP,
149 .incrementor = incrementor,
150 .terminator = terminator
158 memcpy(breakpoints,
"\r\n\\#\0\0",
sizeof(lex_mode.
as.regexp.
breakpoints));
162 if (terminator !=
'\0') {
163 breakpoints[index++] = terminator;
167 if (incrementor !=
'\0') {
168 breakpoints[index++] = incrementor;
172 return lex_mode_push(parser, lex_mode);
179lex_mode_push_string(
pm_parser_t *parser,
bool interpolation,
bool label_allowed, uint8_t incrementor, uint8_t terminator) {
181 .mode = PM_LEX_STRING,
184 .interpolation = interpolation,
185 .label_allowed = label_allowed,
186 .incrementor = incrementor,
187 .terminator = terminator
194 memcpy(breakpoints,
"\r\n\\\0\0\0",
sizeof(lex_mode.
as.string.
breakpoints));
199 if (terminator !=
'\0') {
200 breakpoints[index++] = terminator;
206 breakpoints[index++] =
'#';
211 if (incrementor !=
'\0') {
212 breakpoints[index++] = incrementor;
216 return lex_mode_push(parser, lex_mode);
226 return lex_mode_push_string(parser,
false,
false,
'\0',
'\0');
258 PM_IGNORED_NEWLINE_NONE = 0,
259 PM_IGNORED_NEWLINE_ALL,
260 PM_IGNORED_NEWLINE_PATTERN
261} pm_ignored_newline_type_t;
263static inline pm_ignored_newline_type_t
265 bool ignored = lex_state_p(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_CLASS | PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT) && !lex_state_p(parser, PM_LEX_STATE_LABELED);
268 return PM_IGNORED_NEWLINE_ALL;
269 }
else if ((parser->
lex_state & ~((
unsigned int) PM_LEX_STATE_LABEL)) == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)) {
270 return PM_IGNORED_NEWLINE_PATTERN;
272 return PM_IGNORED_NEWLINE_NONE;
278 return lex_state_p(parser, PM_LEX_STATE_BEG_ANY) || ((parser->
lex_state & (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)) == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED));
283 return lex_state_p(parser, PM_LEX_STATE_ARG_ANY);
287lex_state_spcarg_p(
pm_parser_t *parser,
bool space_seen) {
291 return lex_state_arg_p(parser) && space_seen && !pm_char_is_whitespace(*parser->
current.end);
296 return lex_state_p(parser, PM_LEX_STATE_END_ANY);
304 return lex_state_p(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT);
316#ifndef PM_DEBUG_LOGGING
321#define PM_DEBUG_LOGGING 0
327 fprintf(stderr,
"STATE: ");
330 if (parser->
lex_state == PM_LEX_STATE_NONE) {
331 fprintf(stderr,
"NONE\n");
335#define CHECK_STATE(state) \
336 if (parser->lex_state & state) { \
337 if (!first) fprintf(stderr, "|"); \
338 fprintf(stderr, "%s", #state); \
342 CHECK_STATE(PM_LEX_STATE_BEG)
343 CHECK_STATE(PM_LEX_STATE_END)
344 CHECK_STATE(PM_LEX_STATE_ENDARG)
345 CHECK_STATE(PM_LEX_STATE_ENDFN)
346 CHECK_STATE(PM_LEX_STATE_ARG)
347 CHECK_STATE(PM_LEX_STATE_CMDARG)
348 CHECK_STATE(PM_LEX_STATE_MID)
349 CHECK_STATE(PM_LEX_STATE_FNAME)
350 CHECK_STATE(PM_LEX_STATE_DOT)
351 CHECK_STATE(PM_LEX_STATE_CLASS)
352 CHECK_STATE(PM_LEX_STATE_LABEL)
353 CHECK_STATE(PM_LEX_STATE_LABELED)
354 CHECK_STATE(PM_LEX_STATE_FITEM)
358 fprintf(stderr,
"\n");
363 fprintf(stderr,
"Caller: %s:%d\nPrevious: ", caller_name, line_number);
365 lex_state_set(parser, state);
366 fprintf(stderr,
"Now: ");
368 fprintf(stderr,
"\n");
371#define lex_state_set(parser, state) debug_lex_state_set(parser, state, __func__, __LINE__)
379#define PM_PARSER_COMMAND_LINE_OPTION(parser, option) ((parser)->command_line & (option))
382#define PM_PARSER_COMMAND_LINE_OPTION_A(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_A)
385#define PM_PARSER_COMMAND_LINE_OPTION_E(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_E)
388#define PM_PARSER_COMMAND_LINE_OPTION_L(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_L)
391#define PM_PARSER_COMMAND_LINE_OPTION_N(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_N)
394#define PM_PARSER_COMMAND_LINE_OPTION_P(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_P)
397#define PM_PARSER_COMMAND_LINE_OPTION_X(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_X)
408 pm_diagnostic_list_append(&parser->
error_list, start, end, diag_id);
414#define PM_PARSER_ERR_FORMAT(parser, start, end, diag_id, ...) \
415 pm_diagnostic_list_append_format(&parser->error_list, start, end, diag_id, __VA_ARGS__)
423 pm_parser_err(parser, parser->
current.start, parser->
current.end, diag_id);
430#define PM_PARSER_ERR_LOCATION_FORMAT(parser, location, diag_id, ...) \
431 PM_PARSER_ERR_FORMAT(parser, (location)->start, (location)->end, diag_id, __VA_ARGS__)
446#define PM_PARSER_ERR_NODE_FORMAT(parser, node, diag_id, ...) \
447 PM_PARSER_ERR_FORMAT(parser, (node)->location.start, (node)->location.end, diag_id, __VA_ARGS__)
453#define PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, diag_id) \
454 PM_PARSER_ERR_NODE_FORMAT(parser, node, diag_id, (int) ((node)->location.end - (node)->location.start), (const char *) (node)->location.start)
471 pm_parser_err(parser, token->start, token->end, diag_id);
478#define PM_PARSER_ERR_TOKEN_FORMAT(parser, token, diag_id, ...) \
479 PM_PARSER_ERR_FORMAT(parser, (token).start, (token).end, diag_id, __VA_ARGS__)
485#define PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, token, diag_id) \
486 PM_PARSER_ERR_TOKEN_FORMAT(parser, token, diag_id, (int) ((token).end - (token).start), (const char *) (token).start)
493 pm_diagnostic_list_append(&parser->
warning_list, start, end, diag_id);
502 pm_parser_warn(parser, token->start, token->end, diag_id);
517#define PM_PARSER_WARN_FORMAT(parser, start, end, diag_id, ...) \
518 pm_diagnostic_list_append_format(&parser->warning_list, start, end, diag_id, __VA_ARGS__)
524#define PM_PARSER_WARN_TOKEN_FORMAT(parser, token, diag_id, ...) \
525 PM_PARSER_WARN_FORMAT(parser, (token).start, (token).end, diag_id, __VA_ARGS__)
531#define PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, token, diag_id) \
532 PM_PARSER_WARN_TOKEN_FORMAT(parser, token, diag_id, (int) ((token).end - (token).start), (const char *) (token).start)
538#define PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, ...) \
539 PM_PARSER_WARN_FORMAT(parser, (node)->location.start, (node)->location.end, diag_id, __VA_ARGS__)
547pm_parser_err_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
548 PM_PARSER_ERR_FORMAT(
551 ident_start + ident_length,
554 (
const char *) ident_start
566pm_parser_scope_push(
pm_parser_t *parser,
bool closed) {
568 if (scope == NULL)
return false;
573 .parameters = PM_SCOPE_PARAMETERS_NONE,
574 .implicit_parameters = { 0 },
592 if (scope->
previous == NULL)
return true;
593 if (scope->
closed)
return false;
594 }
while ((scope = scope->
previous) != NULL);
596 assert(
false &&
"unreachable");
604pm_parser_scope_find(
pm_parser_t *parser, uint32_t depth) {
607 while (depth-- > 0) {
608 assert(scope != NULL);
616 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS,
617 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT,
618 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL
619} pm_scope_forwarding_param_check_result_t;
621static pm_scope_forwarding_param_check_result_t
622pm_parser_scope_forwarding_param_check(
pm_parser_t *parser,
const uint8_t mask) {
624 bool conflict =
false;
626 while (scope != NULL) {
630 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT;
632 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS;
643 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL;
648 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_BLOCK)) {
649 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
652 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
653 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_AMPERSAND);
655 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
656 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_AMPERSAND);
663 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS)) {
664 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
667 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
668 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR);
670 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
671 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR);
678 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_ALL)) {
679 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
682 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
687 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
688 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
695 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS)) {
696 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
699 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
700 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR_STAR);
702 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
703 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR_STAR);
712pm_parser_scope_shareable_constant_get(
pm_parser_t *parser) {
736#define PM_LOCALS_HASH_THRESHOLD 9
751 name = ((name >> 16) ^ name) * 0x45d9f3b;
752 name = ((name >> 16) ^ name) * 0x45d9f3b;
753 name = (name >> 16) ^ name;
763 uint32_t next_capacity = locals->
capacity == 0 ? 4 : (locals->
capacity * 2);
764 assert(next_capacity > locals->
capacity);
767 if (next_locals == NULL) abort();
769 if (next_capacity < PM_LOCALS_HASH_THRESHOLD) {
770 if (locals->
size > 0) {
776 bool hash_needed = (locals->
capacity <= PM_LOCALS_HASH_THRESHOLD);
777 uint32_t mask = next_capacity - 1;
779 for (uint32_t index = 0; index < locals->
capacity; index++) {
783 if (hash_needed) local->
hash = pm_locals_hash(local->
name);
785 uint32_t hash = local->
hash;
787 next_locals[hash & mask] = *local;
792 pm_locals_free(locals);
793 locals->
locals = next_locals;
815 pm_locals_resize(locals);
818 if (locals->
capacity < PM_LOCALS_HASH_THRESHOLD) {
819 for (uint32_t index = 0; index < locals->
capacity; index++) {
825 .location = { .start = start, .end = end },
826 .index = locals->
size++,
831 }
else if (local->
name == name) {
836 uint32_t mask = locals->
capacity - 1;
837 uint32_t hash = pm_locals_hash(name);
838 uint32_t initial_hash = hash;
846 .location = { .start = start, .end = end },
847 .index = locals->
size++,
852 }
else if (local->
name == name) {
857 }
while ((hash & mask) != initial_hash);
860 assert(
false &&
"unreachable");
870 if (locals->
capacity < PM_LOCALS_HASH_THRESHOLD) {
871 for (uint32_t index = 0; index < locals->
size; index++) {
873 if (local->
name == name)
return index;
876 uint32_t mask = locals->
capacity - 1;
877 uint32_t hash = pm_locals_hash(name);
878 uint32_t initial_hash = hash & mask;
885 }
else if (local->
name == name) {
890 }
while ((hash & mask) != initial_hash);
902 uint32_t index = pm_locals_find(locals, name);
903 assert(index != UINT32_MAX);
906 assert(local->
reads < UINT32_MAX);
917 uint32_t index = pm_locals_find(locals, name);
918 assert(index != UINT32_MAX);
921 assert(local->
reads > 0);
931 uint32_t index = pm_locals_find(locals, name);
932 assert(index != UINT32_MAX);
947 pm_constant_id_list_init_capacity(list, locals->
size);
952 uint32_t capacity = locals->
capacity < PM_LOCALS_HASH_THRESHOLD ? locals->
size : locals->
capacity;
956 bool warn_unused = !toplevel || (!parser->parsing_eval && !PM_PARSER_COMMAND_LINE_OPTION_E(parser));
958 for (uint32_t index = 0; index < capacity; index++) {
962 pm_constant_id_list_insert(list, (
size_t) local->
index, local->
name);
964 if (warn_unused && local->
reads == 0 && ((parser->start_line >= 0) || (pm_newline_list_line(&parser->newline_list, local->
location.
start, parser->start_line) >= 0))) {
965 pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, local->
name);
967 if (constant->
length >= 1 && *constant->
start !=
'_') {
968 PM_PARSER_WARN_FORMAT(
972 PM_WARN_UNUSED_LOCAL_VARIABLE,
974 (
const char *) constant->
start
990pm_parser_constant_id_location(
pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
991 return pm_constant_pool_insert_shared(&parser->
constant_pool, start, (
size_t) (end - start));
998pm_parser_constant_id_owned(
pm_parser_t *parser, uint8_t *start,
size_t length) {
999 return pm_constant_pool_insert_owned(&parser->
constant_pool, start, length);
1006pm_parser_constant_id_constant(
pm_parser_t *parser,
const char *start,
size_t length) {
1007 return pm_constant_pool_insert_constant(&parser->
constant_pool, (
const uint8_t *) start, length);
1015 return pm_parser_constant_id_location(parser, token->start, token->end);
1024 return token->type == PM_TOKEN_NOT_PROVIDED ? 0 : pm_parser_constant_id_token(parser, token);
1033pm_check_value_expression(
pm_parser_t *parser, pm_node_t *node) {
1034 pm_node_t *void_node = NULL;
1036 while (node != NULL) {
1037 switch (PM_NODE_TYPE(node)) {
1038 case PM_RETURN_NODE:
1043 case PM_MATCH_REQUIRED_NODE:
1044 return void_node != NULL ? void_node : node;
1045 case PM_MATCH_PREDICATE_NODE:
1047 case PM_BEGIN_NODE: {
1048 pm_begin_node_t *cast = (pm_begin_node_t *) node;
1052 pm_node_t *vn = pm_check_value_expression(parser, (pm_node_t *) cast->
rescue_clause);
1053 if (vn != NULL)
return vn;
1057 pm_node_t *vn = pm_check_value_expression(parser, (pm_node_t *) cast->
statements);
1058 if (vn != NULL)
return vn;
1065 pm_node_t *vn = pm_check_value_expression(parser, (pm_node_t *) cast->
statements);
1066 if (vn == NULL)
return NULL;
1067 if (void_node == NULL) void_node = vn;
1069 for (pm_rescue_node_t *rescue_clause = cast->
rescue_clause; rescue_clause != NULL; rescue_clause = rescue_clause->
subsequent) {
1070 pm_node_t *vn = pm_check_value_expression(parser, (pm_node_t *) rescue_clause->statements);
1075 if (void_node == NULL) {
1091 case PM_ENSURE_NODE: {
1092 pm_ensure_node_t *cast = (pm_ensure_node_t *) node;
1096 case PM_PARENTHESES_NODE: {
1097 pm_parentheses_node_t *cast = (pm_parentheses_node_t *) node;
1098 node = (pm_node_t *) cast->
body;
1101 case PM_STATEMENTS_NODE: {
1102 pm_statements_node_t *cast = (pm_statements_node_t *) node;
1107 pm_if_node_t *cast = (pm_if_node_t *) node;
1111 pm_node_t *vn = pm_check_value_expression(parser, (pm_node_t *) cast->
statements);
1115 if (void_node == NULL) {
1121 case PM_UNLESS_NODE: {
1122 pm_unless_node_t *cast = (pm_unless_node_t *) node;
1126 pm_node_t *vn = pm_check_value_expression(parser, (pm_node_t *) cast->
statements);
1130 if (void_node == NULL) {
1136 case PM_ELSE_NODE: {
1137 pm_else_node_t *cast = (pm_else_node_t *) node;
1142 pm_and_node_t *cast = (pm_and_node_t *) node;
1147 pm_or_node_t *cast = (pm_or_node_t *) node;
1151 case PM_LOCAL_VARIABLE_WRITE_NODE: {
1152 pm_local_variable_write_node_t *cast = (pm_local_variable_write_node_t *) node;
1155 for (uint32_t depth = 0; depth < cast->
depth; depth++) scope = scope->
previous;
1169pm_assert_value_expression(
pm_parser_t *parser, pm_node_t *node) {
1170 pm_node_t *void_node = pm_check_value_expression(parser, node);
1171 if (void_node != NULL) {
1172 pm_parser_err_node(parser, void_node, PM_ERR_VOID_EXPRESSION);
1180pm_void_statement_check(
pm_parser_t *parser,
const pm_node_t *node) {
1181 const char *
type = NULL;
1184 switch (PM_NODE_TYPE(node)) {
1185 case PM_BACK_REFERENCE_READ_NODE:
1186 case PM_CLASS_VARIABLE_READ_NODE:
1187 case PM_GLOBAL_VARIABLE_READ_NODE:
1188 case PM_INSTANCE_VARIABLE_READ_NODE:
1189 case PM_LOCAL_VARIABLE_READ_NODE:
1190 case PM_NUMBERED_REFERENCE_READ_NODE:
1191 type =
"a variable";
1194 case PM_CALL_NODE: {
1195 const pm_call_node_t *cast = (
const pm_call_node_t *) node;
1199 switch (message->
length) {
1201 switch (message->
start[0]) {
1218 switch (message->
start[1]) {
1220 if (message->
start[0] ==
'<' || message->
start[0] ==
'>' || message->
start[0] ==
'!' || message->
start[0] ==
'=') {
1226 if (message->
start[0] ==
'+' || message->
start[0] ==
'-') {
1232 if (message->
start[0] ==
'*') {
1240 if (memcmp(message->
start,
"<=>", 3) == 0) {
1249 case PM_CONSTANT_PATH_NODE:
1253 case PM_CONSTANT_READ_NODE:
1254 type =
"a constant";
1257 case PM_DEFINED_NODE:
1266 case PM_IMAGINARY_NODE:
1267 case PM_INTEGER_NODE:
1268 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
1269 case PM_INTERPOLATED_STRING_NODE:
1270 case PM_RATIONAL_NODE:
1271 case PM_REGULAR_EXPRESSION_NODE:
1272 case PM_SOURCE_ENCODING_NODE:
1273 case PM_SOURCE_FILE_NODE:
1274 case PM_SOURCE_LINE_NODE:
1275 case PM_STRING_NODE:
1276 case PM_SYMBOL_NODE:
1284 case PM_RANGE_NODE: {
1285 const pm_range_node_t *cast = (
const pm_range_node_t *) node;
1287 if (PM_NODE_FLAG_P(cast, PM_RANGE_FLAGS_EXCLUDE_END)) {
1310 PM_PARSER_WARN_NODE_FORMAT(parser, node, PM_WARN_VOID_STATEMENT, length,
type);
1319pm_void_statements_check(
pm_parser_t *parser,
const pm_statements_node_t *node,
bool last_value) {
1321 const size_t size = node->
body.
size - (last_value ? 1 : 0);
1322 for (
size_t index = 0; index < size; index++) {
1323 pm_void_statement_check(parser, node->
body.
nodes[index]);
1333 PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL,
1334 PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP,
1335 PM_CONDITIONAL_PREDICATE_TYPE_NOT
1336} pm_conditional_predicate_type_t;
1342pm_parser_warn_conditional_predicate_literal(
pm_parser_t *parser, pm_node_t *node, pm_conditional_predicate_type_t
type,
pm_diagnostic_id_t diag_id,
const char *prefix) {
1344 case PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL:
1345 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"condition");
1347 case PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP:
1348 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"flip-flop");
1350 case PM_CONDITIONAL_PREDICATE_TYPE_NOT:
1360pm_conditional_predicate_warn_write_literal_p(
const pm_node_t *node) {
1361 switch (PM_NODE_TYPE(node)) {
1362 case PM_ARRAY_NODE: {
1363 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1365 const pm_array_node_t *cast = (
const pm_array_node_t *) node;
1366 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1367 if (!pm_conditional_predicate_warn_write_literal_p(cast->
elements.
nodes[index]))
return false;
1372 case PM_HASH_NODE: {
1373 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1375 const pm_hash_node_t *cast = (
const pm_hash_node_t *) node;
1376 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1378 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE))
return false;
1380 const pm_assoc_node_t *assoc = (
const pm_assoc_node_t *) element;
1381 if (!pm_conditional_predicate_warn_write_literal_p(assoc->
key) || !pm_conditional_predicate_warn_write_literal_p(assoc->
value))
return false;
1388 case PM_IMAGINARY_NODE:
1389 case PM_INTEGER_NODE:
1391 case PM_RATIONAL_NODE:
1392 case PM_REGULAR_EXPRESSION_NODE:
1393 case PM_SOURCE_ENCODING_NODE:
1394 case PM_SOURCE_FILE_NODE:
1395 case PM_SOURCE_LINE_NODE:
1396 case PM_STRING_NODE:
1397 case PM_SYMBOL_NODE:
1410pm_conditional_predicate_warn_write_literal(
pm_parser_t *parser,
const pm_node_t *node) {
1411 if (pm_conditional_predicate_warn_write_literal_p(node)) {
1429pm_conditional_predicate(
pm_parser_t *parser, pm_node_t *node, pm_conditional_predicate_type_t
type) {
1430 switch (PM_NODE_TYPE(node)) {
1432 pm_and_node_t *cast = (pm_and_node_t *) node;
1433 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1434 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1438 pm_or_node_t *cast = (pm_or_node_t *) node;
1439 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1440 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1443 case PM_PARENTHESES_NODE: {
1444 pm_parentheses_node_t *cast = (pm_parentheses_node_t *) node;
1446 if ((cast->
body != NULL) && PM_NODE_TYPE_P(cast->
body, PM_STATEMENTS_NODE)) {
1447 pm_statements_node_t *statements = (pm_statements_node_t *) cast->
body;
1448 if (statements->body.size == 1) pm_conditional_predicate(parser, statements->body.nodes[0],
type);
1453 case PM_BEGIN_NODE: {
1454 pm_begin_node_t *cast = (pm_begin_node_t *) node;
1456 pm_statements_node_t *statements = cast->
statements;
1461 case PM_RANGE_NODE: {
1462 pm_range_node_t *cast = (pm_range_node_t *) node;
1464 if (cast->
left != NULL) pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1465 if (cast->
right != NULL) pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1472 assert(
sizeof(pm_range_node_t) ==
sizeof(pm_flip_flop_node_t));
1473 node->
type = PM_FLIP_FLOP_NODE;
1477 case PM_REGULAR_EXPRESSION_NODE:
1481 assert(
sizeof(pm_regular_expression_node_t) ==
sizeof(pm_match_last_line_node_t));
1482 node->
type = PM_MATCH_LAST_LINE_NODE;
1484 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1485 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"regex ");
1489 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
1493 assert(
sizeof(pm_interpolated_regular_expression_node_t) ==
sizeof(pm_interpolated_match_last_line_node_t));
1494 node->
type = PM_INTERPOLATED_MATCH_LAST_LINE_NODE;
1496 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1497 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"regex ");
1501 case PM_INTEGER_NODE:
1502 if (
type == PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP) {
1503 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1504 pm_parser_warn_node(parser, node, PM_WARN_INTEGER_IN_FLIP_FLOP);
1507 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1510 case PM_STRING_NODE:
1511 case PM_SOURCE_FILE_NODE:
1512 case PM_INTERPOLATED_STRING_NODE:
1513 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"string ");
1515 case PM_SYMBOL_NODE:
1516 case PM_INTERPOLATED_SYMBOL_NODE:
1517 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"symbol ");
1519 case PM_SOURCE_LINE_NODE:
1520 case PM_SOURCE_ENCODING_NODE:
1522 case PM_RATIONAL_NODE:
1523 case PM_IMAGINARY_NODE:
1524 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1526 case PM_CLASS_VARIABLE_WRITE_NODE:
1527 pm_conditional_predicate_warn_write_literal(parser, ((pm_class_variable_write_node_t *) node)->value);
1529 case PM_CONSTANT_WRITE_NODE:
1530 pm_conditional_predicate_warn_write_literal(parser, ((pm_constant_write_node_t *) node)->value);
1532 case PM_GLOBAL_VARIABLE_WRITE_NODE:
1533 pm_conditional_predicate_warn_write_literal(parser, ((pm_global_variable_write_node_t *) node)->value);
1535 case PM_INSTANCE_VARIABLE_WRITE_NODE:
1536 pm_conditional_predicate_warn_write_literal(parser, ((pm_instance_variable_write_node_t *) node)->value);
1538 case PM_LOCAL_VARIABLE_WRITE_NODE:
1539 pm_conditional_predicate_warn_write_literal(parser, ((pm_local_variable_write_node_t *) node)->value);
1541 case PM_MULTI_WRITE_NODE:
1542 pm_conditional_predicate_warn_write_literal(parser, ((pm_multi_write_node_t *) node)->value);
1559 return (
pm_token_t) { .type = PM_TOKEN_NOT_PROVIDED, .start = parser->
start, .end = parser->
start };
1562#define PM_LOCATION_NULL_VALUE(parser) ((pm_location_t) { .start = (parser)->start, .end = (parser)->start })
1563#define PM_LOCATION_TOKEN_VALUE(token) ((pm_location_t) { .start = (token)->start, .end = (token)->end })
1564#define PM_LOCATION_NODE_VALUE(node) ((pm_location_t) { .start = (node)->location.start, .end = (node)->location.end })
1565#define PM_LOCATION_NODE_BASE_VALUE(node) ((pm_location_t) { .start = (node)->base.location.start, .end = (node)->base.location.end })
1566#define PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE ((pm_location_t) { .start = NULL, .end = NULL })
1567#define PM_OPTIONAL_LOCATION_TOKEN_VALUE(token) ((token)->type == PM_TOKEN_NOT_PROVIDED ? PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE : PM_LOCATION_TOKEN_VALUE(token))
1595static inline const uint8_t *
1597 if (arguments->
block != NULL) {
1638 pm_parser_err_node(parser, (pm_node_t *) block, PM_ERR_ARGUMENT_UNEXPECTED_BLOCK);
1652char_is_identifier_start(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
1653 if (n <= 0)
return 0;
1660 }
else if (*b ==
'_') {
1662 }
else if (*b >= 0x80) {
1667 }
else if (*b < 0x80) {
1670 return pm_encoding_utf_8_char_width(b, n);
1679char_is_identifier_utf8(
const uint8_t *b, ptrdiff_t n) {
1682 }
else if (*b < 0x80) {
1685 return pm_encoding_utf_8_char_width(b, n);
1695char_is_identifier(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
1703 }
else if (*b ==
'_') {
1705 }
else if (*b >= 0x80) {
1711 return char_is_identifier_utf8(b, n);
1718#define BIT(c, idx) (((c) / 32 - 1 == idx) ? (1U << ((c) % 32)) : 0)
1719#define PUNCT(idx) ( \
1720 BIT('~', idx) | BIT('*', idx) | BIT('$', idx) | BIT('?', idx) | \
1721 BIT('!', idx) | BIT('@', idx) | BIT('/', idx) | BIT('\\', idx) | \
1722 BIT(';', idx) | BIT(',', idx) | BIT('.', idx) | BIT('=', idx) | \
1723 BIT(':', idx) | BIT('<', idx) | BIT('>', idx) | BIT('\"', idx) | \
1724 BIT('&', idx) | BIT('`', idx) | BIT('\'', idx) | BIT('+', idx) | \
1727const unsigned int pm_global_name_punctuation_hash[(0x7e - 0x20 + 31) / 32] = { PUNCT(0), PUNCT(1), PUNCT(2) };
1733char_is_global_name_punctuation(const uint8_t b) {
1734 const unsigned int i = (const unsigned int) b;
1735 if (i <= 0x20 || 0x7e < i) return false;
1737 return (pm_global_name_punctuation_hash[(i - 0x20) / 32] >> (i % 32)) & 1;
1741token_is_setter_name(pm_token_t *token) {
1743 (token->type == PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL) ||
1744 ((token->type == PM_TOKEN_IDENTIFIER) &&
1745 (token->end - token->start >= 2) &&
1746 (token->end[-1] == '='))
1754pm_local_is_keyword(const char *source, size_t length) {
1755#define KEYWORD(name) if (memcmp(source, name, length) == 0) return true
1759 switch (source[0]) {
1760 case 'd': KEYWORD("do"); return false;
1761 case 'i': KEYWORD("if"); KEYWORD("in"); return false;
1762 case 'o': KEYWORD("or"); return false;
1763 default: return false;
1766 switch (source[0]) {
1767 case 'a': KEYWORD("and"); return false;
1768 case 'd': KEYWORD("def"); return false;
1769 case 'e': KEYWORD("end"); return false;
1770 case 'f': KEYWORD("for"); return false;
1771 case 'n': KEYWORD("nil"); KEYWORD("not"); return false;
1772 default: return false;
1775 switch (source[0]) {
1776 case 'c': KEYWORD("case"); return false;
1777 case 'e': KEYWORD("else"); return false;
1778 case 'n': KEYWORD("next"); return false;
1779 case 'r': KEYWORD("redo"); return false;
1780 case 's': KEYWORD("self"); return false;
1781 case 't': KEYWORD("then"); KEYWORD("true"); return false;
1782 case 'w': KEYWORD("when"); return false;
1783 default: return false;
1786 switch (source[0]) {
1787 case 'a': KEYWORD("alias"); return false;
1788 case 'b': KEYWORD("begin"); KEYWORD("break"); return false;
1789 case 'c': KEYWORD("class"); return false;
1790 case 'e': KEYWORD("elsif"); return false;
1791 case 'f': KEYWORD("false"); return false;
1792 case 'r': KEYWORD("retry"); return false;
1793 case 's': KEYWORD("super"); return false;
1794 case 'u': KEYWORD("undef"); KEYWORD("until"); return false;
1795 case 'w': KEYWORD("while"); return false;
1796 case 'y': KEYWORD("yield"); return false;
1797 default: return false;
1800 switch (source[0]) {
1801 case 'e': KEYWORD("ensure"); return false;
1802 case 'm': KEYWORD("module"); return false;
1803 case 'r': KEYWORD("rescue"); KEYWORD("return"); return false;
1804 case 'u': KEYWORD("unless"); return false;
1805 default: return false;
1808 KEYWORD("__LINE__");
1809 KEYWORD("__FILE__");
1812 KEYWORD("__ENCODING__");
1821/******************************************************************************/
1822/* Node flag handling functions */
1823/******************************************************************************/
1829pm_node_flag_set(pm_node_t *node, pm_node_flags_t flag) {
1830 node->flags |= flag;
1837pm_node_flag_unset(pm_node_t *node, pm_node_flags_t flag) {
1838 node->flags &= (pm_node_flags_t) ~flag;
1845pm_node_flag_set_repeated_parameter(pm_node_t *node) {
1846 assert(PM_NODE_TYPE(node) == PM_BLOCK_LOCAL_VARIABLE_NODE ||
1847 PM_NODE_TYPE(node) == PM_BLOCK_PARAMETER_NODE ||
1848 PM_NODE_TYPE(node) == PM_KEYWORD_REST_PARAMETER_NODE ||
1849 PM_NODE_TYPE(node) == PM_OPTIONAL_KEYWORD_PARAMETER_NODE ||
1850 PM_NODE_TYPE(node) == PM_OPTIONAL_PARAMETER_NODE ||
1851 PM_NODE_TYPE(node) == PM_REQUIRED_KEYWORD_PARAMETER_NODE ||
1852 PM_NODE_TYPE(node) == PM_REQUIRED_PARAMETER_NODE ||
1853 PM_NODE_TYPE(node) == PM_REST_PARAMETER_NODE);
1855 pm_node_flag_set(node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER);
1858/******************************************************************************/
1859/* Node creation functions */
1860/******************************************************************************/
1867#define PM_REGULAR_EXPRESSION_ENCODING_MASK ~(PM_REGULAR_EXPRESSION_FLAGS_EUC_JP | PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J | PM_REGULAR_EXPRESSION_FLAGS_UTF_8)
1872static inline pm_node_flags_t
1873pm_regular_expression_flags_create(pm_parser_t *parser, const pm_token_t *closing) {
1874 pm_node_flags_t flags = 0;
1876 if (closing->type == PM_TOKEN_REGEXP_END) {
1877 pm_buffer_t unknown_flags = { 0 };
1879 for (const uint8_t *flag = closing->start + 1; flag < closing->end; flag++) {
1881 case 'i': flags |= PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE; break;
1882 case 'm': flags |= PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE; break;
1883 case 'x': flags |= PM_REGULAR_EXPRESSION_FLAGS_EXTENDED; break;
1884 case 'o': flags |= PM_REGULAR_EXPRESSION_FLAGS_ONCE; break;
1886 case 'e': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_EUC_JP); break;
1887 case 'n': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT); break;
1888 case 's': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J); break;
1889 case 'u': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_UTF_8); break;
1891 default: pm_buffer_append_byte(&unknown_flags, *flag);
1895 size_t unknown_flags_length = pm_buffer_length(&unknown_flags);
1896 if (unknown_flags_length != 0) {
1897 const char *word = unknown_flags_length >= 2 ? "options" : "option";
1898 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, PM_ERR_REGEXP_UNKNOWN_OPTIONS, word, unknown_flags_length, pm_buffer_value(&unknown_flags));
1900 pm_buffer_free(&unknown_flags);
1906#undef PM_REGULAR_EXPRESSION_ENCODING_MASK
1908static pm_statements_node_t *
1909pm_statements_node_create(pm_parser_t *parser);
1912pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline);
1915pm_statements_node_body_length(pm_statements_node_t *node);
1922pm_node_alloc(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, size_t size) {
1923 void *memory = xcalloc(1, size);
1924 if (memory == NULL) {
1925 fprintf(stderr, "Failed to allocate %d bytes\n", (int) size);
1931#define PM_NODE_ALLOC(parser, type) (type *) pm_node_alloc(parser, sizeof(type))
1932#define PM_NODE_IDENTIFY(parser) (++parser->node_id)
1937static pm_missing_node_t *
1938pm_missing_node_create(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
1939 pm_missing_node_t *node = PM_NODE_ALLOC(parser, pm_missing_node_t);
1941 *node = (pm_missing_node_t) {{
1942 .type = PM_MISSING_NODE,
1943 .node_id = PM_NODE_IDENTIFY(parser),
1944 .location = { .start = start, .end = end }
1953static pm_alias_global_variable_node_t *
1954pm_alias_global_variable_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
1955 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
1956 pm_alias_global_variable_node_t *node = PM_NODE_ALLOC(parser, pm_alias_global_variable_node_t);
1958 *node = (pm_alias_global_variable_node_t) {
1960 .type = PM_ALIAS_GLOBAL_VARIABLE_NODE,
1961 .node_id = PM_NODE_IDENTIFY(parser),
1963 .start = keyword->start,
1964 .end = old_name->location.end
1967 .new_name = new_name,
1968 .old_name = old_name,
1969 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
1978static pm_alias_method_node_t *
1979pm_alias_method_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
1980 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
1981 pm_alias_method_node_t *node = PM_NODE_ALLOC(parser, pm_alias_method_node_t);
1983 *node = (pm_alias_method_node_t) {
1985 .type = PM_ALIAS_METHOD_NODE,
1986 .node_id = PM_NODE_IDENTIFY(parser),
1988 .start = keyword->start,
1989 .end = old_name->location.end
1992 .new_name = new_name,
1993 .old_name = old_name,
1994 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
2003static pm_alternation_pattern_node_t *
2004pm_alternation_pattern_node_create(pm_parser_t *parser, pm_node_t *left, pm_node_t *right, const pm_token_t *operator) {
2005 pm_alternation_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_alternation_pattern_node_t);
2007 *node = (pm_alternation_pattern_node_t) {
2009 .type = PM_ALTERNATION_PATTERN_NODE,
2010 .node_id = PM_NODE_IDENTIFY(parser),
2012 .start = left->location.start,
2013 .end = right->location.end
2018 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2027static pm_and_node_t *
2028pm_and_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
2029 pm_assert_value_expression(parser, left);
2031 pm_and_node_t *node = PM_NODE_ALLOC(parser, pm_and_node_t);
2033 *node = (pm_and_node_t) {
2035 .type = PM_AND_NODE,
2036 .node_id = PM_NODE_IDENTIFY(parser),
2038 .start = left->location.start,
2039 .end = right->location.end
2043 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2053static pm_arguments_node_t *
2054pm_arguments_node_create(pm_parser_t *parser) {
2055 pm_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_arguments_node_t);
2057 *node = (pm_arguments_node_t) {
2059 .type = PM_ARGUMENTS_NODE,
2060 .node_id = PM_NODE_IDENTIFY(parser),
2061 .location = PM_LOCATION_NULL_VALUE(parser)
2073pm_arguments_node_size(pm_arguments_node_t *node) {
2074 return node->arguments.size;
2081pm_arguments_node_arguments_append(pm_arguments_node_t *node, pm_node_t *argument) {
2082 if (pm_arguments_node_size(node) == 0) {
2083 node->base.location.start = argument->location.start;
2086 node->base.location.end = argument->location.end;
2087 pm_node_list_append(&node->arguments, argument);
2089 if (PM_NODE_TYPE_P(argument, PM_SPLAT_NODE)) {
2090 if (PM_NODE_FLAG_P(node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
2091 pm_node_flag_set((pm_node_t *) node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS);
2093 pm_node_flag_set((pm_node_t *) node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT);
2101static pm_array_node_t *
2102pm_array_node_create(pm_parser_t *parser, const pm_token_t *opening) {
2103 pm_array_node_t *node = PM_NODE_ALLOC(parser, pm_array_node_t);
2105 *node = (pm_array_node_t) {
2107 .type = PM_ARRAY_NODE,
2108 .flags = PM_NODE_FLAG_STATIC_LITERAL,
2109 .node_id = PM_NODE_IDENTIFY(parser),
2110 .location = PM_LOCATION_TOKEN_VALUE(opening)
2112 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2113 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2124pm_array_node_elements_append(pm_array_node_t *node, pm_node_t *element) {
2125 if (!node->elements.size && !node->opening_loc.start) {
2126 node->base.location.start = element->location.start;
2129 pm_node_list_append(&node->elements, element);
2130 node->base.location.end = element->location.end;
2132 // If the element is not a static literal, then the array is not a static
2133 // literal. Turn that flag off.
2134 if (PM_NODE_TYPE_P(element, PM_ARRAY_NODE) || PM_NODE_TYPE_P(element, PM_HASH_NODE) || PM_NODE_TYPE_P(element, PM_RANGE_NODE) || !PM_NODE_FLAG_P(element, PM_NODE_FLAG_STATIC_LITERAL)) {
2135 pm_node_flag_unset((pm_node_t *)node, PM_NODE_FLAG_STATIC_LITERAL);
2138 if (PM_NODE_TYPE_P(element, PM_SPLAT_NODE)) {
2139 pm_node_flag_set((pm_node_t *)node, PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT);
2147pm_array_node_close_set(pm_array_node_t *node, const pm_token_t *closing) {
2148 assert(closing->type == PM_TOKEN_BRACKET_RIGHT || closing->type == PM_TOKEN_STRING_END || closing->type == PM_TOKEN_MISSING || closing->type == PM_TOKEN_NOT_PROVIDED);
2149 node->base.location.end = closing->end;
2150 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
2157static pm_array_pattern_node_t *
2158pm_array_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *nodes) {
2159 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2161 *node = (pm_array_pattern_node_t) {
2163 .type = PM_ARRAY_PATTERN_NODE,
2164 .node_id = PM_NODE_IDENTIFY(parser),
2166 .start = nodes->nodes[0]->location.start,
2167 .end = nodes->nodes[nodes->size - 1]->location.end
2174 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2175 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
2178 // For now we're going to just copy over each pointer manually. This could be
2179 // much more efficient, as we could instead resize the node list.
2180 bool found_rest = false;
2183 PM_NODE_LIST_FOREACH(nodes, index, child) {
2184 if (!found_rest && (PM_NODE_TYPE_P(child, PM_SPLAT_NODE) || PM_NODE_TYPE_P(child, PM_IMPLICIT_REST_NODE))) {
2187 } else if (found_rest) {
2188 pm_node_list_append(&node->posts, child);
2190 pm_node_list_append(&node->requireds, child);
2200static pm_array_pattern_node_t *
2201pm_array_pattern_node_rest_create(pm_parser_t *parser, pm_node_t *rest) {
2202 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2204 *node = (pm_array_pattern_node_t) {
2206 .type = PM_ARRAY_PATTERN_NODE,
2207 .node_id = PM_NODE_IDENTIFY(parser),
2208 .location = rest->location,
2214 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2215 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
2225static pm_array_pattern_node_t *
2226pm_array_pattern_node_constant_create(pm_parser_t *parser, pm_node_t *constant, const pm_token_t *opening, const pm_token_t *closing) {
2227 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2229 *node = (pm_array_pattern_node_t) {
2231 .type = PM_ARRAY_PATTERN_NODE,
2232 .node_id = PM_NODE_IDENTIFY(parser),
2234 .start = constant->location.start,
2238 .constant = constant,
2240 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2241 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
2253static pm_array_pattern_node_t *
2254pm_array_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
2255 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2257 *node = (pm_array_pattern_node_t) {
2259 .type = PM_ARRAY_PATTERN_NODE,
2260 .node_id = PM_NODE_IDENTIFY(parser),
2262 .start = opening->start,
2268 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2269 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
2278pm_array_pattern_node_requireds_append(pm_array_pattern_node_t *node, pm_node_t *inner) {
2279 pm_node_list_append(&node->requireds, inner);
2285static pm_assoc_node_t *
2286pm_assoc_node_create(pm_parser_t *parser, pm_node_t *key, const pm_token_t *operator, pm_node_t *value) {
2287 pm_assoc_node_t *node = PM_NODE_ALLOC(parser, pm_assoc_node_t);
2290 if (value != NULL && value->location.end > key->location.end) {
2291 end = value->location.end;
2292 } else if (operator->type != PM_TOKEN_NOT_PROVIDED) {
2293 end = operator->end;
2295 end = key->location.end;
2298 // Hash string keys will be frozen, so we can mark them as frozen here so
2299 // that the compiler picks them up and also when we check for static literal
2300 // on the keys it gets factored in.
2301 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
2302 key->flags |= PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL;
2305 // If the key and value of this assoc node are both static literals, then
2306 // we can mark this node as a static literal.
2307 pm_node_flags_t flags = 0;
2309 !PM_NODE_TYPE_P(key, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(key, PM_HASH_NODE) && !PM_NODE_TYPE_P(key, PM_RANGE_NODE) &&
2310 value && !PM_NODE_TYPE_P(value, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(value, PM_HASH_NODE) && !PM_NODE_TYPE_P(value, PM_RANGE_NODE)
2312 flags = key->flags & value->flags & PM_NODE_FLAG_STATIC_LITERAL;
2315 *node = (pm_assoc_node_t) {
2317 .type = PM_ASSOC_NODE,
2319 .node_id = PM_NODE_IDENTIFY(parser),
2321 .start = key->location.start,
2326 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
2336static pm_assoc_splat_node_t *
2337pm_assoc_splat_node_create(pm_parser_t *parser, pm_node_t *value, const pm_token_t *operator) {
2338 assert(operator->type == PM_TOKEN_USTAR_STAR);
2339 pm_assoc_splat_node_t *node = PM_NODE_ALLOC(parser, pm_assoc_splat_node_t);
2341 *node = (pm_assoc_splat_node_t) {
2343 .type = PM_ASSOC_SPLAT_NODE,
2344 .node_id = PM_NODE_IDENTIFY(parser),
2346 .start = operator->start,
2347 .end = value == NULL ? operator->end : value->location.end
2351 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2360static pm_back_reference_read_node_t *
2361pm_back_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
2362 assert(name->type == PM_TOKEN_BACK_REFERENCE);
2363 pm_back_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_back_reference_read_node_t);
2365 *node = (pm_back_reference_read_node_t) {
2367 .type = PM_BACK_REFERENCE_READ_NODE,
2368 .node_id = PM_NODE_IDENTIFY(parser),
2369 .location = PM_LOCATION_TOKEN_VALUE(name),
2371 .name = pm_parser_constant_id_token(parser, name)
2380static pm_begin_node_t *
2381pm_begin_node_create(pm_parser_t *parser, const pm_token_t *begin_keyword, pm_statements_node_t *statements) {
2382 pm_begin_node_t *node = PM_NODE_ALLOC(parser, pm_begin_node_t);
2384 *node = (pm_begin_node_t) {
2386 .type = PM_BEGIN_NODE,
2387 .node_id = PM_NODE_IDENTIFY(parser),
2389 .start = begin_keyword->start,
2390 .end = statements == NULL ? begin_keyword->end : statements->base.location.end
2393 .begin_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(begin_keyword),
2394 .statements = statements,
2395 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
2405pm_begin_node_rescue_clause_set(pm_begin_node_t *node, pm_rescue_node_t *rescue_clause) {
2406 // If the begin keyword doesn't exist, we set the start on the begin_node
2407 if (!node->begin_keyword_loc.start) {
2408 node->base.location.start = rescue_clause->base.location.start;
2410 node->base.location.end = rescue_clause->base.location.end;
2411 node->rescue_clause = rescue_clause;
2418pm_begin_node_else_clause_set(pm_begin_node_t *node, pm_else_node_t *else_clause) {
2419 node->base.location.end = else_clause->base.location.end;
2420 node->else_clause = else_clause;
2427pm_begin_node_ensure_clause_set(pm_begin_node_t *node, pm_ensure_node_t *ensure_clause) {
2428 node->base.location.end = ensure_clause->base.location.end;
2429 node->ensure_clause = ensure_clause;
2436pm_begin_node_end_keyword_set(pm_begin_node_t *node, const pm_token_t *end_keyword) {
2437 assert(end_keyword->type == PM_TOKEN_KEYWORD_END || end_keyword->type == PM_TOKEN_MISSING);
2439 node->base.location.end = end_keyword->end;
2440 node->end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword);
2446static pm_block_argument_node_t *
2447pm_block_argument_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
2448 pm_block_argument_node_t *node = PM_NODE_ALLOC(parser, pm_block_argument_node_t);
2450 *node = (pm_block_argument_node_t) {
2452 .type = PM_BLOCK_ARGUMENT_NODE,
2453 .node_id = PM_NODE_IDENTIFY(parser),
2455 .start = operator->start,
2456 .end = expression == NULL ? operator->end : expression->location.end
2459 .expression = expression,
2460 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2469static pm_block_node_t *
2470pm_block_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const pm_token_t *opening, pm_node_t *parameters, pm_node_t *body, const pm_token_t *closing) {
2471 pm_block_node_t *node = PM_NODE_ALLOC(parser, pm_block_node_t);
2473 *node = (pm_block_node_t) {
2475 .type = PM_BLOCK_NODE,
2476 .node_id = PM_NODE_IDENTIFY(parser),
2477 .location = { .start = opening->start, .end = closing->end },
2480 .parameters = parameters,
2482 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2483 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
2492static pm_block_parameter_node_t *
2493pm_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator) {
2494 assert(operator->type == PM_TOKEN_NOT_PROVIDED || operator->type == PM_TOKEN_UAMPERSAND || operator->type == PM_TOKEN_AMPERSAND);
2495 pm_block_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_block_parameter_node_t);
2497 *node = (pm_block_parameter_node_t) {
2499 .type = PM_BLOCK_PARAMETER_NODE,
2500 .node_id = PM_NODE_IDENTIFY(parser),
2502 .start = operator->start,
2503 .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
2506 .name = pm_parser_optional_constant_id_token(parser, name),
2507 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
2508 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2517static pm_block_parameters_node_t *
2518pm_block_parameters_node_create(pm_parser_t *parser, pm_parameters_node_t *parameters, const pm_token_t *opening) {
2519 pm_block_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_block_parameters_node_t);
2521 const uint8_t *start;
2522 if (opening->type != PM_TOKEN_NOT_PROVIDED) {
2523 start = opening->start;
2524 } else if (parameters != NULL) {
2525 start = parameters->base.location.start;
2531 if (parameters != NULL) {
2532 end = parameters->base.location.end;
2533 } else if (opening->type != PM_TOKEN_NOT_PROVIDED) {
2539 *node = (pm_block_parameters_node_t) {
2541 .type = PM_BLOCK_PARAMETERS_NODE,
2542 .node_id = PM_NODE_IDENTIFY(parser),
2548 .parameters = parameters,
2549 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2550 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2561pm_block_parameters_node_closing_set(pm_block_parameters_node_t *node, const pm_token_t *closing) {
2562 assert(closing->type == PM_TOKEN_PIPE || closing->type == PM_TOKEN_PARENTHESIS_RIGHT || closing->type == PM_TOKEN_MISSING);
2564 node->base.location.end = closing->end;
2565 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
2571static pm_block_local_variable_node_t *
2572pm_block_local_variable_node_create(pm_parser_t *parser, const pm_token_t *name) {
2573 pm_block_local_variable_node_t *node = PM_NODE_ALLOC(parser, pm_block_local_variable_node_t);
2575 *node = (pm_block_local_variable_node_t) {
2577 .type = PM_BLOCK_LOCAL_VARIABLE_NODE,
2578 .node_id = PM_NODE_IDENTIFY(parser),
2579 .location = PM_LOCATION_TOKEN_VALUE(name),
2581 .name = pm_parser_constant_id_token(parser, name)
2591pm_block_parameters_node_append_local(pm_block_parameters_node_t *node, const pm_block_local_variable_node_t *local) {
2592 pm_node_list_append(&node->locals, (pm_node_t *) local);
2594 if (node->base.location.start == NULL) node->base.location.start = local->base.location.start;
2595 node->base.location.end = local->base.location.end;
2601static pm_break_node_t *
2602pm_break_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
2603 assert(keyword->type == PM_TOKEN_KEYWORD_BREAK);
2604 pm_break_node_t *node = PM_NODE_ALLOC(parser, pm_break_node_t);
2606 *node = (pm_break_node_t) {
2608 .type = PM_BREAK_NODE,
2609 .node_id = PM_NODE_IDENTIFY(parser),
2611 .start = keyword->start,
2612 .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
2615 .arguments = arguments,
2616 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
2622// There are certain flags that we want to use internally but don't want to
2623// expose because they are not relevant beyond parsing. Therefore we'll define
2624// them here and not define them in config.yml/a header file.
2625static const pm_node_flags_t PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY = 0x4;
2626static const pm_node_flags_t PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY = 0x40;
2627static const pm_node_flags_t PM_CALL_NODE_FLAGS_COMPARISON = 0x80;
2628static const pm_node_flags_t PM_CALL_NODE_FLAGS_INDEX = 0x100;
2635static pm_call_node_t *
2636pm_call_node_create(pm_parser_t *parser, pm_node_flags_t flags) {
2637 pm_call_node_t *node = PM_NODE_ALLOC(parser, pm_call_node_t);
2639 *node = (pm_call_node_t) {
2641 .type = PM_CALL_NODE,
2643 .node_id = PM_NODE_IDENTIFY(parser),
2644 .location = PM_LOCATION_NULL_VALUE(parser),
2647 .call_operator_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2648 .message_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2649 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2651 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2663static inline pm_node_flags_t
2664pm_call_node_ignore_visibility_flag(const pm_node_t *receiver) {
2665 return PM_NODE_TYPE_P(receiver, PM_SELF_NODE) ? PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY : 0;
2672static pm_call_node_t *
2673pm_call_node_aref_create(pm_parser_t *parser, pm_node_t *receiver, pm_arguments_t *arguments) {
2674 pm_assert_value_expression(parser, receiver);
2676 pm_node_flags_t flags = pm_call_node_ignore_visibility_flag(receiver);
2677 if (arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_ARGUMENT_NODE)) {
2678 flags |= PM_CALL_NODE_FLAGS_INDEX;
2681 pm_call_node_t *node = pm_call_node_create(parser, flags);
2683 node->base.location.start = receiver->location.start;
2684 node->base.location.end = pm_arguments_end(arguments);
2686 node->receiver = receiver;
2687 node->message_loc.start = arguments->opening_loc.start;
2688 node->message_loc.end = arguments->closing_loc.end;
2690 node->opening_loc = arguments->opening_loc;
2691 node->arguments = arguments->arguments;
2692 node->closing_loc = arguments->closing_loc;
2693 node->block = arguments->block;
2695 node->name = pm_parser_constant_id_constant(parser, "[]", 2);
2702static pm_call_node_t *
2703pm_call_node_binary_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_node_t *argument, pm_node_flags_t flags) {
2704 pm_assert_value_expression(parser, receiver);
2705 pm_assert_value_expression(parser, argument);
2707 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver) | flags);
2709 node->base.location.start = MIN(receiver->location.start, argument->location.start);
2710 node->base.location.end = MAX(receiver->location.end, argument->location.end);
2712 node->receiver = receiver;
2713 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2715 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
2716 pm_arguments_node_arguments_append(arguments, argument);
2717 node->arguments = arguments;
2719 node->name = pm_parser_constant_id_token(parser, operator);
2726static pm_call_node_t *
2727pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_token_t *message, pm_arguments_t *arguments) {
2728 pm_assert_value_expression(parser, receiver);
2730 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2732 node->base.location.start = receiver->location.start;
2733 const uint8_t *end = pm_arguments_end(arguments);
2737 node->base.location.end = end;
2739 node->receiver = receiver;
2740 node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2741 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2742 node->opening_loc = arguments->opening_loc;
2743 node->arguments = arguments->arguments;
2744 node->closing_loc = arguments->closing_loc;
2745 node->block = arguments->block;
2747 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2748 pm_node_flag_set((pm_node_t *)node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2751 node->name = pm_parser_constant_id_token(parser, message);
2758static pm_call_node_t *
2759pm_call_node_call_synthesized_create(pm_parser_t *parser, pm_node_t *receiver, const char *message, pm_arguments_node_t *arguments) {
2760 pm_call_node_t *node = pm_call_node_create(parser, 0);
2761 node->base.location.start = parser->start;
2762 node->base.location.end = parser->end;
2764 node->receiver = receiver;
2765 node->call_operator_loc = (pm_location_t) { .start = NULL, .end = NULL };
2766 node->message_loc = (pm_location_t) { .start = NULL, .end = NULL };
2767 node->arguments = arguments;
2769 node->name = pm_parser_constant_id_constant(parser, message, strlen(message));
2777static pm_call_node_t *
2778pm_call_node_fcall_create(pm_parser_t *parser, pm_token_t *message, pm_arguments_t *arguments) {
2779 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2781 node->base.location.start = message->start;
2782 node->base.location.end = pm_arguments_end(arguments);
2784 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2785 node->opening_loc = arguments->opening_loc;
2786 node->arguments = arguments->arguments;
2787 node->closing_loc = arguments->closing_loc;
2788 node->block = arguments->block;
2790 node->name = pm_parser_constant_id_token(parser, message);
2798static pm_call_node_t *
2799pm_call_node_fcall_synthesized_create(pm_parser_t *parser, pm_arguments_node_t *arguments, pm_constant_id_t name) {
2800 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2802 node->base.location = PM_LOCATION_NULL_VALUE(parser);
2803 node->arguments = arguments;
2812static pm_call_node_t *
2813pm_call_node_not_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *message, pm_arguments_t *arguments) {
2814 pm_assert_value_expression(parser, receiver);
2815 if (receiver != NULL) pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
2817 pm_call_node_t *node = pm_call_node_create(parser, receiver == NULL ? 0 : pm_call_node_ignore_visibility_flag(receiver));
2819 node->base.location.start = message->start;
2820 if (arguments->closing_loc.start != NULL) {
2821 node->base.location.end = arguments->closing_loc.end;
2823 assert(receiver != NULL);
2824 node->base.location.end = receiver->location.end;
2827 node->receiver = receiver;
2828 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2829 node->opening_loc = arguments->opening_loc;
2830 node->arguments = arguments->arguments;
2831 node->closing_loc = arguments->closing_loc;
2833 node->name = pm_parser_constant_id_constant(parser, "!", 1);
2840static pm_call_node_t *
2841pm_call_node_shorthand_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_arguments_t *arguments) {
2842 pm_assert_value_expression(parser, receiver);
2844 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2846 node->base.location.start = receiver->location.start;
2847 node->base.location.end = pm_arguments_end(arguments);
2849 node->receiver = receiver;
2850 node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2851 node->opening_loc = arguments->opening_loc;
2852 node->arguments = arguments->arguments;
2853 node->closing_loc = arguments->closing_loc;
2854 node->block = arguments->block;
2856 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2857 pm_node_flag_set((pm_node_t *)node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2860 node->name = pm_parser_constant_id_constant(parser, "call", 4);
2867static pm_call_node_t *
2868pm_call_node_unary_create(pm_parser_t *parser, pm_token_t *operator, pm_node_t *receiver, const char *name) {
2869 pm_assert_value_expression(parser, receiver);
2871 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2873 node->base.location.start = operator->start;
2874 node->base.location.end = receiver->location.end;
2876 node->receiver = receiver;
2877 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2879 node->name = pm_parser_constant_id_constant(parser, name, strlen(name));
2887static pm_call_node_t *
2888pm_call_node_variable_call_create(pm_parser_t *parser, pm_token_t *message) {
2889 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2891 node->base.location = PM_LOCATION_TOKEN_VALUE(message);
2892 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2894 node->name = pm_parser_constant_id_token(parser, message);
2903pm_call_node_writable_p(const pm_parser_t *parser, const pm_call_node_t *node) {
2905 (node->message_loc.start != NULL) &&
2906 (node->message_loc.end[-1] != '!') &&
2907 (node->message_loc.end[-1] != '?') &&
2908 char_is_identifier_start(parser, node->message_loc.start, parser->end - node->message_loc.start) &&
2909 (node->opening_loc.start == NULL) &&
2910 (node->arguments == NULL) &&
2911 (node->block == NULL)
2919pm_call_write_read_name_init(pm_parser_t *parser, pm_constant_id_t *read_name, pm_constant_id_t *write_name) {
2920 pm_constant_t *write_constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *write_name);
2922 if (write_constant->length > 0) {
2923 size_t length = write_constant->length - 1;
2925 void *memory = xmalloc(length);
2926 memcpy(memory, write_constant->start, length);
2928 *read_name = pm_constant_pool_insert_owned(&parser->constant_pool, (uint8_t *) memory, length);
2930 // We can get here if the message was missing because of a syntax error.
2931 *read_name = pm_parser_constant_id_constant(parser, "", 0);
2938static pm_call_and_write_node_t *
2939pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2940 assert(target->block == NULL);
2941 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
2942 pm_call_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_and_write_node_t);
2944 *node = (pm_call_and_write_node_t) {
2946 .type = PM_CALL_AND_WRITE_NODE,
2947 .flags = target->base.flags,
2948 .node_id = PM_NODE_IDENTIFY(parser),
2950 .start = target->base.location.start,
2951 .end = value->location.end
2954 .receiver = target->receiver,
2955 .call_operator_loc = target->call_operator_loc,
2956 .message_loc = target->message_loc,
2958 .write_name = target->name,
2959 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2963 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
2965 // Here we're going to free the target, since it is no longer necessary.
2966 // However, we don't want to call `pm_node_destroy` because we want to keep
2967 // around all of its children since we just reused them.
2978pm_index_arguments_check(pm_parser_t *parser, const pm_arguments_node_t *arguments, const pm_node_t *block) {
2979 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) {
2980 if (arguments != NULL && PM_NODE_FLAG_P(arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) {
2982 PM_NODE_LIST_FOREACH(&arguments->arguments, index, node) {
2983 if (PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE)) {
2984 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_INDEX_KEYWORDS);
2990 if (block != NULL) {
2991 pm_parser_err_node(parser, block, PM_ERR_UNEXPECTED_INDEX_BLOCK);
2999static pm_index_and_write_node_t *
3000pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3001 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3002 pm_index_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_and_write_node_t);
3004 pm_index_arguments_check(parser, target->arguments, target->block);
3006 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3007 *node = (pm_index_and_write_node_t) {
3009 .type = PM_INDEX_AND_WRITE_NODE,
3010 .flags = target->base.flags,
3011 .node_id = PM_NODE_IDENTIFY(parser),
3013 .start = target->base.location.start,
3014 .end = value->location.end
3017 .receiver = target->receiver,
3018 .call_operator_loc = target->call_operator_loc,
3019 .opening_loc = target->opening_loc,
3020 .arguments = target->arguments,
3021 .closing_loc = target->closing_loc,
3022 .block = (pm_block_argument_node_t *) target->block,
3023 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3027 // Here we're going to free the target, since it is no longer necessary.
3028 // However, we don't want to call `pm_node_destroy` because we want to keep
3029 // around all of its children since we just reused them.
3038static pm_call_operator_write_node_t *
3039pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3040 assert(target->block == NULL);
3041 pm_call_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_operator_write_node_t);
3043 *node = (pm_call_operator_write_node_t) {
3045 .type = PM_CALL_OPERATOR_WRITE_NODE,
3046 .flags = target->base.flags,
3047 .node_id = PM_NODE_IDENTIFY(parser),
3049 .start = target->base.location.start,
3050 .end = value->location.end
3053 .receiver = target->receiver,
3054 .call_operator_loc = target->call_operator_loc,
3055 .message_loc = target->message_loc,
3057 .write_name = target->name,
3058 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
3059 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3063 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3065 // Here we're going to free the target, since it is no longer necessary.
3066 // However, we don't want to call `pm_node_destroy` because we want to keep
3067 // around all of its children since we just reused them.
3076static pm_index_operator_write_node_t *
3077pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3078 pm_index_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_operator_write_node_t);
3080 pm_index_arguments_check(parser, target->arguments, target->block);
3082 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3083 *node = (pm_index_operator_write_node_t) {
3085 .type = PM_INDEX_OPERATOR_WRITE_NODE,
3086 .flags = target->base.flags,
3087 .node_id = PM_NODE_IDENTIFY(parser),
3089 .start = target->base.location.start,
3090 .end = value->location.end
3093 .receiver = target->receiver,
3094 .call_operator_loc = target->call_operator_loc,
3095 .opening_loc = target->opening_loc,
3096 .arguments = target->arguments,
3097 .closing_loc = target->closing_loc,
3098 .block = (pm_block_argument_node_t *) target->block,
3099 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
3100 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3104 // Here we're going to free the target, since it is no longer necessary.
3105 // However, we don't want to call `pm_node_destroy` because we want to keep
3106 // around all of its children since we just reused them.
3115static pm_call_or_write_node_t *
3116pm_call_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3117 assert(target->block == NULL);
3118 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3119 pm_call_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_or_write_node_t);
3121 *node = (pm_call_or_write_node_t) {
3123 .type = PM_CALL_OR_WRITE_NODE,
3124 .flags = target->base.flags,
3125 .node_id = PM_NODE_IDENTIFY(parser),
3127 .start = target->base.location.start,
3128 .end = value->location.end
3131 .receiver = target->receiver,
3132 .call_operator_loc = target->call_operator_loc,
3133 .message_loc = target->message_loc,
3135 .write_name = target->name,
3136 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3140 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3142 // Here we're going to free the target, since it is no longer necessary.
3143 // However, we don't want to call `pm_node_destroy` because we want to keep
3144 // around all of its children since we just reused them.
3153static pm_index_or_write_node_t *
3154pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3155 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3156 pm_index_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_or_write_node_t);
3158 pm_index_arguments_check(parser, target->arguments, target->block);
3160 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3161 *node = (pm_index_or_write_node_t) {
3163 .type = PM_INDEX_OR_WRITE_NODE,
3164 .flags = target->base.flags,
3165 .node_id = PM_NODE_IDENTIFY(parser),
3167 .start = target->base.location.start,
3168 .end = value->location.end
3171 .receiver = target->receiver,
3172 .call_operator_loc = target->call_operator_loc,
3173 .opening_loc = target->opening_loc,
3174 .arguments = target->arguments,
3175 .closing_loc = target->closing_loc,
3176 .block = (pm_block_argument_node_t *) target->block,
3177 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3181 // Here we're going to free the target, since it is no longer necessary.
3182 // However, we don't want to call `pm_node_destroy` because we want to keep
3183 // around all of its children since we just reused them.
3193static pm_call_target_node_t *
3194pm_call_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3195 pm_call_target_node_t *node = PM_NODE_ALLOC(parser, pm_call_target_node_t);
3197 *node = (pm_call_target_node_t) {
3199 .type = PM_CALL_TARGET_NODE,
3200 .flags = target->base.flags,
3201 .node_id = PM_NODE_IDENTIFY(parser),
3202 .location = target->base.location
3204 .receiver = target->receiver,
3205 .call_operator_loc = target->call_operator_loc,
3206 .name = target->name,
3207 .message_loc = target->message_loc
3210 // Here we're going to free the target, since it is no longer necessary.
3211 // However, we don't want to call `pm_node_destroy` because we want to keep
3212 // around all of its children since we just reused them.
3222static pm_index_target_node_t *
3223pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3224 pm_index_target_node_t *node = PM_NODE_ALLOC(parser, pm_index_target_node_t);
3225 pm_node_flags_t flags = target->base.flags;
3227 pm_index_arguments_check(parser, target->arguments, target->block);
3229 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3230 *node = (pm_index_target_node_t) {
3232 .type = PM_INDEX_TARGET_NODE,
3233 .flags = flags | PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE,
3234 .node_id = PM_NODE_IDENTIFY(parser),
3235 .location = target->base.location
3237 .receiver = target->receiver,
3238 .opening_loc = target->opening_loc,
3239 .arguments = target->arguments,
3240 .closing_loc = target->closing_loc,
3241 .block = (pm_block_argument_node_t *) target->block,
3244 // Here we're going to free the target, since it is no longer necessary.
3245 // However, we don't want to call `pm_node_destroy` because we want to keep
3246 // around all of its children since we just reused them.
3255static pm_capture_pattern_node_t *
3256pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_local_variable_target_node_t *target, const pm_token_t *operator) {
3257 pm_capture_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_capture_pattern_node_t);
3259 *node = (pm_capture_pattern_node_t) {
3261 .type = PM_CAPTURE_PATTERN_NODE,
3262 .node_id = PM_NODE_IDENTIFY(parser),
3264 .start = value->location.start,
3265 .end = target->base.location.end
3270 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
3279static pm_case_node_t *
3280pm_case_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3281 pm_case_node_t *node = PM_NODE_ALLOC(parser, pm_case_node_t);
3283 *node = (pm_case_node_t) {
3285 .type = PM_CASE_NODE,
3286 .node_id = PM_NODE_IDENTIFY(parser),
3288 .start = case_keyword->start,
3289 .end = end_keyword->end
3292 .predicate = predicate,
3293 .else_clause = NULL,
3294 .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
3295 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3306pm_case_node_condition_append(pm_case_node_t *node, pm_node_t *condition) {
3307 assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
3309 pm_node_list_append(&node->conditions, condition);
3310 node->base.location.end = condition->location.end;
3317pm_case_node_else_clause_set(pm_case_node_t *node, pm_else_node_t *else_clause) {
3318 node->else_clause = else_clause;
3319 node->base.location.end = else_clause->base.location.end;
3326pm_case_node_end_keyword_loc_set(pm_case_node_t *node, const pm_token_t *end_keyword) {
3327 node->base.location.end = end_keyword->end;
3328 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
3334static pm_case_match_node_t *
3335pm_case_match_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3336 pm_case_match_node_t *node = PM_NODE_ALLOC(parser, pm_case_match_node_t);
3338 *node = (pm_case_match_node_t) {
3340 .type = PM_CASE_MATCH_NODE,
3341 .node_id = PM_NODE_IDENTIFY(parser),
3343 .start = case_keyword->start,
3344 .end = end_keyword->end
3347 .predicate = predicate,
3348 .else_clause = NULL,
3349 .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
3350 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3361pm_case_match_node_condition_append(pm_case_match_node_t *node, pm_node_t *condition) {
3362 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
3364 pm_node_list_append(&node->conditions, condition);
3365 node->base.location.end = condition->location.end;
3372pm_case_match_node_else_clause_set(pm_case_match_node_t *node, pm_else_node_t *else_clause) {
3373 node->else_clause = else_clause;
3374 node->base.location.end = else_clause->base.location.end;
3381pm_case_match_node_end_keyword_loc_set(pm_case_match_node_t *node, const pm_token_t *end_keyword) {
3382 node->base.location.end = end_keyword->end;
3383 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
3389static pm_class_node_t *
3390pm_class_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const pm_token_t *class_keyword, pm_node_t *constant_path, const pm_token_t *name, const pm_token_t *inheritance_operator, pm_node_t *superclass, pm_node_t *body, const pm_token_t *end_keyword) {
3391 pm_class_node_t *node = PM_NODE_ALLOC(parser, pm_class_node_t);
3393 *node = (pm_class_node_t) {
3395 .type = PM_CLASS_NODE,
3396 .node_id = PM_NODE_IDENTIFY(parser),
3397 .location = { .start = class_keyword->start, .end = end_keyword->end },
3400 .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
3401 .constant_path = constant_path,
3402 .inheritance_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(inheritance_operator),
3403 .superclass = superclass,
3405 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3406 .name = pm_parser_constant_id_token(parser, name)
3415static pm_class_variable_and_write_node_t *
3416pm_class_variable_and_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3417 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3418 pm_class_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_and_write_node_t);
3420 *node = (pm_class_variable_and_write_node_t) {
3422 .type = PM_CLASS_VARIABLE_AND_WRITE_NODE,
3423 .node_id = PM_NODE_IDENTIFY(parser),
3425 .start = target->base.location.start,
3426 .end = value->location.end
3429 .name = target->name,
3430 .name_loc = target->base.location,
3431 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3441static pm_class_variable_operator_write_node_t *
3442pm_class_variable_operator_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3443 pm_class_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_operator_write_node_t);
3445 *node = (pm_class_variable_operator_write_node_t) {
3447 .type = PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE,
3448 .node_id = PM_NODE_IDENTIFY(parser),
3450 .start = target->base.location.start,
3451 .end = value->location.end
3454 .name = target->name,
3455 .name_loc = target->base.location,
3456 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3458 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3467static pm_class_variable_or_write_node_t *
3468pm_class_variable_or_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3469 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3470 pm_class_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_or_write_node_t);
3472 *node = (pm_class_variable_or_write_node_t) {
3474 .type = PM_CLASS_VARIABLE_OR_WRITE_NODE,
3475 .node_id = PM_NODE_IDENTIFY(parser),
3477 .start = target->base.location.start,
3478 .end = value->location.end
3481 .name = target->name,
3482 .name_loc = target->base.location,
3483 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3493static pm_class_variable_read_node_t *
3494pm_class_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
3495 assert(token->type == PM_TOKEN_CLASS_VARIABLE);
3496 pm_class_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_read_node_t);
3498 *node = (pm_class_variable_read_node_t) {
3500 .type = PM_CLASS_VARIABLE_READ_NODE,
3501 .node_id = PM_NODE_IDENTIFY(parser),
3502 .location = PM_LOCATION_TOKEN_VALUE(token)
3504 .name = pm_parser_constant_id_token(parser, token)
3516static inline pm_node_flags_t
3517pm_implicit_array_write_flags(const pm_node_t *node, pm_node_flags_t flags) {
3518 if (PM_NODE_TYPE_P(node, PM_ARRAY_NODE) && ((const pm_array_node_t *) node)->opening_loc.start == NULL) {
3527static pm_class_variable_write_node_t *
3528pm_class_variable_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *read_node, pm_token_t *operator, pm_node_t *value) {
3529 pm_class_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_write_node_t);
3531 *node = (pm_class_variable_write_node_t) {
3533 .type = PM_CLASS_VARIABLE_WRITE_NODE,
3534 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3535 .node_id = PM_NODE_IDENTIFY(parser),
3537 .start = read_node->base.location.start,
3538 .end = value->location.end
3541 .name = read_node->name,
3542 .name_loc = PM_LOCATION_NODE_VALUE((pm_node_t *) read_node),
3543 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3553static pm_constant_path_and_write_node_t *
3554pm_constant_path_and_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3555 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3556 pm_constant_path_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_and_write_node_t);
3558 *node = (pm_constant_path_and_write_node_t) {
3560 .type = PM_CONSTANT_PATH_AND_WRITE_NODE,
3561 .node_id = PM_NODE_IDENTIFY(parser),
3563 .start = target->base.location.start,
3564 .end = value->location.end
3568 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3578static pm_constant_path_operator_write_node_t *
3579pm_constant_path_operator_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3580 pm_constant_path_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_operator_write_node_t);
3582 *node = (pm_constant_path_operator_write_node_t) {
3584 .type = PM_CONSTANT_PATH_OPERATOR_WRITE_NODE,
3585 .node_id = PM_NODE_IDENTIFY(parser),
3587 .start = target->base.location.start,
3588 .end = value->location.end
3592 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3594 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3603static pm_constant_path_or_write_node_t *
3604pm_constant_path_or_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3605 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3606 pm_constant_path_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_or_write_node_t);
3608 *node = (pm_constant_path_or_write_node_t) {
3610 .type = PM_CONSTANT_PATH_OR_WRITE_NODE,
3611 .node_id = PM_NODE_IDENTIFY(parser),
3613 .start = target->base.location.start,
3614 .end = value->location.end
3618 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3628static pm_constant_path_node_t *
3629pm_constant_path_node_create(pm_parser_t *parser, pm_node_t *parent, const pm_token_t *delimiter, const pm_token_t *name_token) {
3630 pm_assert_value_expression(parser, parent);
3631 pm_constant_path_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_node_t);
3633 pm_constant_id_t name = PM_CONSTANT_ID_UNSET;
3634 if (name_token->type == PM_TOKEN_CONSTANT) {
3635 name = pm_parser_constant_id_token(parser, name_token);
3638 *node = (pm_constant_path_node_t) {
3640 .type = PM_CONSTANT_PATH_NODE,
3641 .node_id = PM_NODE_IDENTIFY(parser),
3643 .start = parent == NULL ? delimiter->start : parent->location.start,
3644 .end = name_token->end
3649 .delimiter_loc = PM_LOCATION_TOKEN_VALUE(delimiter),
3650 .name_loc = PM_LOCATION_TOKEN_VALUE(name_token)
3659static pm_constant_path_write_node_t *
3660pm_constant_path_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3661 pm_constant_path_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_write_node_t);
3663 *node = (pm_constant_path_write_node_t) {
3665 .type = PM_CONSTANT_PATH_WRITE_NODE,
3666 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3667 .node_id = PM_NODE_IDENTIFY(parser),
3669 .start = target->base.location.start,
3670 .end = value->location.end
3674 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3684static pm_constant_and_write_node_t *
3685pm_constant_and_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3686 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3687 pm_constant_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_and_write_node_t);
3689 *node = (pm_constant_and_write_node_t) {
3691 .type = PM_CONSTANT_AND_WRITE_NODE,
3692 .node_id = PM_NODE_IDENTIFY(parser),
3694 .start = target->base.location.start,
3695 .end = value->location.end
3698 .name = target->name,
3699 .name_loc = target->base.location,
3700 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3710static pm_constant_operator_write_node_t *
3711pm_constant_operator_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3712 pm_constant_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_operator_write_node_t);
3714 *node = (pm_constant_operator_write_node_t) {
3716 .type = PM_CONSTANT_OPERATOR_WRITE_NODE,
3717 .node_id = PM_NODE_IDENTIFY(parser),
3719 .start = target->base.location.start,
3720 .end = value->location.end
3723 .name = target->name,
3724 .name_loc = target->base.location,
3725 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3727 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3736static pm_constant_or_write_node_t *
3737pm_constant_or_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3738 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3739 pm_constant_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_or_write_node_t);
3741 *node = (pm_constant_or_write_node_t) {
3743 .type = PM_CONSTANT_OR_WRITE_NODE,
3744 .node_id = PM_NODE_IDENTIFY(parser),
3746 .start = target->base.location.start,
3747 .end = value->location.end
3750 .name = target->name,
3751 .name_loc = target->base.location,
3752 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3762static pm_constant_read_node_t *
3763pm_constant_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
3764 assert(name->type == PM_TOKEN_CONSTANT || name->type == PM_TOKEN_MISSING);
3765 pm_constant_read_node_t *node = PM_NODE_ALLOC(parser, pm_constant_read_node_t);
3767 *node = (pm_constant_read_node_t) {
3769 .type = PM_CONSTANT_READ_NODE,
3770 .node_id = PM_NODE_IDENTIFY(parser),
3771 .location = PM_LOCATION_TOKEN_VALUE(name)
3773 .name = pm_parser_constant_id_token(parser, name)
3782static pm_constant_write_node_t *
3783pm_constant_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3784 pm_constant_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_write_node_t);
3786 *node = (pm_constant_write_node_t) {
3788 .type = PM_CONSTANT_WRITE_NODE,
3789 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3790 .node_id = PM_NODE_IDENTIFY(parser),
3792 .start = target->base.location.start,
3793 .end = value->location.end
3796 .name = target->name,
3797 .name_loc = target->base.location,
3798 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3809pm_def_node_receiver_check(pm_parser_t *parser, const pm_node_t *node) {
3810 switch (PM_NODE_TYPE(node)) {
3811 case PM_BEGIN_NODE: {
3812 const pm_begin_node_t *cast = (pm_begin_node_t *) node;
3813 if (cast->statements != NULL) pm_def_node_receiver_check(parser, (pm_node_t *) cast->statements);
3816 case PM_PARENTHESES_NODE: {
3817 const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node;
3818 if (cast->body != NULL) pm_def_node_receiver_check(parser, cast->body);
3821 case PM_STATEMENTS_NODE: {
3822 const pm_statements_node_t *cast = (const pm_statements_node_t *) node;
3823 pm_def_node_receiver_check(parser, cast->body.nodes[cast->body.size - 1]);
3828 case PM_IMAGINARY_NODE:
3829 case PM_INTEGER_NODE:
3830 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
3831 case PM_INTERPOLATED_STRING_NODE:
3832 case PM_INTERPOLATED_SYMBOL_NODE:
3833 case PM_INTERPOLATED_X_STRING_NODE:
3834 case PM_RATIONAL_NODE:
3835 case PM_REGULAR_EXPRESSION_NODE:
3836 case PM_SOURCE_ENCODING_NODE:
3837 case PM_SOURCE_FILE_NODE:
3838 case PM_SOURCE_LINE_NODE:
3839 case PM_STRING_NODE:
3840 case PM_SYMBOL_NODE:
3841 case PM_X_STRING_NODE:
3842 pm_parser_err_node(parser, node, PM_ERR_SINGLETON_FOR_LITERALS);
3852static pm_def_node_t *
3854 pm_parser_t *parser,
3855 pm_constant_id_t name,
3856 const pm_token_t *name_loc,
3857 pm_node_t *receiver,
3858 pm_parameters_node_t *parameters,
3860 pm_constant_id_list_t *locals,
3861 const pm_token_t *def_keyword,
3862 const pm_token_t *operator,
3863 const pm_token_t *lparen,
3864 const pm_token_t *rparen,
3865 const pm_token_t *equal,
3866 const pm_token_t *end_keyword
3868 pm_def_node_t *node = PM_NODE_ALLOC(parser, pm_def_node_t);
3871 if (end_keyword->type == PM_TOKEN_NOT_PROVIDED) {
3872 end = body->location.end;
3874 end = end_keyword->end;
3877 if (receiver != NULL) {
3878 pm_def_node_receiver_check(parser, receiver);
3881 *node = (pm_def_node_t) {
3883 .type = PM_DEF_NODE,
3884 .node_id = PM_NODE_IDENTIFY(parser),
3885 .location = { .start = def_keyword->start, .end = end },
3888 .name_loc = PM_LOCATION_TOKEN_VALUE(name_loc),
3889 .receiver = receiver,
3890 .parameters = parameters,
3893 .def_keyword_loc = PM_LOCATION_TOKEN_VALUE(def_keyword),
3894 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3895 .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
3896 .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
3897 .equal_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(equal),
3898 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
3907static pm_defined_node_t *
3908pm_defined_node_create(pm_parser_t *parser, const pm_token_t *lparen, pm_node_t *value, const pm_token_t *rparen, const pm_location_t *keyword_loc) {
3909 pm_defined_node_t *node = PM_NODE_ALLOC(parser, pm_defined_node_t);
3911 *node = (pm_defined_node_t) {
3913 .type = PM_DEFINED_NODE,
3914 .node_id = PM_NODE_IDENTIFY(parser),
3916 .start = keyword_loc->start,
3917 .end = (rparen->type == PM_TOKEN_NOT_PROVIDED ? value->location.end : rparen->end)
3920 .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
3922 .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
3923 .keyword_loc = *keyword_loc
3932static pm_else_node_t *
3933pm_else_node_create(pm_parser_t *parser, const pm_token_t *else_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
3934 pm_else_node_t *node = PM_NODE_ALLOC(parser, pm_else_node_t);
3935 const uint8_t *end = NULL;
3936 if ((end_keyword->type == PM_TOKEN_NOT_PROVIDED) && (statements != NULL)) {
3937 end = statements->base.location.end;
3939 end = end_keyword->end;
3942 *node = (pm_else_node_t) {
3944 .type = PM_ELSE_NODE,
3945 .node_id = PM_NODE_IDENTIFY(parser),
3947 .start = else_keyword->start,
3951 .else_keyword_loc = PM_LOCATION_TOKEN_VALUE(else_keyword),
3952 .statements = statements,
3953 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
3962static pm_embedded_statements_node_t *
3963pm_embedded_statements_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
3964 pm_embedded_statements_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_statements_node_t);
3966 *node = (pm_embedded_statements_node_t) {
3968 .type = PM_EMBEDDED_STATEMENTS_NODE,
3969 .node_id = PM_NODE_IDENTIFY(parser),
3971 .start = opening->start,
3975 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
3976 .statements = statements,
3977 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
3986static pm_embedded_variable_node_t *
3987pm_embedded_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
3988 pm_embedded_variable_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_variable_node_t);
3990 *node = (pm_embedded_variable_node_t) {
3992 .type = PM_EMBEDDED_VARIABLE_NODE,
3993 .node_id = PM_NODE_IDENTIFY(parser),
3995 .start = operator->start,
3996 .end = variable->location.end
3999 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4000 .variable = variable
4009static pm_ensure_node_t *
4010pm_ensure_node_create(pm_parser_t *parser, const pm_token_t *ensure_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
4011 pm_ensure_node_t *node = PM_NODE_ALLOC(parser, pm_ensure_node_t);
4013 *node = (pm_ensure_node_t) {
4015 .type = PM_ENSURE_NODE,
4016 .node_id = PM_NODE_IDENTIFY(parser),
4018 .start = ensure_keyword->start,
4019 .end = end_keyword->end
4022 .ensure_keyword_loc = PM_LOCATION_TOKEN_VALUE(ensure_keyword),
4023 .statements = statements,
4024 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
4033static pm_false_node_t *
4034pm_false_node_create(pm_parser_t *parser, const pm_token_t *token) {
4035 assert(token->type == PM_TOKEN_KEYWORD_FALSE);
4036 pm_false_node_t *node = PM_NODE_ALLOC(parser, pm_false_node_t);
4038 *node = (pm_false_node_t) {{
4039 .type = PM_FALSE_NODE,
4040 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4041 .node_id = PM_NODE_IDENTIFY(parser),
4042 .location = PM_LOCATION_TOKEN_VALUE(token)
4052static pm_find_pattern_node_t *
4053pm_find_pattern_node_create(pm_parser_t *parser, pm_node_list_t *nodes) {
4054 pm_find_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_find_pattern_node_t);
4056 pm_node_t *left = nodes->nodes[0];
4057 assert(PM_NODE_TYPE_P(left, PM_SPLAT_NODE));
4058 pm_splat_node_t *left_splat_node = (pm_splat_node_t *) left;
4062 if (nodes->size == 1) {
4063 right = (pm_node_t *) pm_missing_node_create(parser, left->location.end, left->location.end);
4065 right = nodes->nodes[nodes->size - 1];
4066 assert(PM_NODE_TYPE_P(right, PM_SPLAT_NODE));
4069#if PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS
4070 // FindPatternNode#right is typed as SplatNode in this case, so replace the potential MissingNode with a SplatNode.
4071 // The resulting AST will anyway be ignored, but this file still needs to compile.
4072 pm_splat_node_t *right_splat_node = PM_NODE_TYPE_P(right, PM_SPLAT_NODE) ? (pm_splat_node_t *) right : left_splat_node;
4074 pm_node_t *right_splat_node = right;
4076 *node = (pm_find_pattern_node_t) {
4078 .type = PM_FIND_PATTERN_NODE,
4079 .node_id = PM_NODE_IDENTIFY(parser),
4081 .start = left->location.start,
4082 .end = right->location.end,
4086 .left = left_splat_node,
4087 .right = right_splat_node,
4089 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4090 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4093 // For now we're going to just copy over each pointer manually. This could be
4094 // much more efficient, as we could instead resize the node list to only point
4096 for (size_t index = 1; index < nodes->size - 1; index++) {
4097 pm_node_list_append(&node->requireds, nodes->nodes[index]);
4108pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
4109 ptrdiff_t diff = token->end - token->start;
4110 if (diff <= 0) return 0.0;
4112 // First, get a buffer of the content.
4113 size_t length = (size_t) diff;
4114 char *buffer = xmalloc(sizeof(char) * (length + 1));
4115 memcpy((void *) buffer, token->start, length);
4117 // Next, determine if we need to replace the decimal point because of
4118 // locale-specific options, and then normalize them if we have to.
4119 char decimal_point = *localeconv()->decimal_point;
4120 if (decimal_point != '.') {
4121 for (size_t index = 0; index < length; index++) {
4122 if (buffer[index] == '.') buffer[index] = decimal_point;
4126 // Next, handle underscores by removing them from the buffer.
4127 for (size_t index = 0; index < length; index++) {
4128 if (buffer[index] == '_') {
4129 memmove((void *) (buffer + index), (void *) (buffer + index + 1), length - index);
4134 // Null-terminate the buffer so that strtod cannot read off the end.
4135 buffer[length] = '\0';
4137 // Now, call strtod to parse the value. Note that CRuby has their own
4138 // version of strtod which avoids locales. We're okay using the locale-aware
4139 // version because we've already validated through the parser that the token
4140 // is in a valid format.
4143 double value = strtod(buffer, &eptr);
4145 // This should never happen, because we've already checked that the token
4146 // is in a valid format. However it's good to be safe.
4147 if ((eptr != buffer + length) || (errno != 0 && errno != ERANGE)) {
4148 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, (*token), PM_ERR_FLOAT_PARSE);
4149 xfree((void *) buffer);
4153 // If errno is set, then it should only be ERANGE. At this point we need to
4154 // check if it's infinity (it should be).
4155 if (errno == ERANGE && PRISM_ISINF(value)) {
4157 const char *ellipsis;
4163 warn_width = (int) length;
4167 pm_diagnostic_list_append_format(&parser->warning_list, token->start, token->end, PM_WARN_FLOAT_OUT_OF_RANGE, warn_width, (const char *) token->start, ellipsis);
4168 value = (value < 0.0) ? -HUGE_VAL : HUGE_VAL;
4171 // Finally we can free the buffer and return the value.
4172 xfree((void *) buffer);
4179static pm_float_node_t *
4180pm_float_node_create(pm_parser_t *parser, const pm_token_t *token) {
4181 assert(token->type == PM_TOKEN_FLOAT);
4182 pm_float_node_t *node = PM_NODE_ALLOC(parser, pm_float_node_t);
4184 *node = (pm_float_node_t) {
4186 .type = PM_FLOAT_NODE,
4187 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4188 .node_id = PM_NODE_IDENTIFY(parser),
4189 .location = PM_LOCATION_TOKEN_VALUE(token)
4191 .value = pm_double_parse(parser, token)
4200static pm_imaginary_node_t *
4201pm_float_node_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4202 assert(token->type == PM_TOKEN_FLOAT_IMAGINARY);
4204 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4205 *node = (pm_imaginary_node_t) {
4207 .type = PM_IMAGINARY_NODE,
4208 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4209 .node_id = PM_NODE_IDENTIFY(parser),
4210 .location = PM_LOCATION_TOKEN_VALUE(token)
4212 .numeric = (pm_node_t *) pm_float_node_create(parser, &((pm_token_t) {
4213 .type = PM_TOKEN_FLOAT,
4214 .start = token->start,
4215 .end = token->end - 1
4225static pm_rational_node_t *
4226pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
4227 assert(token->type == PM_TOKEN_FLOAT_RATIONAL);
4229 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
4230 *node = (pm_rational_node_t) {
4232 .type = PM_RATIONAL_NODE,
4233 .flags = PM_INTEGER_BASE_FLAGS_DECIMAL | PM_NODE_FLAG_STATIC_LITERAL,
4234 .node_id = PM_NODE_IDENTIFY(parser),
4235 .location = PM_LOCATION_TOKEN_VALUE(token)
4238 .denominator = { 0 }
4241 const uint8_t *start = token->start;
4242 const uint8_t *end = token->end - 1; // r
4244 while (start < end && *start == '0') start++; // 0.1 -> .1
4245 while (end > start && end[-1] == '0') end--; // 1.0 -> 1.
4247 size_t length = (size_t) (end - start);
4249 node->denominator.value = 1;
4253 const uint8_t *point = memchr(start, '.', length);
4254 assert(point && "should have a decimal point");
4256 uint8_t *digits = xmalloc(length);
4257 if (digits == NULL) {
4258 fputs("[pm_float_node_rational_create] Failed to allocate memory", stderr);
4262 memcpy(digits, start, (unsigned long) (point - start));
4263 memcpy(digits + (point - start), point + 1, (unsigned long) (end - point - 1));
4264 pm_integer_parse(&node->numerator, PM_INTEGER_BASE_DEFAULT, digits, digits + length - 1);
4267 if (end - point > 1) memset(digits + 1, '0', (size_t) (end - point - 1));
4268 pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + (end - point));
4271 pm_integers_reduce(&node->numerator, &node->denominator);
4279static pm_imaginary_node_t *
4280pm_float_node_rational_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4281 assert(token->type == PM_TOKEN_FLOAT_RATIONAL_IMAGINARY);
4283 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4284 *node = (pm_imaginary_node_t) {
4286 .type = PM_IMAGINARY_NODE,
4287 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4288 .node_id = PM_NODE_IDENTIFY(parser),
4289 .location = PM_LOCATION_TOKEN_VALUE(token)
4291 .numeric = (pm_node_t *) pm_float_node_rational_create(parser, &((pm_token_t) {
4292 .type = PM_TOKEN_FLOAT_RATIONAL,
4293 .start = token->start,
4294 .end = token->end - 1
4304static pm_for_node_t *
4306 pm_parser_t *parser,
4308 pm_node_t *collection,
4309 pm_statements_node_t *statements,
4310 const pm_token_t *for_keyword,
4311 const pm_token_t *in_keyword,
4312 const pm_token_t *do_keyword,
4313 const pm_token_t *end_keyword
4315 pm_for_node_t *node = PM_NODE_ALLOC(parser, pm_for_node_t);
4317 *node = (pm_for_node_t) {
4319 .type = PM_FOR_NODE,
4320 .node_id = PM_NODE_IDENTIFY(parser),
4322 .start = for_keyword->start,
4323 .end = end_keyword->end
4327 .collection = collection,
4328 .statements = statements,
4329 .for_keyword_loc = PM_LOCATION_TOKEN_VALUE(for_keyword),
4330 .in_keyword_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
4331 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
4332 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
4341static pm_forwarding_arguments_node_t *
4342pm_forwarding_arguments_node_create(pm_parser_t *parser, const pm_token_t *token) {
4343 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4344 pm_forwarding_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_arguments_node_t);
4346 *node = (pm_forwarding_arguments_node_t) {{
4347 .type = PM_FORWARDING_ARGUMENTS_NODE,
4348 .node_id = PM_NODE_IDENTIFY(parser),
4349 .location = PM_LOCATION_TOKEN_VALUE(token)
4358static pm_forwarding_parameter_node_t *
4359pm_forwarding_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
4360 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4361 pm_forwarding_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_parameter_node_t);
4363 *node = (pm_forwarding_parameter_node_t) {{
4364 .type = PM_FORWARDING_PARAMETER_NODE,
4365 .node_id = PM_NODE_IDENTIFY(parser),
4366 .location = PM_LOCATION_TOKEN_VALUE(token)
4375static pm_forwarding_super_node_t *
4376pm_forwarding_super_node_create(pm_parser_t *parser, const pm_token_t *token, pm_arguments_t *arguments) {
4377 assert(arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_NODE));
4378 assert(token->type == PM_TOKEN_KEYWORD_SUPER);
4379 pm_forwarding_super_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_super_node_t);
4381 pm_block_node_t *block = NULL;
4382 if (arguments->block != NULL) {
4383 block = (pm_block_node_t *) arguments->block;
4386 *node = (pm_forwarding_super_node_t) {
4388 .type = PM_FORWARDING_SUPER_NODE,
4389 .node_id = PM_NODE_IDENTIFY(parser),
4391 .start = token->start,
4392 .end = block != NULL ? block->base.location.end : token->end
4405static pm_hash_pattern_node_t *
4406pm_hash_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4407 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4409 *node = (pm_hash_pattern_node_t) {
4411 .type = PM_HASH_PATTERN_NODE,
4412 .node_id = PM_NODE_IDENTIFY(parser),
4414 .start = opening->start,
4419 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4420 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
4431static pm_hash_pattern_node_t *
4432pm_hash_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *elements, pm_node_t *rest) {
4433 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4435 const uint8_t *start;
4438 if (elements->size > 0) {
4440 start = elements->nodes[0]->location.start;
4441 end = rest->location.end;
4443 start = elements->nodes[0]->location.start;
4444 end = elements->nodes[elements->size - 1]->location.end;
4447 assert(rest != NULL);
4448 start = rest->location.start;
4449 end = rest->location.end;
4452 *node = (pm_hash_pattern_node_t) {
4454 .type = PM_HASH_PATTERN_NODE,
4455 .node_id = PM_NODE_IDENTIFY(parser),
4464 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4465 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4469 PM_NODE_LIST_FOREACH(elements, index, element) {
4470 pm_node_list_append(&node->elements, element);
4479static pm_constant_id_t
4480pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
4481 switch (PM_NODE_TYPE(target)) {
4482 case PM_GLOBAL_VARIABLE_READ_NODE:
4483 return ((pm_global_variable_read_node_t *) target)->name;
4484 case PM_BACK_REFERENCE_READ_NODE:
4485 return ((pm_back_reference_read_node_t *) target)->name;
4486 case PM_NUMBERED_REFERENCE_READ_NODE:
4487 // This will only ever happen in the event of a syntax error, but we
4488 // still need to provide something for the node.
4489 return pm_parser_constant_id_location(parser, target->location.start, target->location.end);
4491 assert(false && "unreachable");
4492 return (pm_constant_id_t) -1;
4499static pm_global_variable_and_write_node_t *
4500pm_global_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4501 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4502 pm_global_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_and_write_node_t);
4504 *node = (pm_global_variable_and_write_node_t) {
4506 .type = PM_GLOBAL_VARIABLE_AND_WRITE_NODE,
4507 .node_id = PM_NODE_IDENTIFY(parser),
4509 .start = target->location.start,
4510 .end = value->location.end
4513 .name = pm_global_variable_write_name(parser, target),
4514 .name_loc = target->location,
4515 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4525static pm_global_variable_operator_write_node_t *
4526pm_global_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4527 pm_global_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_operator_write_node_t);
4529 *node = (pm_global_variable_operator_write_node_t) {
4531 .type = PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE,
4532 .node_id = PM_NODE_IDENTIFY(parser),
4534 .start = target->location.start,
4535 .end = value->location.end
4538 .name = pm_global_variable_write_name(parser, target),
4539 .name_loc = target->location,
4540 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4542 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
4551static pm_global_variable_or_write_node_t *
4552pm_global_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4553 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4554 pm_global_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_or_write_node_t);
4556 *node = (pm_global_variable_or_write_node_t) {
4558 .type = PM_GLOBAL_VARIABLE_OR_WRITE_NODE,
4559 .node_id = PM_NODE_IDENTIFY(parser),
4561 .start = target->location.start,
4562 .end = value->location.end
4565 .name = pm_global_variable_write_name(parser, target),
4566 .name_loc = target->location,
4567 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4577static pm_global_variable_read_node_t *
4578pm_global_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
4579 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4581 *node = (pm_global_variable_read_node_t) {
4583 .type = PM_GLOBAL_VARIABLE_READ_NODE,
4584 .node_id = PM_NODE_IDENTIFY(parser),
4585 .location = PM_LOCATION_TOKEN_VALUE(name),
4587 .name = pm_parser_constant_id_token(parser, name)
4596static pm_global_variable_read_node_t *
4597pm_global_variable_read_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name) {
4598 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4600 *node = (pm_global_variable_read_node_t) {
4602 .type = PM_GLOBAL_VARIABLE_READ_NODE,
4603 .node_id = PM_NODE_IDENTIFY(parser),
4604 .location = PM_LOCATION_NULL_VALUE(parser)
4615static pm_global_variable_write_node_t *
4616pm_global_variable_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4617 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4619 *node = (pm_global_variable_write_node_t) {
4621 .type = PM_GLOBAL_VARIABLE_WRITE_NODE,
4622 .node_id = PM_NODE_IDENTIFY(parser),
4623 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
4625 .start = target->location.start,
4626 .end = value->location.end
4629 .name = pm_global_variable_write_name(parser, target),
4630 .name_loc = PM_LOCATION_NODE_VALUE(target),
4631 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
4641static pm_global_variable_write_node_t *
4642pm_global_variable_write_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name, pm_node_t *value) {
4643 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4645 *node = (pm_global_variable_write_node_t) {
4647 .type = PM_GLOBAL_VARIABLE_WRITE_NODE,
4648 .node_id = PM_NODE_IDENTIFY(parser),
4649 .location = PM_LOCATION_NULL_VALUE(parser)
4652 .name_loc = PM_LOCATION_NULL_VALUE(parser),
4653 .operator_loc = PM_LOCATION_NULL_VALUE(parser),
4663static pm_hash_node_t *
4664pm_hash_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4665 assert(opening != NULL);
4666 pm_hash_node_t *node = PM_NODE_ALLOC(parser, pm_hash_node_t);
4668 *node = (pm_hash_node_t) {
4670 .type = PM_HASH_NODE,
4671 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4672 .node_id = PM_NODE_IDENTIFY(parser),
4673 .location = PM_LOCATION_TOKEN_VALUE(opening)
4675 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4676 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
4687pm_hash_node_elements_append(pm_hash_node_t *hash, pm_node_t *element) {
4688 pm_node_list_append(&hash->elements, element);
4690 bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE);
4691 if (static_literal) {
4692 pm_assoc_node_t *assoc = (pm_assoc_node_t *) element;
4693 static_literal = !PM_NODE_TYPE_P(assoc->key, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(assoc->key, PM_HASH_NODE) && !PM_NODE_TYPE_P(assoc->key, PM_RANGE_NODE);
4694 static_literal = static_literal && PM_NODE_FLAG_P(assoc->key, PM_NODE_FLAG_STATIC_LITERAL);
4695 static_literal = static_literal && PM_NODE_FLAG_P(assoc, PM_NODE_FLAG_STATIC_LITERAL);
4698 if (!static_literal) {
4699 pm_node_flag_unset((pm_node_t *)hash, PM_NODE_FLAG_STATIC_LITERAL);
4704pm_hash_node_closing_loc_set(pm_hash_node_t *hash, pm_token_t *token) {
4705 hash->base.location.end = token->end;
4706 hash->closing_loc = PM_LOCATION_TOKEN_VALUE(token);
4712static pm_if_node_t *
4713pm_if_node_create(pm_parser_t *parser,
4714 const pm_token_t *if_keyword,
4715 pm_node_t *predicate,
4716 const pm_token_t *then_keyword,
4717 pm_statements_node_t *statements,
4718 pm_node_t *subsequent,
4719 const pm_token_t *end_keyword
4721 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4722 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4725 if (end_keyword->type != PM_TOKEN_NOT_PROVIDED) {
4726 end = end_keyword->end;
4727 } else if (subsequent != NULL) {
4728 end = subsequent->location.end;
4729 } else if (pm_statements_node_body_length(statements) != 0) {
4730 end = statements->base.location.end;
4732 end = predicate->location.end;
4735 *node = (pm_if_node_t) {
4738 .flags = PM_NODE_FLAG_NEWLINE,
4739 .node_id = PM_NODE_IDENTIFY(parser),
4741 .start = if_keyword->start,
4745 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4746 .predicate = predicate,
4747 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
4748 .statements = statements,
4749 .subsequent = subsequent,
4750 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
4759static pm_if_node_t *
4760pm_if_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *if_keyword, pm_node_t *predicate) {
4761 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4762 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4764 pm_statements_node_t *statements = pm_statements_node_create(parser);
4765 pm_statements_node_body_append(parser, statements, statement, true);
4767 *node = (pm_if_node_t) {
4770 .flags = PM_NODE_FLAG_NEWLINE,
4771 .node_id = PM_NODE_IDENTIFY(parser),
4773 .start = statement->location.start,
4774 .end = predicate->location.end
4777 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4778 .predicate = predicate,
4779 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4780 .statements = statements,
4782 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4791static pm_if_node_t *
4792pm_if_node_ternary_create(pm_parser_t *parser, pm_node_t *predicate, const pm_token_t *qmark, pm_node_t *true_expression, const pm_token_t *colon, pm_node_t *false_expression) {
4793 pm_assert_value_expression(parser, predicate);
4794 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4796 pm_statements_node_t *if_statements = pm_statements_node_create(parser);
4797 pm_statements_node_body_append(parser, if_statements, true_expression, true);
4799 pm_statements_node_t *else_statements = pm_statements_node_create(parser);
4800 pm_statements_node_body_append(parser, else_statements, false_expression, true);
4802 pm_token_t end_keyword = not_provided(parser);
4803 pm_else_node_t *else_node = pm_else_node_create(parser, colon, else_statements, &end_keyword);
4805 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4807 *node = (pm_if_node_t) {
4810 .flags = PM_NODE_FLAG_NEWLINE,
4811 .node_id = PM_NODE_IDENTIFY(parser),
4813 .start = predicate->location.start,
4814 .end = false_expression->location.end,
4817 .if_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4818 .predicate = predicate,
4819 .then_keyword_loc = PM_LOCATION_TOKEN_VALUE(qmark),
4820 .statements = if_statements,
4821 .subsequent = (pm_node_t *) else_node,
4822 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4830pm_if_node_end_keyword_loc_set(pm_if_node_t *node, const pm_token_t *keyword) {
4831 node->base.location.end = keyword->end;
4832 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4836pm_else_node_end_keyword_loc_set(pm_else_node_t *node, const pm_token_t *keyword) {
4837 node->base.location.end = keyword->end;
4838 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4844static pm_implicit_node_t *
4845pm_implicit_node_create(pm_parser_t *parser, pm_node_t *value) {
4846 pm_implicit_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_node_t);
4848 *node = (pm_implicit_node_t) {
4850 .type = PM_IMPLICIT_NODE,
4851 .node_id = PM_NODE_IDENTIFY(parser),
4852 .location = value->location
4863static pm_implicit_rest_node_t *
4864pm_implicit_rest_node_create(pm_parser_t *parser, const pm_token_t *token) {
4865 assert(token->type == PM_TOKEN_COMMA);
4867 pm_implicit_rest_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_rest_node_t);
4869 *node = (pm_implicit_rest_node_t) {
4871 .type = PM_IMPLICIT_REST_NODE,
4872 .node_id = PM_NODE_IDENTIFY(parser),
4873 .location = PM_LOCATION_TOKEN_VALUE(token)
4883static pm_integer_node_t *
4884pm_integer_node_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4885 assert(token->type == PM_TOKEN_INTEGER);
4886 pm_integer_node_t *node = PM_NODE_ALLOC(parser, pm_integer_node_t);
4888 *node = (pm_integer_node_t) {
4890 .type = PM_INTEGER_NODE,
4891 .flags = base | PM_NODE_FLAG_STATIC_LITERAL,
4892 .node_id = PM_NODE_IDENTIFY(parser),
4893 .location = PM_LOCATION_TOKEN_VALUE(token)
4898 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4900 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4901 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4902 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4903 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4904 default: assert(false && "unreachable"); break;
4907 pm_integer_parse(&node->value, integer_base, token->start, token->end);
4915static pm_imaginary_node_t *
4916pm_integer_node_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4917 assert(token->type == PM_TOKEN_INTEGER_IMAGINARY);
4919 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4920 *node = (pm_imaginary_node_t) {
4922 .type = PM_IMAGINARY_NODE,
4923 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4924 .node_id = PM_NODE_IDENTIFY(parser),
4925 .location = PM_LOCATION_TOKEN_VALUE(token)
4927 .numeric = (pm_node_t *) pm_integer_node_create(parser, base, &((pm_token_t) {
4928 .type = PM_TOKEN_INTEGER,
4929 .start = token->start,
4930 .end = token->end - 1
4941static pm_rational_node_t *
4942pm_integer_node_rational_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4943 assert(token->type == PM_TOKEN_INTEGER_RATIONAL);
4945 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
4946 *node = (pm_rational_node_t) {
4948 .type = PM_RATIONAL_NODE,
4949 .flags = base | PM_NODE_FLAG_STATIC_LITERAL,
4950 .node_id = PM_NODE_IDENTIFY(parser),
4951 .location = PM_LOCATION_TOKEN_VALUE(token)
4954 .denominator = { .value = 1, 0 }
4957 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4959 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4960 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4961 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4962 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4963 default: assert(false && "unreachable"); break;
4966 pm_integer_parse(&node->numerator, integer_base, token->start, token->end - 1);
4975static pm_imaginary_node_t *
4976pm_integer_node_rational_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4977 assert(token->type == PM_TOKEN_INTEGER_RATIONAL_IMAGINARY);
4979 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4980 *node = (pm_imaginary_node_t) {
4982 .type = PM_IMAGINARY_NODE,
4983 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4984 .node_id = PM_NODE_IDENTIFY(parser),
4985 .location = PM_LOCATION_TOKEN_VALUE(token)
4987 .numeric = (pm_node_t *) pm_integer_node_rational_create(parser, base, &((pm_token_t) {
4988 .type = PM_TOKEN_INTEGER_RATIONAL,
4989 .start = token->start,
4990 .end = token->end - 1
5000static pm_in_node_t *
5001pm_in_node_create(pm_parser_t *parser, pm_node_t *pattern, pm_statements_node_t *statements, const pm_token_t *in_keyword, const pm_token_t *then_keyword) {
5002 pm_in_node_t *node = PM_NODE_ALLOC(parser, pm_in_node_t);
5005 if (statements != NULL) {
5006 end = statements->base.location.end;
5007 } else if (then_keyword->type != PM_TOKEN_NOT_PROVIDED) {
5008 end = then_keyword->end;
5010 end = pattern->location.end;
5013 *node = (pm_in_node_t) {
5016 .node_id = PM_NODE_IDENTIFY(parser),
5018 .start = in_keyword->start,
5023 .statements = statements,
5024 .in_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
5025 .then_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword)
5034static pm_instance_variable_and_write_node_t *
5035pm_instance_variable_and_write_node_create(pm_parser_t *parser, pm_instance_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
5036 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5037 pm_instance_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_and_write_node_t);
5039 *node = (pm_instance_variable_and_write_node_t) {
5041 .type = PM_INSTANCE_VARIABLE_AND_WRITE_NODE,
5042 .node_id = PM_NODE_IDENTIFY(parser),
5044 .start = target->base.location.start,
5045 .end = value->location.end
5048 .name = target->name,
5049 .name_loc = target->base.location,
5050 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5060static pm_instance_variable_operator_write_node_t *
5061pm_instance_variable_operator_write_node_create(pm_parser_t *parser, pm_instance_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
5062 pm_instance_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_operator_write_node_t);
5064 *node = (pm_instance_variable_operator_write_node_t) {
5066 .type = PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE,
5067 .node_id = PM_NODE_IDENTIFY(parser),
5069 .start = target->base.location.start,
5070 .end = value->location.end
5073 .name = target->name,
5074 .name_loc = target->base.location,
5075 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5077 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
5086static pm_instance_variable_or_write_node_t *
5087pm_instance_variable_or_write_node_create(pm_parser_t *parser, pm_instance_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
5088 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5089 pm_instance_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_or_write_node_t);
5091 *node = (pm_instance_variable_or_write_node_t) {
5093 .type = PM_INSTANCE_VARIABLE_OR_WRITE_NODE,
5094 .node_id = PM_NODE_IDENTIFY(parser),
5096 .start = target->base.location.start,
5097 .end = value->location.end
5100 .name = target->name,
5101 .name_loc = target->base.location,
5102 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5112static pm_instance_variable_read_node_t *
5113pm_instance_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
5114 assert(token->type == PM_TOKEN_INSTANCE_VARIABLE);
5115 pm_instance_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_read_node_t);
5117 *node = (pm_instance_variable_read_node_t) {
5119 .type = PM_INSTANCE_VARIABLE_READ_NODE,
5120 .node_id = PM_NODE_IDENTIFY(parser),
5121 .location = PM_LOCATION_TOKEN_VALUE(token)
5123 .name = pm_parser_constant_id_token(parser, token)
5133static pm_instance_variable_write_node_t *
5134pm_instance_variable_write_node_create(pm_parser_t *parser, pm_instance_variable_read_node_t *read_node, pm_token_t *operator, pm_node_t *value) {
5135 pm_instance_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_write_node_t);
5136 *node = (pm_instance_variable_write_node_t) {
5138 .type = PM_INSTANCE_VARIABLE_WRITE_NODE,
5139 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5140 .node_id = PM_NODE_IDENTIFY(parser),
5142 .start = read_node->base.location.start,
5143 .end = value->location.end
5146 .name = read_node->name,
5147 .name_loc = PM_LOCATION_NODE_BASE_VALUE(read_node),
5148 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
5161pm_interpolated_node_append(pm_node_t *node, pm_node_list_t *parts, pm_node_t *part) {
5162 switch (PM_NODE_TYPE(part)) {
5163 case PM_STRING_NODE:
5164 pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5166 case PM_EMBEDDED_STATEMENTS_NODE: {
5167 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5168 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5170 if (embedded == NULL) {
5171 // If there are no statements or more than one statement, then
5172 // we lose the static literal flag.
5173 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5174 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5175 // If the embedded statement is a string, then we can keep the
5176 // static literal flag and mark the string as frozen.
5177 pm_node_flag_set(embedded, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5178 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5179 // If the embedded statement is an interpolated string and it's
5180 // a static literal, then we can keep the static literal flag.
5182 // Otherwise we lose the static literal flag.
5183 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5188 case PM_EMBEDDED_VARIABLE_NODE:
5189 pm_node_flag_unset((pm_node_t *) node, PM_NODE_FLAG_STATIC_LITERAL);
5192 assert(false && "unexpected node type");
5196 pm_node_list_append(parts, part);
5202static pm_interpolated_regular_expression_node_t *
5203pm_interpolated_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening) {
5204 pm_interpolated_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_regular_expression_node_t);
5206 *node = (pm_interpolated_regular_expression_node_t) {
5208 .type = PM_INTERPOLATED_REGULAR_EXPRESSION_NODE,
5209 .flags = PM_NODE_FLAG_STATIC_LITERAL,
5210 .node_id = PM_NODE_IDENTIFY(parser),
5212 .start = opening->start,
5216 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5217 .closing_loc = PM_LOCATION_TOKEN_VALUE(opening),
5225pm_interpolated_regular_expression_node_append(pm_interpolated_regular_expression_node_t *node, pm_node_t *part) {
5226 if (node->base.location.start > part->location.start) {
5227 node->base.location.start = part->location.start;
5229 if (node->base.location.end < part->location.end) {
5230 node->base.location.end = part->location.end;
5233 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5237pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_interpolated_regular_expression_node_t *node, const pm_token_t *closing) {
5238 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
5239 node->base.location.end = closing->end;
5240 pm_node_flag_set((pm_node_t *) node, pm_regular_expression_flags_create(parser, closing));
5267pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_node_t *part) {
5268#define CLEAR_FLAGS(node) \
5269 node->base.flags = (pm_node_flags_t) (node->base.flags & ~(PM_NODE_FLAG_STATIC_LITERAL | PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE))
5271#define MUTABLE_FLAGS(node) \
5272 node->base.flags = (pm_node_flags_t) ((node->base.flags | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE) & ~PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN);
5274 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
5275 node->base.location.start = part->location.start;
5278 node->base.location.end = MAX(node->base.location.end, part->location.end);
5280 switch (PM_NODE_TYPE(part)) {
5281 case PM_STRING_NODE:
5282 part->flags = (pm_node_flags_t) ((part->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5284 case PM_INTERPOLATED_STRING_NODE:
5285 if (PM_NODE_FLAG_P(part, PM_NODE_FLAG_STATIC_LITERAL)) {
5286 // If the string that we're concatenating is a static literal,
5287 // then we can keep the static literal flag for this string.
5289 // Otherwise, we lose the static literal flag here and we should
5290 // also clear the mutability flags.
5294 case PM_EMBEDDED_STATEMENTS_NODE: {
5295 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5296 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5298 if (embedded == NULL) {
5299 // If we're embedding multiple statements or no statements, then
5300 // the string is not longer a static literal.
5302 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5303 // If the embedded statement is a string, then we can make that
5304 // string as frozen and static literal, and not touch the static
5305 // literal status of this string.
5306 embedded->flags = (pm_node_flags_t) ((embedded->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5308 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5309 MUTABLE_FLAGS(node);
5311 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5312 // If the embedded statement is an interpolated string, but that
5313 // string is marked as static literal, then we can keep our
5314 // static literal status for this string.
5315 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5316 MUTABLE_FLAGS(node);
5319 // In all other cases, we lose the static literal flag here and
5326 case PM_EMBEDDED_VARIABLE_NODE:
5327 // Embedded variables clear static literal, which means we also
5328 // should clear the mutability flags.
5331 case PM_X_STRING_NODE:
5332 case PM_INTERPOLATED_X_STRING_NODE:
5333 // If this is an x string, then this is a syntax error. But we want
5334 // to handle it here so that we don't fail the assertion.
5338 assert(false && "unexpected node type");
5342 pm_node_list_append(&node->parts, part);
5351static pm_interpolated_string_node_t *
5352pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5353 pm_interpolated_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_string_node_t);
5354 pm_node_flags_t flags = PM_NODE_FLAG_STATIC_LITERAL;
5356 switch (parser->frozen_string_literal) {
5357 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
5358 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE;
5360 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
5361 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN;
5365 *node = (pm_interpolated_string_node_t) {
5367 .type = PM_INTERPOLATED_STRING_NODE,
5369 .node_id = PM_NODE_IDENTIFY(parser),
5371 .start = opening->start,
5372 .end = closing->end,
5375 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5376 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5380 if (parts != NULL) {
5382 PM_NODE_LIST_FOREACH(parts, index, part) {
5383 pm_interpolated_string_node_append(node, part);
5394pm_interpolated_string_node_closing_set(pm_interpolated_string_node_t *node, const pm_token_t *closing) {
5395 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5396 node->base.location.end = closing->end;
5400pm_interpolated_symbol_node_append(pm_interpolated_symbol_node_t *node, pm_node_t *part) {
5401 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
5402 node->base.location.start = part->location.start;
5405 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5406 node->base.location.end = MAX(node->base.location.end, part->location.end);
5410pm_interpolated_symbol_node_closing_loc_set(pm_interpolated_symbol_node_t *node, const pm_token_t *closing) {
5411 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5412 node->base.location.end = closing->end;
5418static pm_interpolated_symbol_node_t *
5419pm_interpolated_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5420 pm_interpolated_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_symbol_node_t);
5422 *node = (pm_interpolated_symbol_node_t) {
5424 .type = PM_INTERPOLATED_SYMBOL_NODE,
5425 .flags = PM_NODE_FLAG_STATIC_LITERAL,
5426 .node_id = PM_NODE_IDENTIFY(parser),
5428 .start = opening->start,
5429 .end = closing->end,
5432 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5433 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5437 if (parts != NULL) {
5439 PM_NODE_LIST_FOREACH(parts, index, part) {
5440 pm_interpolated_symbol_node_append(node, part);
5450static pm_interpolated_x_string_node_t *
5451pm_interpolated_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5452 pm_interpolated_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_x_string_node_t);
5454 *node = (pm_interpolated_x_string_node_t) {
5456 .type = PM_INTERPOLATED_X_STRING_NODE,
5457 .node_id = PM_NODE_IDENTIFY(parser),
5459 .start = opening->start,
5463 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5464 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5472pm_interpolated_xstring_node_append(pm_interpolated_x_string_node_t *node, pm_node_t *part) {
5473 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5474 node->base.location.end = part->location.end;
5478pm_interpolated_xstring_node_closing_set(pm_interpolated_x_string_node_t *node, const pm_token_t *closing) {
5479 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5480 node->base.location.end = closing->end;
5486static pm_it_local_variable_read_node_t *
5487pm_it_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5488 pm_it_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_it_local_variable_read_node_t);
5490 *node = (pm_it_local_variable_read_node_t) {
5492 .type = PM_IT_LOCAL_VARIABLE_READ_NODE,
5493 .node_id = PM_NODE_IDENTIFY(parser),
5494 .location = PM_LOCATION_TOKEN_VALUE(name)
5504static pm_it_parameters_node_t *
5505pm_it_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5506 pm_it_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_it_parameters_node_t);
5508 *node = (pm_it_parameters_node_t) {
5510 .type = PM_IT_PARAMETERS_NODE,
5511 .node_id = PM_NODE_IDENTIFY(parser),
5513 .start = opening->start,
5525static pm_keyword_hash_node_t *
5526pm_keyword_hash_node_create(pm_parser_t *parser) {
5527 pm_keyword_hash_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_hash_node_t);
5529 *node = (pm_keyword_hash_node_t) {
5531 .type = PM_KEYWORD_HASH_NODE,
5532 .flags = PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS,
5533 .node_id = PM_NODE_IDENTIFY(parser),
5534 .location = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
5546pm_keyword_hash_node_elements_append(pm_keyword_hash_node_t *hash, pm_node_t *element) {
5547 // If the element being added is not an AssocNode or does not have a symbol
5548 // key, then we want to turn the SYMBOL_KEYS flag off.
5549 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE) || !PM_NODE_TYPE_P(((pm_assoc_node_t *) element)->key, PM_SYMBOL_NODE)) {
5550 pm_node_flag_unset((pm_node_t *)hash, PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS);
5553 pm_node_list_append(&hash->elements, element);
5554 if (hash->base.location.start == NULL) {
5555 hash->base.location.start = element->location.start;
5557 hash->base.location.end = element->location.end;
5563static pm_required_keyword_parameter_node_t *
5564pm_required_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name) {
5565 pm_required_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_keyword_parameter_node_t);
5567 *node = (pm_required_keyword_parameter_node_t) {
5569 .type = PM_REQUIRED_KEYWORD_PARAMETER_NODE,
5570 .node_id = PM_NODE_IDENTIFY(parser),
5572 .start = name->start,
5576 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5577 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5586static pm_optional_keyword_parameter_node_t *
5587pm_optional_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, pm_node_t *value) {
5588 pm_optional_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_keyword_parameter_node_t);
5590 *node = (pm_optional_keyword_parameter_node_t) {
5592 .type = PM_OPTIONAL_KEYWORD_PARAMETER_NODE,
5593 .node_id = PM_NODE_IDENTIFY(parser),
5595 .start = name->start,
5596 .end = value->location.end
5599 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5600 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5610static pm_keyword_rest_parameter_node_t *
5611pm_keyword_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
5612 pm_keyword_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_rest_parameter_node_t);
5614 *node = (pm_keyword_rest_parameter_node_t) {
5616 .type = PM_KEYWORD_REST_PARAMETER_NODE,
5617 .node_id = PM_NODE_IDENTIFY(parser),
5619 .start = operator->start,
5620 .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
5623 .name = pm_parser_optional_constant_id_token(parser, name),
5624 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
5625 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5634static pm_lambda_node_t *
5635pm_lambda_node_create(
5636 pm_parser_t *parser,
5637 pm_constant_id_list_t *locals,
5638 const pm_token_t *operator,
5639 const pm_token_t *opening,
5640 const pm_token_t *closing,
5641 pm_node_t *parameters,
5644 pm_lambda_node_t *node = PM_NODE_ALLOC(parser, pm_lambda_node_t);
5646 *node = (pm_lambda_node_t) {
5648 .type = PM_LAMBDA_NODE,
5649 .node_id = PM_NODE_IDENTIFY(parser),
5651 .start = operator->start,
5656 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5657 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5658 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
5659 .parameters = parameters,
5669static pm_local_variable_and_write_node_t *
5670pm_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) {
5671 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));
5672 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5673 pm_local_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_and_write_node_t);
5675 *node = (pm_local_variable_and_write_node_t) {
5677 .type = PM_LOCAL_VARIABLE_AND_WRITE_NODE,
5678 .node_id = PM_NODE_IDENTIFY(parser),
5680 .start = target->location.start,
5681 .end = value->location.end
5684 .name_loc = target->location,
5685 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5697static pm_local_variable_operator_write_node_t *
5698pm_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) {
5699 pm_local_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_operator_write_node_t);
5701 *node = (pm_local_variable_operator_write_node_t) {
5703 .type = PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE,
5704 .node_id = PM_NODE_IDENTIFY(parser),
5706 .start = target->location.start,
5707 .end = value->location.end
5710 .name_loc = target->location,
5711 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5714 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
5724static pm_local_variable_or_write_node_t *
5725pm_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) {
5726 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));
5727 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5728 pm_local_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_or_write_node_t);
5730 *node = (pm_local_variable_or_write_node_t) {
5732 .type = PM_LOCAL_VARIABLE_OR_WRITE_NODE,
5733 .node_id = PM_NODE_IDENTIFY(parser),
5735 .start = target->location.start,
5736 .end = value->location.end
5739 .name_loc = target->location,
5740 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5752static pm_local_variable_read_node_t *
5753pm_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) {
5754 if (!missing) pm_locals_read(&pm_parser_scope_find(parser, depth)->locals, name_id);
5756 pm_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_read_node_t);
5758 *node = (pm_local_variable_read_node_t) {
5760 .type = PM_LOCAL_VARIABLE_READ_NODE,
5761 .node_id = PM_NODE_IDENTIFY(parser),
5762 .location = PM_LOCATION_TOKEN_VALUE(name)
5774static pm_local_variable_read_node_t *
5775pm_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5776 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5777 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, false);
5784static pm_local_variable_read_node_t *
5785pm_local_variable_read_node_missing_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5786 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5787 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, true);
5793static pm_local_variable_write_node_t *
5794pm_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) {
5795 pm_local_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_write_node_t);
5797 *node = (pm_local_variable_write_node_t) {
5799 .type = PM_LOCAL_VARIABLE_WRITE_NODE,
5800 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5801 .node_id = PM_NODE_IDENTIFY(parser),
5803 .start = name_loc->start,
5804 .end = value->location.end
5810 .name_loc = *name_loc,
5811 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator)
5821pm_token_is_it(const uint8_t *start, const uint8_t *end) {
5822 return (end - start == 2) && (start[0] == 'i') && (start[1] == 't');
5830pm_token_is_numbered_parameter(const uint8_t *start, const uint8_t *end) {
5831 return (end - start == 2) && (start[0] == '_') && (start[1] != '0') && (pm_char_is_decimal_digit(start[1]));
5839pm_refute_numbered_parameter(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
5840 if (pm_token_is_numbered_parameter(start, end)) {
5841 PM_PARSER_ERR_FORMAT(parser, start, end, PM_ERR_PARAMETER_NUMBERED_RESERVED, start);
5849static pm_local_variable_target_node_t *
5850pm_local_variable_target_node_create(pm_parser_t *parser, const pm_location_t *location, pm_constant_id_t name, uint32_t depth) {
5851 pm_refute_numbered_parameter(parser, location->start, location->end);
5852 pm_local_variable_target_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_target_node_t);
5854 *node = (pm_local_variable_target_node_t) {
5856 .type = PM_LOCAL_VARIABLE_TARGET_NODE,
5857 .node_id = PM_NODE_IDENTIFY(parser),
5858 .location = *location
5870static pm_match_predicate_node_t *
5871pm_match_predicate_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5872 pm_assert_value_expression(parser, value);
5874 pm_match_predicate_node_t *node = PM_NODE_ALLOC(parser, pm_match_predicate_node_t);
5876 *node = (pm_match_predicate_node_t) {
5878 .type = PM_MATCH_PREDICATE_NODE,
5879 .node_id = PM_NODE_IDENTIFY(parser),
5881 .start = value->location.start,
5882 .end = pattern->location.end
5887 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5896static pm_match_required_node_t *
5897pm_match_required_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5898 pm_assert_value_expression(parser, value);
5900 pm_match_required_node_t *node = PM_NODE_ALLOC(parser, pm_match_required_node_t);
5902 *node = (pm_match_required_node_t) {
5904 .type = PM_MATCH_REQUIRED_NODE,
5905 .node_id = PM_NODE_IDENTIFY(parser),
5907 .start = value->location.start,
5908 .end = pattern->location.end
5913 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5922static pm_match_write_node_t *
5923pm_match_write_node_create(pm_parser_t *parser, pm_call_node_t *call) {
5924 pm_match_write_node_t *node = PM_NODE_ALLOC(parser, pm_match_write_node_t);
5926 *node = (pm_match_write_node_t) {
5928 .type = PM_MATCH_WRITE_NODE,
5929 .node_id = PM_NODE_IDENTIFY(parser),
5930 .location = call->base.location
5942static pm_module_node_t *
5943pm_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) {
5944 pm_module_node_t *node = PM_NODE_ALLOC(parser, pm_module_node_t);
5946 *node = (pm_module_node_t) {
5948 .type = PM_MODULE_NODE,
5949 .node_id = PM_NODE_IDENTIFY(parser),
5951 .start = module_keyword->start,
5952 .end = end_keyword->end
5955 .locals = (locals == NULL ? ((pm_constant_id_list_t) { .ids = NULL, .size = 0, .capacity = 0 }) : *locals),
5956 .module_keyword_loc = PM_LOCATION_TOKEN_VALUE(module_keyword),
5957 .constant_path = constant_path,
5959 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
5960 .name = pm_parser_constant_id_token(parser, name)
5969static pm_multi_target_node_t *
5970pm_multi_target_node_create(pm_parser_t *parser) {
5971 pm_multi_target_node_t *node = PM_NODE_ALLOC(parser, pm_multi_target_node_t);
5973 *node = (pm_multi_target_node_t) {
5975 .type = PM_MULTI_TARGET_NODE,
5976 .node_id = PM_NODE_IDENTIFY(parser),
5977 .location = { .start = NULL, .end = NULL }
5982 .lparen_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
5983 .rparen_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
5993pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t *node, pm_node_t *target) {
5994 if (PM_NODE_TYPE_P(target, PM_SPLAT_NODE)) {
5995 if (node->rest == NULL) {
5996 node->rest = target;
5998 pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
5999 pm_node_list_append(&node->rights, target);
6001 } else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
6002 if (node->rest == NULL) {
6003 node->rest = target;
6005 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
6006 pm_node_list_append(&node->rights, target);
6008 } else if (node->rest == NULL) {
6009 pm_node_list_append(&node->lefts, target);
6011 pm_node_list_append(&node->rights, target);
6014 if (node->base.location.start == NULL || (node->base.location.start > target->location.start)) {
6015 node->base.location.start = target->location.start;
6018 if (node->base.location.end == NULL || (node->base.location.end < target->location.end)) {
6019 node->base.location.end = target->location.end;
6027pm_multi_target_node_opening_set(pm_multi_target_node_t *node, const pm_token_t *lparen) {
6028 node->base.location.start = lparen->start;
6029 node->lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen);
6036pm_multi_target_node_closing_set(pm_multi_target_node_t *node, const pm_token_t *rparen) {
6037 node->base.location.end = rparen->end;
6038 node->rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen);
6044static pm_multi_write_node_t *
6045pm_multi_write_node_create(pm_parser_t *parser, pm_multi_target_node_t *target, const pm_token_t *operator, pm_node_t *value) {
6046 pm_multi_write_node_t *node = PM_NODE_ALLOC(parser, pm_multi_write_node_t);
6048 *node = (pm_multi_write_node_t) {
6050 .type = PM_MULTI_WRITE_NODE,
6051 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
6052 .node_id = PM_NODE_IDENTIFY(parser),
6054 .start = target->base.location.start,
6055 .end = value->location.end
6058 .lefts = target->lefts,
6059 .rest = target->rest,
6060 .rights = target->rights,
6061 .lparen_loc = target->lparen_loc,
6062 .rparen_loc = target->rparen_loc,
6063 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6067 // Explicitly do not call pm_node_destroy here because we want to keep
6068 // around all of the information within the MultiWriteNode node.
6077static pm_next_node_t *
6078pm_next_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6079 assert(keyword->type == PM_TOKEN_KEYWORD_NEXT);
6080 pm_next_node_t *node = PM_NODE_ALLOC(parser, pm_next_node_t);
6082 *node = (pm_next_node_t) {
6084 .type = PM_NEXT_NODE,
6085 .node_id = PM_NODE_IDENTIFY(parser),
6087 .start = keyword->start,
6088 .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
6091 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6092 .arguments = arguments
6101static pm_nil_node_t *
6102pm_nil_node_create(pm_parser_t *parser, const pm_token_t *token) {
6103 assert(token->type == PM_TOKEN_KEYWORD_NIL);
6104 pm_nil_node_t *node = PM_NODE_ALLOC(parser, pm_nil_node_t);
6106 *node = (pm_nil_node_t) {{
6107 .type = PM_NIL_NODE,
6108 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6109 .node_id = PM_NODE_IDENTIFY(parser),
6110 .location = PM_LOCATION_TOKEN_VALUE(token)
6119static pm_no_keywords_parameter_node_t *
6120pm_no_keywords_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
6121 assert(operator->type == PM_TOKEN_USTAR_STAR || operator->type == PM_TOKEN_STAR_STAR);
6122 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
6123 pm_no_keywords_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_no_keywords_parameter_node_t);
6125 *node = (pm_no_keywords_parameter_node_t) {
6127 .type = PM_NO_KEYWORDS_PARAMETER_NODE,
6128 .node_id = PM_NODE_IDENTIFY(parser),
6130 .start = operator->start,
6134 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6135 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
6144static pm_numbered_parameters_node_t *
6145pm_numbered_parameters_node_create(pm_parser_t *parser, const pm_location_t *location, uint8_t maximum) {
6146 pm_numbered_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_parameters_node_t);
6148 *node = (pm_numbered_parameters_node_t) {
6150 .type = PM_NUMBERED_PARAMETERS_NODE,
6151 .node_id = PM_NODE_IDENTIFY(parser),
6152 .location = *location
6164#define NTH_REF_MAX ((uint32_t) (INT_MAX >> 1))
6173pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *token) {
6174 const uint8_t *start = token->start + 1;
6175 const uint8_t *end = token->end;
6177 ptrdiff_t diff = end - start;
6179#if PTRDIFF_MAX > SIZE_MAX
6180 assert(diff < (ptrdiff_t) SIZE_MAX);
6182 size_t length = (size_t) diff;
6184 char *digits = xcalloc(length + 1, sizeof(char));
6185 memcpy(digits, start, length);
6186 digits[length] = '\0';
6190 unsigned long value = strtoul(digits, &endptr, 10);
6192 if ((digits == endptr) || (*endptr != '\0')) {
6193 pm_parser_err(parser, start, end, PM_ERR_INVALID_NUMBER_DECIMAL);
6199 if ((errno == ERANGE) || (value > NTH_REF_MAX)) {
6200 PM_PARSER_WARN_FORMAT(parser, start, end, PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start);
6204 return (uint32_t) value;
6212static pm_numbered_reference_read_node_t *
6213pm_numbered_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
6214 assert(name->type == PM_TOKEN_NUMBERED_REFERENCE);
6215 pm_numbered_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_reference_read_node_t);
6217 *node = (pm_numbered_reference_read_node_t) {
6219 .type = PM_NUMBERED_REFERENCE_READ_NODE,
6220 .node_id = PM_NODE_IDENTIFY(parser),
6221 .location = PM_LOCATION_TOKEN_VALUE(name),
6223 .number = pm_numbered_reference_read_node_number(parser, name)
6232static pm_optional_parameter_node_t *
6233pm_optional_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator, pm_node_t *value) {
6234 pm_optional_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_parameter_node_t);
6236 *node = (pm_optional_parameter_node_t) {
6238 .type = PM_OPTIONAL_PARAMETER_NODE,
6239 .node_id = PM_NODE_IDENTIFY(parser),
6241 .start = name->start,
6242 .end = value->location.end
6245 .name = pm_parser_constant_id_token(parser, name),
6246 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
6247 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6257static pm_or_node_t *
6258pm_or_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
6259 pm_assert_value_expression(parser, left);
6261 pm_or_node_t *node = PM_NODE_ALLOC(parser, pm_or_node_t);
6263 *node = (pm_or_node_t) {
6266 .node_id = PM_NODE_IDENTIFY(parser),
6268 .start = left->location.start,
6269 .end = right->location.end
6274 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6283static pm_parameters_node_t *
6284pm_parameters_node_create(pm_parser_t *parser) {
6285 pm_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_parameters_node_t);
6287 *node = (pm_parameters_node_t) {
6289 .type = PM_PARAMETERS_NODE,
6290 .node_id = PM_NODE_IDENTIFY(parser),
6291 .location = PM_LOCATION_TOKEN_VALUE(&parser->current)
6294 .keyword_rest = NULL,
6309pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param) {
6310 if (params->base.location.start == NULL) {
6311 params->base.location.start = param->location.start;
6313 params->base.location.start = params->base.location.start < param->location.start ? params->base.location.start : param->location.start;
6316 if (params->base.location.end == NULL) {
6317 params->base.location.end = param->location.end;
6319 params->base.location.end = params->base.location.end > param->location.end ? params->base.location.end : param->location.end;
6327pm_parameters_node_requireds_append(pm_parameters_node_t *params, pm_node_t *param) {
6328 pm_parameters_node_location_set(params, param);
6329 pm_node_list_append(¶ms->requireds, param);
6336pm_parameters_node_optionals_append(pm_parameters_node_t *params, pm_optional_parameter_node_t *param) {
6337 pm_parameters_node_location_set(params, (pm_node_t *) param);
6338 pm_node_list_append(¶ms->optionals, (pm_node_t *) param);
6345pm_parameters_node_posts_append(pm_parameters_node_t *params, pm_node_t *param) {
6346 pm_parameters_node_location_set(params, param);
6347 pm_node_list_append(¶ms->posts, param);
6354pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6355 pm_parameters_node_location_set(params, param);
6356 params->rest = param;
6363pm_parameters_node_keywords_append(pm_parameters_node_t *params, pm_node_t *param) {
6364 pm_parameters_node_location_set(params, param);
6365 pm_node_list_append(¶ms->keywords, param);
6372pm_parameters_node_keyword_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6373 assert(params->keyword_rest == NULL);
6374 pm_parameters_node_location_set(params, param);
6375 params->keyword_rest = param;
6382pm_parameters_node_block_set(pm_parameters_node_t *params, pm_block_parameter_node_t *param) {
6383 assert(params->block == NULL);
6384 pm_parameters_node_location_set(params, (pm_node_t *) param);
6385 params->block = param;
6391static pm_program_node_t *
6392pm_program_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, pm_statements_node_t *statements) {
6393 pm_program_node_t *node = PM_NODE_ALLOC(parser, pm_program_node_t);
6395 *node = (pm_program_node_t) {
6397 .type = PM_PROGRAM_NODE,
6398 .node_id = PM_NODE_IDENTIFY(parser),
6400 .start = statements == NULL ? parser->start : statements->base.location.start,
6401 .end = statements == NULL ? parser->end : statements->base.location.end
6405 .statements = statements
6414static pm_parentheses_node_t *
6415pm_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) {
6416 pm_parentheses_node_t *node = PM_NODE_ALLOC(parser, pm_parentheses_node_t);
6418 *node = (pm_parentheses_node_t) {
6420 .type = PM_PARENTHESES_NODE,
6422 .node_id = PM_NODE_IDENTIFY(parser),
6424 .start = opening->start,
6429 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6430 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6439static pm_pinned_expression_node_t *
6440pm_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) {
6441 pm_pinned_expression_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_expression_node_t);
6443 *node = (pm_pinned_expression_node_t) {
6445 .type = PM_PINNED_EXPRESSION_NODE,
6446 .node_id = PM_NODE_IDENTIFY(parser),
6448 .start = operator->start,
6452 .expression = expression,
6453 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6454 .lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen),
6455 .rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen)
6464static pm_pinned_variable_node_t *
6465pm_pinned_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
6466 pm_pinned_variable_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_variable_node_t);
6468 *node = (pm_pinned_variable_node_t) {
6470 .type = PM_PINNED_VARIABLE_NODE,
6471 .node_id = PM_NODE_IDENTIFY(parser),
6473 .start = operator->start,
6474 .end = variable->location.end
6477 .variable = variable,
6478 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6487static pm_post_execution_node_t *
6488pm_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) {
6489 pm_post_execution_node_t *node = PM_NODE_ALLOC(parser, pm_post_execution_node_t);
6491 *node = (pm_post_execution_node_t) {
6493 .type = PM_POST_EXECUTION_NODE,
6494 .node_id = PM_NODE_IDENTIFY(parser),
6496 .start = keyword->start,
6500 .statements = statements,
6501 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6502 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6503 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6512static pm_pre_execution_node_t *
6513pm_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) {
6514 pm_pre_execution_node_t *node = PM_NODE_ALLOC(parser, pm_pre_execution_node_t);
6516 *node = (pm_pre_execution_node_t) {
6518 .type = PM_PRE_EXECUTION_NODE,
6519 .node_id = PM_NODE_IDENTIFY(parser),
6521 .start = keyword->start,
6525 .statements = statements,
6526 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6527 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6528 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6537static pm_range_node_t *
6538pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
6539 pm_assert_value_expression(parser, left);
6540 pm_assert_value_expression(parser, right);
6542 pm_range_node_t *node = PM_NODE_ALLOC(parser, pm_range_node_t);
6543 pm_node_flags_t flags = 0;
6545 // Indicate that this node is an exclusive range if the operator is `...`.
6546 if (operator->type == PM_TOKEN_DOT_DOT_DOT || operator->type == PM_TOKEN_UDOT_DOT_DOT) {
6547 flags |= PM_RANGE_FLAGS_EXCLUDE_END;
6550 // Indicate that this node is a static literal (i.e., can be compiled with
6551 // a putobject in CRuby) if the left and right are implicit nil, explicit
6552 // nil, or integers.
6554 (left == NULL || PM_NODE_TYPE_P(left, PM_NIL_NODE) || PM_NODE_TYPE_P(left, PM_INTEGER_NODE)) &&
6555 (right == NULL || PM_NODE_TYPE_P(right, PM_NIL_NODE) || PM_NODE_TYPE_P(right, PM_INTEGER_NODE))
6557 flags |= PM_NODE_FLAG_STATIC_LITERAL;
6560 *node = (pm_range_node_t) {
6562 .type = PM_RANGE_NODE,
6564 .node_id = PM_NODE_IDENTIFY(parser),
6566 .start = (left == NULL ? operator->start : left->location.start),
6567 .end = (right == NULL ? operator->end : right->location.end)
6572 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6581static pm_redo_node_t *
6582pm_redo_node_create(pm_parser_t *parser, const pm_token_t *token) {
6583 assert(token->type == PM_TOKEN_KEYWORD_REDO);
6584 pm_redo_node_t *node = PM_NODE_ALLOC(parser, pm_redo_node_t);
6586 *node = (pm_redo_node_t) {{
6587 .type = PM_REDO_NODE,
6588 .node_id = PM_NODE_IDENTIFY(parser),
6589 .location = PM_LOCATION_TOKEN_VALUE(token)
6599static pm_regular_expression_node_t *
6600pm_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) {
6601 pm_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_regular_expression_node_t);
6603 *node = (pm_regular_expression_node_t) {
6605 .type = PM_REGULAR_EXPRESSION_NODE,
6606 .flags = pm_regular_expression_flags_create(parser, closing) | PM_NODE_FLAG_STATIC_LITERAL,
6607 .node_id = PM_NODE_IDENTIFY(parser),
6609 .start = MIN(opening->start, closing->start),
6610 .end = MAX(opening->end, closing->end)
6613 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6614 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
6615 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
6616 .unescaped = *unescaped
6625static inline pm_regular_expression_node_t *
6626pm_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6627 return pm_regular_expression_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6633static pm_required_parameter_node_t *
6634pm_required_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
6635 pm_required_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_parameter_node_t);
6637 *node = (pm_required_parameter_node_t) {
6639 .type = PM_REQUIRED_PARAMETER_NODE,
6640 .node_id = PM_NODE_IDENTIFY(parser),
6641 .location = PM_LOCATION_TOKEN_VALUE(token)
6643 .name = pm_parser_constant_id_token(parser, token)
6652static pm_rescue_modifier_node_t *
6653pm_rescue_modifier_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *keyword, pm_node_t *rescue_expression) {
6654 pm_rescue_modifier_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_modifier_node_t);
6656 *node = (pm_rescue_modifier_node_t) {
6658 .type = PM_RESCUE_MODIFIER_NODE,
6659 .node_id = PM_NODE_IDENTIFY(parser),
6661 .start = expression->location.start,
6662 .end = rescue_expression->location.end
6665 .expression = expression,
6666 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6667 .rescue_expression = rescue_expression
6676static pm_rescue_node_t *
6677pm_rescue_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
6678 pm_rescue_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_node_t);
6680 *node = (pm_rescue_node_t) {
6682 .type = PM_RESCUE_NODE,
6683 .node_id = PM_NODE_IDENTIFY(parser),
6684 .location = PM_LOCATION_TOKEN_VALUE(keyword)
6686 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6687 .operator_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
6688 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
6699pm_rescue_node_operator_set(pm_rescue_node_t *node, const pm_token_t *operator) {
6700 node->operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
6707pm_rescue_node_reference_set(pm_rescue_node_t *node, pm_node_t *reference) {
6708 node->reference = reference;
6709 node->base.location.end = reference->location.end;
6716pm_rescue_node_statements_set(pm_rescue_node_t *node, pm_statements_node_t *statements) {
6717 node->statements = statements;
6718 if (pm_statements_node_body_length(statements) > 0) {
6719 node->base.location.end = statements->base.location.end;
6727pm_rescue_node_subsequent_set(pm_rescue_node_t *node, pm_rescue_node_t *subsequent) {
6728 node->subsequent = subsequent;
6729 node->base.location.end = subsequent->base.location.end;
6736pm_rescue_node_exceptions_append(pm_rescue_node_t *node, pm_node_t *exception) {
6737 pm_node_list_append(&node->exceptions, exception);
6738 node->base.location.end = exception->location.end;
6744static pm_rest_parameter_node_t *
6745pm_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
6746 pm_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_rest_parameter_node_t);
6748 *node = (pm_rest_parameter_node_t) {
6750 .type = PM_REST_PARAMETER_NODE,
6751 .node_id = PM_NODE_IDENTIFY(parser),
6753 .start = operator->start,
6754 .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
6757 .name = pm_parser_optional_constant_id_token(parser, name),
6758 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
6759 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6768static pm_retry_node_t *
6769pm_retry_node_create(pm_parser_t *parser, const pm_token_t *token) {
6770 assert(token->type == PM_TOKEN_KEYWORD_RETRY);
6771 pm_retry_node_t *node = PM_NODE_ALLOC(parser, pm_retry_node_t);
6773 *node = (pm_retry_node_t) {{
6774 .type = PM_RETRY_NODE,
6775 .node_id = PM_NODE_IDENTIFY(parser),
6776 .location = PM_LOCATION_TOKEN_VALUE(token)
6785static pm_return_node_t *
6786pm_return_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6787 pm_return_node_t *node = PM_NODE_ALLOC(parser, pm_return_node_t);
6789 *node = (pm_return_node_t) {
6791 .type = PM_RETURN_NODE,
6792 .node_id = PM_NODE_IDENTIFY(parser),
6794 .start = keyword->start,
6795 .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
6798 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6799 .arguments = arguments
6808static pm_self_node_t *
6809pm_self_node_create(pm_parser_t *parser, const pm_token_t *token) {
6810 assert(token->type == PM_TOKEN_KEYWORD_SELF);
6811 pm_self_node_t *node = PM_NODE_ALLOC(parser, pm_self_node_t);
6813 *node = (pm_self_node_t) {{
6814 .type = PM_SELF_NODE,
6815 .node_id = PM_NODE_IDENTIFY(parser),
6816 .location = PM_LOCATION_TOKEN_VALUE(token)
6825static pm_shareable_constant_node_t *
6826pm_shareable_constant_node_create(pm_parser_t *parser, pm_node_t *write, pm_shareable_constant_value_t value) {
6827 pm_shareable_constant_node_t *node = PM_NODE_ALLOC(parser, pm_shareable_constant_node_t);
6829 *node = (pm_shareable_constant_node_t) {
6831 .type = PM_SHAREABLE_CONSTANT_NODE,
6832 .flags = (pm_node_flags_t) value,
6833 .node_id = PM_NODE_IDENTIFY(parser),
6834 .location = PM_LOCATION_NODE_VALUE(write)
6845static pm_singleton_class_node_t *
6846pm_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) {
6847 pm_singleton_class_node_t *node = PM_NODE_ALLOC(parser, pm_singleton_class_node_t);
6849 *node = (pm_singleton_class_node_t) {
6851 .type = PM_SINGLETON_CLASS_NODE,
6852 .node_id = PM_NODE_IDENTIFY(parser),
6854 .start = class_keyword->start,
6855 .end = end_keyword->end
6859 .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
6860 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6861 .expression = expression,
6863 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
6872static pm_source_encoding_node_t *
6873pm_source_encoding_node_create(pm_parser_t *parser, const pm_token_t *token) {
6874 assert(token->type == PM_TOKEN_KEYWORD___ENCODING__);
6875 pm_source_encoding_node_t *node = PM_NODE_ALLOC(parser, pm_source_encoding_node_t);
6877 *node = (pm_source_encoding_node_t) {{
6878 .type = PM_SOURCE_ENCODING_NODE,
6879 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6880 .node_id = PM_NODE_IDENTIFY(parser),
6881 .location = PM_LOCATION_TOKEN_VALUE(token)
6890static pm_source_file_node_t*
6891pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword) {
6892 pm_source_file_node_t *node = PM_NODE_ALLOC(parser, pm_source_file_node_t);
6893 assert(file_keyword->type == PM_TOKEN_KEYWORD___FILE__);
6895 pm_node_flags_t flags = 0;
6897 switch (parser->frozen_string_literal) {
6898 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6899 flags |= PM_STRING_FLAGS_MUTABLE;
6901 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6902 flags |= PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6906 *node = (pm_source_file_node_t) {
6908 .type = PM_SOURCE_FILE_NODE,
6910 .node_id = PM_NODE_IDENTIFY(parser),
6911 .location = PM_LOCATION_TOKEN_VALUE(file_keyword),
6913 .filepath = parser->filepath
6922static pm_source_line_node_t *
6923pm_source_line_node_create(pm_parser_t *parser, const pm_token_t *token) {
6924 assert(token->type == PM_TOKEN_KEYWORD___LINE__);
6925 pm_source_line_node_t *node = PM_NODE_ALLOC(parser, pm_source_line_node_t);
6927 *node = (pm_source_line_node_t) {{
6928 .type = PM_SOURCE_LINE_NODE,
6929 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6930 .node_id = PM_NODE_IDENTIFY(parser),
6931 .location = PM_LOCATION_TOKEN_VALUE(token)
6940static pm_splat_node_t *
6941pm_splat_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
6942 pm_splat_node_t *node = PM_NODE_ALLOC(parser, pm_splat_node_t);
6944 *node = (pm_splat_node_t) {
6946 .type = PM_SPLAT_NODE,
6947 .node_id = PM_NODE_IDENTIFY(parser),
6949 .start = operator->start,
6950 .end = (expression == NULL ? operator->end : expression->location.end)
6953 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6954 .expression = expression
6963static pm_statements_node_t *
6964pm_statements_node_create(pm_parser_t *parser) {
6965 pm_statements_node_t *node = PM_NODE_ALLOC(parser, pm_statements_node_t);
6967 *node = (pm_statements_node_t) {
6969 .type = PM_STATEMENTS_NODE,
6970 .node_id = PM_NODE_IDENTIFY(parser),
6971 .location = PM_LOCATION_NULL_VALUE(parser)
6983pm_statements_node_body_length(pm_statements_node_t *node) {
6984 return node && node->body.size;
6991pm_statements_node_location_set(pm_statements_node_t *node, const uint8_t *start, const uint8_t *end) {
6992 node->base.location = (pm_location_t) { .start = start, .end = end };
7000pm_statements_node_body_update(pm_statements_node_t *node, pm_node_t *statement) {
7001 if (pm_statements_node_body_length(node) == 0 || statement->location.start < node->base.location.start) {
7002 node->base.location.start = statement->location.start;
7005 if (statement->location.end > node->base.location.end) {
7006 node->base.location.end = statement->location.end;
7014pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline) {
7015 pm_statements_node_body_update(node, statement);
7017 if (node->body.size > 0) {
7018 const pm_node_t *previous = node->body.nodes[node->body.size - 1];
7020 switch (PM_NODE_TYPE(previous)) {
7025 case PM_RETURN_NODE:
7026 pm_parser_warn_node(parser, statement, PM_WARN_UNREACHABLE_STATEMENT);
7033 pm_node_list_append(&node->body, statement);
7034 if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
7041pm_statements_node_body_prepend(pm_statements_node_t *node, pm_node_t *statement) {
7042 pm_statements_node_body_update(node, statement);
7043 pm_node_list_prepend(&node->body, statement);
7044 pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
7050static inline pm_string_node_t *
7051pm_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) {
7052 pm_string_node_t *node = PM_NODE_ALLOC(parser, pm_string_node_t);
7053 pm_node_flags_t flags = 0;
7055 switch (parser->frozen_string_literal) {
7056 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
7057 flags = PM_STRING_FLAGS_MUTABLE;
7059 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
7060 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
7064 *node = (pm_string_node_t) {
7066 .type = PM_STRING_NODE,
7068 .node_id = PM_NODE_IDENTIFY(parser),
7070 .start = (opening->type == PM_TOKEN_NOT_PROVIDED ? content->start : opening->start),
7071 .end = (closing->type == PM_TOKEN_NOT_PROVIDED ? content->end : closing->end)
7074 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7075 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
7076 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7077 .unescaped = *string
7086static pm_string_node_t *
7087pm_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7088 return pm_string_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7095static pm_string_node_t *
7096pm_string_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7097 pm_string_node_t *node = pm_string_node_create_unescaped(parser, opening, content, closing, &parser->current_string);
7098 parser->current_string = PM_STRING_EMPTY;
7105static pm_super_node_t *
7106pm_super_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_t *arguments) {
7107 assert(keyword->type == PM_TOKEN_KEYWORD_SUPER);
7108 pm_super_node_t *node = PM_NODE_ALLOC(parser, pm_super_node_t);
7110 const uint8_t *end = pm_arguments_end(arguments);
7112 assert(false && "unreachable");
7115 *node = (pm_super_node_t) {
7117 .type = PM_SUPER_NODE,
7118 .node_id = PM_NODE_IDENTIFY(parser),
7120 .start = keyword->start,
7124 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7125 .lparen_loc = arguments->opening_loc,
7126 .arguments = arguments->arguments,
7127 .rparen_loc = arguments->closing_loc,
7128 .block = arguments->block
7139pm_ascii_only_p(const pm_string_t *contents) {
7140 const size_t length = pm_string_length(contents);
7141 const uint8_t *source = pm_string_source(contents);
7143 for (size_t index = 0; index < length; index++) {
7144 if (source[index] & 0x80) return false;
7154parse_symbol_encoding_validate_utf8(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
7155 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
7156 size_t width = pm_encoding_utf_8_char_width(cursor, end - cursor);
7159 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
7172parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
7173 const pm_encoding_t *encoding = parser->encoding;
7175 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
7176 size_t width = encoding->char_width(cursor, end - cursor);
7179 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
7196static inline pm_node_flags_t
7197parse_symbol_encoding(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents, bool validate) {
7198 if (parser->explicit_encoding != NULL) {
7199 // A Symbol may optionally have its encoding explicitly set. This will
7200 // happen if an escape sequence results in a non-ASCII code point.
7201 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7202 if (validate) parse_symbol_encoding_validate_utf8(parser, location, contents);
7203 return PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING;
7204 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7205 return PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING;
7206 } else if (validate) {
7207 parse_symbol_encoding_validate_other(parser, location, contents);
7209 } else if (pm_ascii_only_p(contents)) {
7210 // Ruby stipulates that all source files must use an ASCII-compatible
7211 // encoding. Thus, all symbols appearing in source are eligible for
7212 // "downgrading" to US-ASCII.
7213 return PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING;
7214 } else if (validate) {
7215 parse_symbol_encoding_validate_other(parser, location, contents);
7221static pm_node_flags_t
7222parse_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) {
7223 assert ((modifier == 'n' && modifier_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) ||
7224 (modifier == 'u' && modifier_encoding == PM_ENCODING_UTF_8_ENTRY) ||
7225 (modifier == 'e' && modifier_encoding == PM_ENCODING_EUC_JP_ENTRY) ||
7226 (modifier == 's' && modifier_encoding == PM_ENCODING_WINDOWS_31J_ENTRY));
7228 // There's special validation logic used if a string does not contain any character escape sequences.
7229 if (parser->explicit_encoding == NULL) {
7230 // If an ASCII-only string without character escapes is used with an encoding modifier, then resulting Regexp
7231 // has the modifier encoding, unless the ASCII-8BIT modifier is used, in which case the Regexp "downgrades" to
7232 // the US-ASCII encoding.
7234 return modifier == 'n' ? PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING : flags;
7237 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7239 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
7241 } else if (parser->encoding != modifier_encoding) {
7242 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_ENCODING_OPTION_MISMATCH, modifier, parser->encoding->name);
7244 if (modifier == 'n' && !ascii_only) {
7245 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));
7252 // 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.
7253 bool mixed_encoding = false;
7255 if (mixed_encoding) {
7256 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
7257 } else if (modifier != 'n' && parser->explicit_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) {
7258 // 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.
7259 bool valid_string_in_modifier_encoding = true;
7261 if (!valid_string_in_modifier_encoding) {
7262 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
7264 } else if (modifier != 'u' && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7265 // 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.
7266 if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
7267 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));
7271 // We've determined the encoding would naturally be EUC-JP and there is no need to force the encoding to anything else.
7281static pm_node_flags_t
7282parse_and_validate_regular_expression_encoding(pm_parser_t *parser, const pm_string_t *source, bool ascii_only, pm_node_flags_t flags) {
7283 // 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.
7284 bool valid_unicode_range = true;
7285 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY && !valid_unicode_range) {
7286 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));
7290 // US-ASCII strings do not admit multi-byte character literals. However, character escape sequences corresponding
7291 // to multi-byte characters are allowed.
7292 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY && parser->explicit_encoding == NULL && !ascii_only) {
7293 // CRuby will continue processing even though a SyntaxError has already been detected. It may result in the
7294 // following error message appearing twice. We do the same for compatibility.
7295 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
7306 if (flags & PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT) {
7307 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'n', PM_ENCODING_ASCII_8BIT_ENTRY);
7310 if (flags & PM_REGULAR_EXPRESSION_FLAGS_UTF_8) {
7311 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'u', PM_ENCODING_UTF_8_ENTRY);
7314 if (flags & PM_REGULAR_EXPRESSION_FLAGS_EUC_JP) {
7315 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'e', PM_ENCODING_EUC_JP_ENTRY);
7318 if (flags & PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J) {
7319 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 's', PM_ENCODING_WINDOWS_31J_ENTRY);
7322 // At this point no encoding modifiers will be present on the regular expression as they would have already
7323 // been processed. Ruby stipulates that all source files must use an ASCII-compatible encoding. Thus, all
7324 // regular expressions without an encoding modifier appearing in source are eligible for "downgrading" to US-ASCII.
7326 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING;
7329 // A Regexp may optionally have its encoding explicitly set via a character escape sequence in the source string
7330 // or by specifying a modifier.
7332 // NB: an explicitly set encoding is ignored by Ruby if the Regexp consists of only US ASCII code points.
7333 if (parser->explicit_encoding != NULL) {
7334 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7335 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING;
7336 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7337 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING;
7348static pm_symbol_node_t *
7349pm_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) {
7350 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7352 *node = (pm_symbol_node_t) {
7354 .type = PM_SYMBOL_NODE,
7355 .flags = PM_NODE_FLAG_STATIC_LITERAL | flags,
7356 .node_id = PM_NODE_IDENTIFY(parser),
7358 .start = (opening->type == PM_TOKEN_NOT_PROVIDED ? value->start : opening->start),
7359 .end = (closing->type == PM_TOKEN_NOT_PROVIDED ? value->end : closing->end)
7362 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7363 .value_loc = PM_LOCATION_TOKEN_VALUE(value),
7364 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7365 .unescaped = *unescaped
7374static inline pm_symbol_node_t *
7375pm_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
7376 return pm_symbol_node_create_unescaped(parser, opening, value, closing, &PM_STRING_EMPTY, 0);
7382static pm_symbol_node_t *
7383pm_symbol_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
7384 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));
7385 parser->current_string = PM_STRING_EMPTY;
7392static pm_symbol_node_t *
7393pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
7394 pm_symbol_node_t *node;
7396 switch (token->type) {
7397 case PM_TOKEN_LABEL: {
7398 pm_token_t opening = not_provided(parser);
7399 pm_token_t closing = { .type = PM_TOKEN_LABEL_END, .start = token->end - 1, .end = token->end };
7401 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end - 1 };
7402 node = pm_symbol_node_create(parser, &opening, &label, &closing);
7404 assert((label.end - label.start) >= 0);
7405 pm_string_shared_init(&node->unescaped, label.start, label.end);
7406 pm_node_flag_set((pm_node_t *) node, parse_symbol_encoding(parser, &label, &node->unescaped, false));
7410 case PM_TOKEN_MISSING: {
7411 pm_token_t opening = not_provided(parser);
7412 pm_token_t closing = not_provided(parser);
7414 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end };
7415 node = pm_symbol_node_create(parser, &opening, &label, &closing);
7419 assert(false && "unreachable");
7430static pm_symbol_node_t *
7431pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
7432 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7434 *node = (pm_symbol_node_t) {
7436 .type = PM_SYMBOL_NODE,
7437 .flags = PM_NODE_FLAG_STATIC_LITERAL | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING,
7438 .node_id = PM_NODE_IDENTIFY(parser),
7439 .location = PM_LOCATION_NULL_VALUE(parser)
7441 .value_loc = PM_LOCATION_NULL_VALUE(parser),
7445 pm_string_constant_init(&node->unescaped, content, strlen(content));
7453pm_symbol_node_label_p(pm_node_t *node) {
7454 const uint8_t *end = NULL;
7456 switch (PM_NODE_TYPE(node)) {
7457 case PM_SYMBOL_NODE:
7458 end = ((pm_symbol_node_t *) node)->closing_loc.end;
7460 case PM_INTERPOLATED_SYMBOL_NODE:
7461 end = ((pm_interpolated_symbol_node_t *) node)->closing_loc.end;
7467 return (end != NULL) && (end[-1] == ':');
7473static pm_symbol_node_t *
7474pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const pm_token_t *opening, const pm_token_t *closing) {
7475 pm_symbol_node_t *new_node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7477 *new_node = (pm_symbol_node_t) {
7479 .type = PM_SYMBOL_NODE,
7480 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7481 .node_id = PM_NODE_IDENTIFY(parser),
7483 .start = opening->start,
7487 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7488 .value_loc = node->content_loc,
7489 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7490 .unescaped = node->unescaped
7493 pm_token_t content = { .type = PM_TOKEN_IDENTIFIER, .start = node->content_loc.start, .end = node->content_loc.end };
7494 pm_node_flag_set((pm_node_t *) new_node, parse_symbol_encoding(parser, &content, &node->unescaped, true));
7496 // We are explicitly _not_ using pm_node_destroy here because we don't want
7497 // to trash the unescaped string. We could instead copy the string if we
7498 // know that it is owned, but we're taking the fast path for now.
7507static pm_string_node_t *
7508pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
7509 pm_string_node_t *new_node = PM_NODE_ALLOC(parser, pm_string_node_t);
7510 pm_node_flags_t flags = 0;
7512 switch (parser->frozen_string_literal) {
7513 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
7514 flags = PM_STRING_FLAGS_MUTABLE;
7516 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
7517 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
7521 *new_node = (pm_string_node_t) {
7523 .type = PM_STRING_NODE,
7525 .node_id = PM_NODE_IDENTIFY(parser),
7526 .location = node->base.location
7528 .opening_loc = node->opening_loc,
7529 .content_loc = node->value_loc,
7530 .closing_loc = node->closing_loc,
7531 .unescaped = node->unescaped
7534 // We are explicitly _not_ using pm_node_destroy here because we don't want
7535 // to trash the unescaped string. We could instead copy the string if we
7536 // know that it is owned, but we're taking the fast path for now.
7545static pm_true_node_t *
7546pm_true_node_create(pm_parser_t *parser, const pm_token_t *token) {
7547 assert(token->type == PM_TOKEN_KEYWORD_TRUE);
7548 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
7550 *node = (pm_true_node_t) {{
7551 .type = PM_TRUE_NODE,
7552 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7553 .node_id = PM_NODE_IDENTIFY(parser),
7554 .location = PM_LOCATION_TOKEN_VALUE(token)
7563static pm_true_node_t *
7564pm_true_node_synthesized_create(pm_parser_t *parser) {
7565 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
7567 *node = (pm_true_node_t) {{
7568 .type = PM_TRUE_NODE,
7569 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7570 .node_id = PM_NODE_IDENTIFY(parser),
7571 .location = { .start = parser->start, .end = parser->end }
7580static pm_undef_node_t *
7581pm_undef_node_create(pm_parser_t *parser, const pm_token_t *token) {
7582 assert(token->type == PM_TOKEN_KEYWORD_UNDEF);
7583 pm_undef_node_t *node = PM_NODE_ALLOC(parser, pm_undef_node_t);
7585 *node = (pm_undef_node_t) {
7587 .type = PM_UNDEF_NODE,
7588 .node_id = PM_NODE_IDENTIFY(parser),
7589 .location = PM_LOCATION_TOKEN_VALUE(token),
7591 .keyword_loc = PM_LOCATION_TOKEN_VALUE(token),
7602pm_undef_node_append(pm_undef_node_t *node, pm_node_t *name) {
7603 node->base.location.end = name->location.end;
7604 pm_node_list_append(&node->names, name);
7610static pm_unless_node_t *
7611pm_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) {
7612 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7613 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
7616 if (statements != NULL) {
7617 end = statements->base.location.end;
7619 end = predicate->location.end;
7622 *node = (pm_unless_node_t) {
7624 .type = PM_UNLESS_NODE,
7625 .flags = PM_NODE_FLAG_NEWLINE,
7626 .node_id = PM_NODE_IDENTIFY(parser),
7628 .start = keyword->start,
7632 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7633 .predicate = predicate,
7634 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
7635 .statements = statements,
7636 .else_clause = NULL,
7637 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
7646static pm_unless_node_t *
7647pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *unless_keyword, pm_node_t *predicate) {
7648 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7649 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
7651 pm_statements_node_t *statements = pm_statements_node_create(parser);
7652 pm_statements_node_body_append(parser, statements, statement, true);
7654 *node = (pm_unless_node_t) {
7656 .type = PM_UNLESS_NODE,
7657 .flags = PM_NODE_FLAG_NEWLINE,
7658 .node_id = PM_NODE_IDENTIFY(parser),
7660 .start = statement->location.start,
7661 .end = predicate->location.end
7664 .keyword_loc = PM_LOCATION_TOKEN_VALUE(unless_keyword),
7665 .predicate = predicate,
7666 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7667 .statements = statements,
7668 .else_clause = NULL,
7669 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
7676pm_unless_node_end_keyword_loc_set(pm_unless_node_t *node, const pm_token_t *end_keyword) {
7677 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
7678 node->base.location.end = end_keyword->end;
7687pm_loop_modifier_block_exits(pm_parser_t *parser, pm_statements_node_t *statements) {
7688 assert(parser->current_block_exits != NULL);
7690 // All of the block exits that we want to remove should be within the
7691 // statements, and since we are modifying the statements, we shouldn't have
7692 // to check the end location.
7693 const uint8_t *start = statements->base.location.start;
7695 for (size_t index = parser->current_block_exits->size; index > 0; index--) {
7696 pm_node_t *block_exit = parser->current_block_exits->nodes[index - 1];
7697 if (block_exit->location.start < start) break;
7699 // Implicitly remove from the list by lowering the size.
7700 parser->current_block_exits->size--;
7707static pm_until_node_t *
7708pm_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) {
7709 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
7710 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7712 *node = (pm_until_node_t) {
7714 .type = PM_UNTIL_NODE,
7716 .node_id = PM_NODE_IDENTIFY(parser),
7718 .start = keyword->start,
7719 .end = closing->end,
7722 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7723 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
7724 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7725 .predicate = predicate,
7726 .statements = statements
7735static pm_until_node_t *
7736pm_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) {
7737 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
7738 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7739 pm_loop_modifier_block_exits(parser, statements);
7741 *node = (pm_until_node_t) {
7743 .type = PM_UNTIL_NODE,
7745 .node_id = PM_NODE_IDENTIFY(parser),
7747 .start = statements->base.location.start,
7748 .end = predicate->location.end,
7751 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7752 .do_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7753 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7754 .predicate = predicate,
7755 .statements = statements
7764static pm_when_node_t *
7765pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
7766 pm_when_node_t *node = PM_NODE_ALLOC(parser, pm_when_node_t);
7768 *node = (pm_when_node_t) {
7770 .type = PM_WHEN_NODE,
7771 .node_id = PM_NODE_IDENTIFY(parser),
7773 .start = keyword->start,
7777 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7779 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7790pm_when_node_conditions_append(pm_when_node_t *node, pm_node_t *condition) {
7791 node->base.location.end = condition->location.end;
7792 pm_node_list_append(&node->conditions, condition);
7799pm_when_node_then_keyword_loc_set(pm_when_node_t *node, const pm_token_t *then_keyword) {
7800 node->base.location.end = then_keyword->end;
7801 node->then_keyword_loc = PM_LOCATION_TOKEN_VALUE(then_keyword);
7808pm_when_node_statements_set(pm_when_node_t *node, pm_statements_node_t *statements) {
7809 if (statements->base.location.end > node->base.location.end) {
7810 node->base.location.end = statements->base.location.end;
7813 node->statements = statements;
7819static pm_while_node_t *
7820pm_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) {
7821 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7822 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7824 *node = (pm_while_node_t) {
7826 .type = PM_WHILE_NODE,
7828 .node_id = PM_NODE_IDENTIFY(parser),
7830 .start = keyword->start,
7834 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7835 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
7836 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7837 .predicate = predicate,
7838 .statements = statements
7847static pm_while_node_t *
7848pm_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) {
7849 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7850 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7851 pm_loop_modifier_block_exits(parser, statements);
7853 *node = (pm_while_node_t) {
7855 .type = PM_WHILE_NODE,
7857 .node_id = PM_NODE_IDENTIFY(parser),
7859 .start = statements->base.location.start,
7860 .end = predicate->location.end
7863 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7864 .do_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7865 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7866 .predicate = predicate,
7867 .statements = statements
7876static pm_while_node_t *
7877pm_while_node_synthesized_create(pm_parser_t *parser, pm_node_t *predicate, pm_statements_node_t *statements) {
7878 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7880 *node = (pm_while_node_t) {
7882 .type = PM_WHILE_NODE,
7883 .node_id = PM_NODE_IDENTIFY(parser),
7884 .location = PM_LOCATION_NULL_VALUE(parser)
7886 .keyword_loc = PM_LOCATION_NULL_VALUE(parser),
7887 .do_keyword_loc = PM_LOCATION_NULL_VALUE(parser),
7888 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
7889 .predicate = predicate,
7890 .statements = statements
7900static pm_x_string_node_t *
7901pm_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) {
7902 pm_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_x_string_node_t);
7904 *node = (pm_x_string_node_t) {
7906 .type = PM_X_STRING_NODE,
7907 .flags = PM_STRING_FLAGS_FROZEN,
7908 .node_id = PM_NODE_IDENTIFY(parser),
7910 .start = opening->start,
7914 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
7915 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
7916 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
7917 .unescaped = *unescaped
7926static inline pm_x_string_node_t *
7927pm_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7928 return pm_xstring_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7934static pm_yield_node_t *
7935pm_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) {
7936 pm_yield_node_t *node = PM_NODE_ALLOC(parser, pm_yield_node_t);
7939 if (rparen_loc->start != NULL) {
7940 end = rparen_loc->end;
7941 } else if (arguments != NULL) {
7942 end = arguments->base.location.end;
7943 } else if (lparen_loc->start != NULL) {
7944 end = lparen_loc->end;
7949 *node = (pm_yield_node_t) {
7951 .type = PM_YIELD_NODE,
7952 .node_id = PM_NODE_IDENTIFY(parser),
7954 .start = keyword->start,
7958 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7959 .lparen_loc = *lparen_loc,
7960 .arguments = arguments,
7961 .rparen_loc = *rparen_loc
7968#undef PM_NODE_IDENTIFY
7975pm_parser_local_depth_constant_id(pm_parser_t *parser, pm_constant_id_t constant_id) {
7976 pm_scope_t *scope = parser->current_scope;
7979 while (scope != NULL) {
7980 if (pm_locals_find(&scope->locals, constant_id) != UINT32_MAX) return depth;
7981 if (scope->closed) break;
7983 scope = scope->previous;
7996pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
7997 return pm_parser_local_depth_constant_id(parser, pm_parser_constant_id_token(parser, token));
8004pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id, const uint8_t *start, const uint8_t *end, uint32_t reads) {
8005 pm_locals_write(&parser->current_scope->locals, constant_id, start, end, reads);
8011static pm_constant_id_t
8012pm_parser_local_add_location(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, uint32_t reads) {
8013 pm_constant_id_t constant_id = pm_parser_constant_id_location(parser, start, end);
8014 if (constant_id != 0) pm_parser_local_add(parser, constant_id, start, end, reads);
8021static inline pm_constant_id_t
8022pm_parser_local_add_token(pm_parser_t *parser, pm_token_t *token, uint32_t reads) {
8023 return pm_parser_local_add_location(parser, token->start, token->end, reads);
8029static pm_constant_id_t
8030pm_parser_local_add_owned(pm_parser_t *parser, uint8_t *start, size_t length) {
8031 pm_constant_id_t constant_id = pm_parser_constant_id_owned(parser, start, length);
8032 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
8039static pm_constant_id_t
8040pm_parser_local_add_constant(pm_parser_t *parser, const char *start, size_t length) {
8041 pm_constant_id_t constant_id = pm_parser_constant_id_constant(parser, start, length);
8042 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
8054pm_parser_parameter_name_check(pm_parser_t *parser, const pm_token_t *name) {
8055 // We want to check whether the parameter name is a numbered parameter or
8057 pm_refute_numbered_parameter(parser, name->start, name->end);
8059 // Otherwise we'll fetch the constant id for the parameter name and check
8060 // whether it's already in the current scope.
8061 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, name);
8063 if (pm_locals_find(&parser->current_scope->locals, constant_id) != UINT32_MAX) {
8064 // Add an error if the parameter doesn't start with _ and has been seen before
8065 if ((name->start < name->end) && (*name->start != '_')) {
8066 pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NAME_DUPLICATED);
8077pm_parser_scope_pop(pm_parser_t *parser) {
8078 pm_scope_t *scope = parser->current_scope;
8079 parser->current_scope = scope->previous;
8080 pm_locals_free(&scope->locals);
8081 pm_node_list_free(&scope->implicit_parameters);
8085/******************************************************************************/
8087/******************************************************************************/
8093pm_state_stack_push(pm_state_stack_t *stack, bool value) {
8094 *stack = (*stack << 1) | (value & 1);
8101pm_state_stack_pop(pm_state_stack_t *stack) {
8109pm_state_stack_p(const pm_state_stack_t *stack) {
8114pm_accepts_block_stack_push(pm_parser_t *parser, bool value) {
8115 // Use the negation of the value to prevent stack overflow.
8116 pm_state_stack_push(&parser->accepts_block_stack, !value);
8120pm_accepts_block_stack_pop(pm_parser_t *parser) {
8121 pm_state_stack_pop(&parser->accepts_block_stack);
8125pm_accepts_block_stack_p(pm_parser_t *parser) {
8126 return !pm_state_stack_p(&parser->accepts_block_stack);
8130pm_do_loop_stack_push(pm_parser_t *parser, bool value) {
8131 pm_state_stack_push(&parser->do_loop_stack, value);
8135pm_do_loop_stack_pop(pm_parser_t *parser) {
8136 pm_state_stack_pop(&parser->do_loop_stack);
8140pm_do_loop_stack_p(pm_parser_t *parser) {
8141 return pm_state_stack_p(&parser->do_loop_stack);
8144/******************************************************************************/
8145/* Lexer check helpers */
8146/******************************************************************************/
8152static inline uint8_t
8153peek_at(const pm_parser_t *parser, const uint8_t *cursor) {
8154 if (cursor < parser->end) {
8166static inline uint8_t
8167peek_offset(pm_parser_t *parser, ptrdiff_t offset) {
8168 return peek_at(parser, parser->current.end + offset);
8175static inline uint8_t
8176peek(const pm_parser_t *parser) {
8177 return peek_at(parser, parser->current.end);
8185match(pm_parser_t *parser, uint8_t value) {
8186 if (peek(parser) == value) {
8187 parser->current.end++;
8198match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
8199 if (peek_at(parser, cursor) == '\n') {
8202 if (peek_at(parser, cursor) == '\r' && peek_at(parser, cursor + 1) == '\n') {
8214match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
8215 return match_eol_at(parser, parser->current.end + offset);
8224match_eol(pm_parser_t *parser) {
8225 return match_eol_at(parser, parser->current.end);
8231static inline const uint8_t *
8232next_newline(const uint8_t *cursor, ptrdiff_t length) {
8233 assert(length >= 0);
8235 // Note that it's okay for us to use memchr here to look for \n because none
8236 // of the encodings that we support have \n as a component of a multi-byte
8238 return memchr(cursor, '\n', (size_t) length);
8245ambiguous_operator_p(const pm_parser_t *parser, bool space_seen) {
8246 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));
8254parser_lex_magic_comment_encoding_value(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
8255 const pm_encoding_t *encoding = pm_encoding_find(start, end);
8257 if (encoding != NULL) {
8258 if (parser->encoding != encoding) {
8259 parser->encoding = encoding;
8260 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
8263 parser->encoding_changed = (encoding != PM_ENCODING_UTF_8_ENTRY);
8275parser_lex_magic_comment_encoding(pm_parser_t *parser) {
8276 const uint8_t *cursor = parser->current.start + 1;
8277 const uint8_t *end = parser->current.end;
8279 bool separator = false;
8281 if (end - cursor <= 6) return;
8282 switch (cursor[6]) {
8283 case 'C': case 'c': cursor += 6; continue;
8284 case 'O': case 'o': cursor += 5; continue;
8285 case 'D': case 'd': cursor += 4; continue;
8286 case 'I': case 'i': cursor += 3; continue;
8287 case 'N': case 'n': cursor += 2; continue;
8288 case 'G': case 'g': cursor += 1; continue;
8295 if (pm_char_is_whitespace(*cursor)) break;
8298 if (pm_strncasecmp(cursor - 6, (const uint8_t *) "coding", 6) == 0) break;
8304 if (++cursor >= end) return;
8305 } while (pm_char_is_whitespace(*cursor));
8307 if (separator) break;
8308 if (*cursor != '=' && *cursor != ':') return;
8314 const uint8_t *value_start = cursor;
8315 while ((*cursor == '-' || *cursor == '_' || parser->encoding->alnum_char(cursor, 1)) && ++cursor < end);
8317 if (!parser_lex_magic_comment_encoding_value(parser, value_start, cursor)) {
8318 // If we were unable to parse the encoding value, then we've got an
8319 // issue because we didn't understand the encoding that the user was
8320 // trying to use. In this case we'll keep using the default encoding but
8321 // add an error to the parser to indicate an unsuccessful parse.
8322 pm_parser_err(parser, value_start, cursor, PM_ERR_INVALID_ENCODING_MAGIC_COMMENT);
8327 PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE,
8328 PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE,
8329 PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID
8330} pm_magic_comment_boolean_value_t;
8336static pm_magic_comment_boolean_value_t
8337parser_lex_magic_comment_boolean_value(const uint8_t *value_start, uint32_t value_length) {
8338 if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "true", 4) == 0) {
8339 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE;
8340 } else if (value_length == 5 && pm_strncasecmp(value_start, (const uint8_t *) "false", 5) == 0) {
8341 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE;
8343 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID;
8348pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
8349 return b == '\'' || b == '"' || b == ':' || b == ';';
8357static inline const uint8_t *
8358parser_lex_magic_comment_emacs_marker(
pm_parser_t *parser,
const uint8_t *cursor,
const uint8_t *end) {
8359 while ((cursor + 3 <= end) && (cursor = pm_memchr(cursor,
'-', (
size_t) (end - cursor), parser->
encoding_changed, parser->
encoding)) != NULL) {
8360 if (cursor + 3 <= end && cursor[1] ==
'*' && cursor[2] ==
'-') {
8379parser_lex_magic_comment(
pm_parser_t *parser,
bool semantic_token_seen) {
8382 const uint8_t *start = parser->
current.start + 1;
8383 const uint8_t *end = parser->
current.end;
8384 if (end - start <= 7)
return false;
8386 const uint8_t *cursor;
8387 bool indicator =
false;
8389 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
8392 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
8403 while (cursor < end) {
8404 while (cursor < end && (pm_char_is_magic_comment_key_delimiter(*cursor) || pm_char_is_whitespace(*cursor))) cursor++;
8406 const uint8_t *key_start = cursor;
8407 while (cursor < end && (!pm_char_is_magic_comment_key_delimiter(*cursor) && !pm_char_is_whitespace(*cursor))) cursor++;
8409 const uint8_t *key_end = cursor;
8410 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
8411 if (cursor == end)
break;
8413 if (*cursor ==
':') {
8416 if (!indicator)
return false;
8420 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
8421 if (cursor == end)
break;
8423 const uint8_t *value_start;
8424 const uint8_t *value_end;
8426 if (*cursor ==
'"') {
8427 value_start = ++cursor;
8428 for (; cursor < end && *cursor !=
'"'; cursor++) {
8429 if (*cursor ==
'\\' && (cursor + 1 < end)) cursor++;
8432 if (*cursor ==
'"') cursor++;
8434 value_start = cursor;
8435 while (cursor < end && *cursor !=
'"' && *cursor !=
';' && !pm_char_is_whitespace(*cursor)) cursor++;
8440 while (cursor < end && (*cursor ==
';' || pm_char_is_whitespace(*cursor))) cursor++;
8442 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
8443 if (cursor != end)
return false;
8449 const size_t key_length = (size_t) (key_end - key_start);
8453 pm_string_shared_init(&key, key_start, key_end);
8455 uint8_t *buffer =
xmalloc(key_length);
8456 if (buffer == NULL)
break;
8458 memcpy(buffer, key_start, key_length);
8459 buffer[dash - key_start] =
'_';
8461 while ((dash = pm_memchr(dash + 1,
'-', (
size_t) (key_end - dash - 1), parser->
encoding_changed, parser->
encoding)) != NULL) {
8462 buffer[dash - key_start] =
'_';
8465 pm_string_owned_init(&key, buffer, key_length);
8470 const uint8_t *key_source = pm_string_source(&key);
8471 uint32_t value_length = (uint32_t) (value_end - value_start);
8477 (key_length == 8 && pm_strncasecmp(key_source, (
const uint8_t *)
"encoding", 8) == 0) ||
8478 (key_length == 6 && pm_strncasecmp(key_source, (
const uint8_t *)
"coding", 6) == 0)
8480 result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
8484 if (key_length == 11) {
8485 if (pm_strncasecmp(key_source, (
const uint8_t *)
"warn_indent", 11) == 0) {
8486 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
8487 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
8488 PM_PARSER_WARN_TOKEN_FORMAT(
8491 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8493 (
const char *) key_source,
8495 (
const char *) value_start
8498 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
8501 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
8506 }
else if (key_length == 21) {
8507 if (pm_strncasecmp(key_source, (
const uint8_t *)
"frozen_string_literal", 21) == 0) {
8510 if (semantic_token_seen) {
8511 pm_parser_warn_token(parser, &parser->
current, PM_WARN_IGNORED_FROZEN_STRING_LITERAL);
8513 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
8514 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
8515 PM_PARSER_WARN_TOKEN_FORMAT(
8518 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8520 (
const char *) key_source,
8522 (
const char *) value_start
8525 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
8528 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
8534 }
else if (key_length == 24) {
8535 if (pm_strncasecmp(key_source, (
const uint8_t *)
"shareable_constant_value", 24) == 0) {
8536 const uint8_t *cursor = parser->
current.start;
8537 while ((cursor > parser->
start) && ((cursor[-1] ==
' ') || (cursor[-1] ==
'\t'))) cursor--;
8539 if (!((cursor == parser->
start) || (cursor[-1] ==
'\n'))) {
8540 pm_parser_warn_token(parser, &parser->
current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
8541 }
else if (value_length == 4 && pm_strncasecmp(value_start, (
const uint8_t *)
"none", 4) == 0) {
8542 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
8543 }
else if (value_length == 7 && pm_strncasecmp(value_start, (
const uint8_t *)
"literal", 7) == 0) {
8544 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
8545 }
else if (value_length == 23 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_everything", 23) == 0) {
8546 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING);
8547 }
else if (value_length == 17 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_copy", 17) == 0) {
8548 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY);
8550 PM_PARSER_WARN_TOKEN_FORMAT(
8553 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8555 (
const char *) key_source,
8557 (
const char *) value_start
8565 pm_string_free(&key);
8585static const uint32_t context_terminators[] = {
8587 [
PM_CONTEXT_BEGIN] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8590 [
PM_CONTEXT_BEGIN_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8592 [
PM_CONTEXT_BLOCK_KEYWORDS] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
8595 [
PM_CONTEXT_BLOCK_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8596 [
PM_CONTEXT_CASE_WHEN] = (1 << PM_TOKEN_KEYWORD_WHEN) | (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_ELSE),
8597 [
PM_CONTEXT_CASE_IN] = (1 << PM_TOKEN_KEYWORD_IN) | (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_ELSE),
8598 [
PM_CONTEXT_CLASS] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
8601 [
PM_CONTEXT_CLASS_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8602 [
PM_CONTEXT_DEF] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
8605 [
PM_CONTEXT_DEF_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8610 [
PM_CONTEXT_ELSIF] = (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_ELSIF) | (1 << PM_TOKEN_KEYWORD_END),
8614 [
PM_CONTEXT_IF] = (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_ELSIF) | (1 << PM_TOKEN_KEYWORD_END),
8616 [
PM_CONTEXT_LAMBDA_DO_END] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
8619 [
PM_CONTEXT_LAMBDA_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8622 [
PM_CONTEXT_MODULE] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
8625 [
PM_CONTEXT_MODULE_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8629 [
PM_CONTEXT_PREDICATE] = (1 << PM_TOKEN_KEYWORD_THEN) | (1 << PM_TOKEN_NEWLINE) | (1 << PM_TOKEN_SEMICOLON),
8632 [
PM_CONTEXT_SCLASS] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
8635 [
PM_CONTEXT_SCLASS_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8637 [
PM_CONTEXT_UNLESS] = (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
8644 return token->type < 32 && (context_terminators[context] & (1 << token->type));
8655 while (context_node != NULL) {
8656 if (context_terminator(context_node->
context, token))
return context_node->
context;
8657 context_node = context_node->
prev;
8666 if (context_node == NULL)
return false;
8691 while (context_node != NULL) {
8692 if (context_node->
context == context)
return true;
8693 context_node = context_node->
prev;
8703 while (context_node != NULL) {
8704 switch (context_node->
context) {
8725 context_node = context_node->
prev;
8740 assert(
false &&
"unreachable");
8797 assert(
false &&
"unreachable");
8806pm_strspn_number_validate(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const uint8_t *invalid) {
8807 if (invalid != NULL) {
8808 pm_diagnostic_id_t diag_id = (invalid == (
string + length - 1)) ? PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING : PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER;
8809 pm_parser_err(parser, invalid, invalid + 1, diag_id);
8814pm_strspn_binary_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8815 const uint8_t *invalid = NULL;
8816 size_t length = pm_strspn_binary_number(
string, parser->
end -
string, &invalid);
8817 pm_strspn_number_validate(parser,
string, length, invalid);
8822pm_strspn_octal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8823 const uint8_t *invalid = NULL;
8824 size_t length = pm_strspn_octal_number(
string, parser->
end -
string, &invalid);
8825 pm_strspn_number_validate(parser,
string, length, invalid);
8830pm_strspn_decimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8831 const uint8_t *invalid = NULL;
8832 size_t length = pm_strspn_decimal_number(
string, parser->
end -
string, &invalid);
8833 pm_strspn_number_validate(parser,
string, length, invalid);
8838pm_strspn_hexadecimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8839 const uint8_t *invalid = NULL;
8840 size_t length = pm_strspn_hexadecimal_number(
string, parser->
end -
string, &invalid);
8841 pm_strspn_number_validate(parser,
string, length, invalid);
8845static pm_token_type_t
8846lex_optional_float_suffix(
pm_parser_t *parser,
bool* seen_e) {
8847 pm_token_type_t
type = PM_TOKEN_INTEGER;
8851 if (peek(parser) ==
'.') {
8852 if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8854 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8855 type = PM_TOKEN_FLOAT;
8865 if ((peek(parser) ==
'e') || (peek(parser) ==
'E')) {
8866 if ((peek_offset(parser, 1) ==
'+') || (peek_offset(parser, 1) ==
'-')) {
8869 if (pm_char_is_decimal_digit(peek(parser))) {
8871 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8873 pm_parser_err_current(parser, PM_ERR_INVALID_FLOAT_EXPONENT);
8875 }
else if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8877 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8883 type = PM_TOKEN_FLOAT;
8889static pm_token_type_t
8890lex_numeric_prefix(
pm_parser_t *parser,
bool* seen_e) {
8891 pm_token_type_t
type = PM_TOKEN_INTEGER;
8894 if (peek_offset(parser, -1) ==
'0') {
8895 switch (*parser->
current.end) {
8900 if (pm_char_is_decimal_digit(peek(parser))) {
8901 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8904 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_DECIMAL);
8913 if (pm_char_is_binary_digit(peek(parser))) {
8914 parser->
current.end += pm_strspn_binary_number_validate(parser, parser->
current.end);
8917 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
8927 if (pm_char_is_octal_digit(peek(parser))) {
8928 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8931 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
8947 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8955 if (pm_char_is_hexadecimal_digit(peek(parser))) {
8956 parser->
current.end += pm_strspn_hexadecimal_number_validate(parser, parser->
current.end);
8959 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
8962 parser->
integer_base = PM_INTEGER_BASE_FLAGS_HEXADECIMAL;
8967 type = lex_optional_float_suffix(parser, seen_e);
8974 type = lex_optional_float_suffix(parser, seen_e);
8981 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8984 type = lex_optional_float_suffix(parser, seen_e);
8990 if (peek_offset(parser, 0) ==
'.' && pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8991 const uint8_t *fraction_start = parser->
current.end;
8992 const uint8_t *fraction_end = parser->
current.end + 2;
8993 fraction_end += pm_strspn_decimal_digit(fraction_end, parser->
end - fraction_end);
8994 pm_parser_err(parser, fraction_start, fraction_end, PM_ERR_INVALID_NUMBER_FRACTION);
9000static pm_token_type_t
9002 pm_token_type_t
type = PM_TOKEN_INTEGER;
9006 bool seen_e =
false;
9007 type = lex_numeric_prefix(parser, &seen_e);
9009 const uint8_t *end = parser->
current.end;
9010 pm_token_type_t suffix_type =
type;
9012 if (
type == PM_TOKEN_INTEGER) {
9013 if (match(parser,
'r')) {
9014 suffix_type = PM_TOKEN_INTEGER_RATIONAL;
9016 if (match(parser,
'i')) {
9017 suffix_type = PM_TOKEN_INTEGER_RATIONAL_IMAGINARY;
9019 }
else if (match(parser,
'i')) {
9020 suffix_type = PM_TOKEN_INTEGER_IMAGINARY;
9023 if (!seen_e && match(parser,
'r')) {
9024 suffix_type = PM_TOKEN_FLOAT_RATIONAL;
9026 if (match(parser,
'i')) {
9027 suffix_type = PM_TOKEN_FLOAT_RATIONAL_IMAGINARY;
9029 }
else if (match(parser,
'i')) {
9030 suffix_type = PM_TOKEN_FLOAT_IMAGINARY;
9034 const uint8_t b = peek(parser);
9035 if (b !=
'\0' && (b >= 0x80 || ((b >=
'a' && b <=
'z') || (b >=
'A' && b <=
'Z')) || b ==
'_')) {
9045static pm_token_type_t
9048 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
9049 return PM_TOKEN_GLOBAL_VARIABLE;
9054 bool allow_multiple =
true;
9056 switch (*parser->
current.end) {
9074 return PM_TOKEN_GLOBAL_VARIABLE;
9081 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_BACK_REFERENCE;
9087 if ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0) {
9090 }
while ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0);
9094 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
current, diag_id);
9097 return PM_TOKEN_GLOBAL_VARIABLE;
9110 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_NUMBERED_REFERENCE;
9114 allow_multiple =
false;
9119 if ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0) {
9122 }
while (allow_multiple && (width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0);
9123 }
else if (pm_char_is_whitespace(peek(parser))) {
9126 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
9132 PM_PARSER_ERR_FORMAT(parser, parser->
current.start, end, diag_id, (
int) (end - parser->
current.start), (
const char *) parser->
current.start);
9135 return PM_TOKEN_GLOBAL_VARIABLE;
9152static inline pm_token_type_t
9153lex_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) {
9154 if (memcmp(current_start, value, vlen) == 0) {
9157 if (parser->
lex_state & PM_LEX_STATE_FNAME) {
9158 lex_state_set(parser, PM_LEX_STATE_ENDFN);
9160 lex_state_set(parser, state);
9161 if (state == PM_LEX_STATE_BEG) {
9165 if ((modifier_type != PM_TOKEN_EOF) && !(last_state & (PM_LEX_STATE_BEG | PM_LEX_STATE_LABELED | PM_LEX_STATE_CLASS))) {
9166 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
9167 return modifier_type;
9174 return PM_TOKEN_EOF;
9177static pm_token_type_t
9178lex_identifier(
pm_parser_t *parser,
bool previous_command_start) {
9181 const uint8_t *end = parser->
end;
9182 const uint8_t *current_start = parser->
current.start;
9183 const uint8_t *current_end = parser->
current.end;
9186 if (encoding_changed) {
9187 while ((width = char_is_identifier(parser, current_end, end - current_end)) > 0) {
9188 current_end += width;
9191 while ((width = char_is_identifier_utf8(current_end, end - current_end)) > 0) {
9192 current_end += width;
9195 parser->
current.end = current_end;
9199 width = (size_t) (current_end - current_start);
9201 if (current_end < end) {
9202 if (((current_end + 1 >= end) || (current_end[1] !=
'=')) && (match(parser,
'!') || match(parser,
'?'))) {
9208 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
9209 (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')
9213 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
9214 (void) match(parser,
':');
9215 return PM_TOKEN_LABEL;
9218 if (parser->
lex_state != PM_LEX_STATE_DOT) {
9219 if (width == 8 && (lex_keyword(parser, current_start,
"defined?", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_DEFINED, PM_TOKEN_EOF) != PM_TOKEN_EOF)) {
9220 return PM_TOKEN_KEYWORD_DEFINED;
9224 return PM_TOKEN_METHOD_NAME;
9227 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,
'=')) {
9230 return PM_TOKEN_IDENTIFIER;
9234 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
9235 peek(parser) ==
':' && peek_offset(parser, 1) !=
':'
9239 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
9240 (void) match(parser,
':');
9241 return PM_TOKEN_LABEL;
9245 if (parser->
lex_state != PM_LEX_STATE_DOT) {
9246 pm_token_type_t
type;
9249 if (lex_keyword(parser, current_start,
"do", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_DO, PM_TOKEN_EOF) != PM_TOKEN_EOF) {
9250 if (pm_do_loop_stack_p(parser)) {
9251 return PM_TOKEN_KEYWORD_DO_LOOP;
9253 return PM_TOKEN_KEYWORD_DO;
9256 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;
9257 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;
9258 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;
9261 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;
9262 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;
9263 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;
9264 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;
9265 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;
9266 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;
9267 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;
9270 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;
9271 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;
9272 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;
9273 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;
9274 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;
9275 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;
9276 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;
9277 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;
9280 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;
9281 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;
9282 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;
9283 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;
9284 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;
9285 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;
9286 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;
9287 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;
9288 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;
9289 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;
9290 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;
9291 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;
9292 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;
9295 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;
9296 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;
9297 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;
9298 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;
9299 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;
9302 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;
9303 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;
9306 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;
9311 if (encoding_changed) {
9312 return parser->
encoding->
isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
9314 return pm_encoding_utf_8_isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
9340static pm_token_type_t
9341lex_interpolation(
pm_parser_t *parser,
const uint8_t *pound) {
9344 if (pound + 1 >= parser->
end) {
9345 parser->
current.end = pound + 1;
9346 return PM_TOKEN_STRING_CONTENT;
9355 if (pound + 2 >= parser->
end) {
9356 parser->
current.end = pound + 1;
9357 return PM_TOKEN_STRING_CONTENT;
9362 const uint8_t *variable = pound + 2;
9363 if (*variable ==
'@' && pound + 3 < parser->
end) variable++;
9365 if (char_is_identifier_start(parser, variable, parser->
end - variable)) {
9369 if (pound > parser->
current.start) {
9371 return PM_TOKEN_STRING_CONTENT;
9376 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
9377 parser->
current.end = pound + 1;
9378 return PM_TOKEN_EMBVAR;
9384 parser->
current.end = pound + 1;
9385 return PM_TOKEN_NOT_PROVIDED;
9390 if (pound + 2 >= parser->
end) {
9391 parser->
current.end = pound + 1;
9392 return PM_TOKEN_STRING_CONTENT;
9398 const uint8_t *check = pound + 2;
9400 if (pound[2] ==
'-') {
9401 if (pound + 3 >= parser->
end) {
9402 parser->
current.end = pound + 2;
9403 return PM_TOKEN_STRING_CONTENT;
9414 char_is_identifier_start(parser, check, parser->
end - check) ||
9415 (pound[2] !=
'-' && (pm_char_is_decimal_digit(pound[2]) || char_is_global_name_punctuation(pound[2])))
9420 if (pound > parser->
current.start) {
9422 return PM_TOKEN_STRING_CONTENT;
9427 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
9428 parser->
current.end = pound + 1;
9429 return PM_TOKEN_EMBVAR;
9434 parser->
current.end = pound + 1;
9435 return PM_TOKEN_NOT_PROVIDED;
9440 if (pound > parser->
current.start) {
9442 return PM_TOKEN_STRING_CONTENT;
9449 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBEXPR });
9450 parser->
current.end = pound + 2;
9452 pm_do_loop_stack_push(parser,
false);
9453 return PM_TOKEN_EMBEXPR_BEGIN;
9458 parser->
current.end = pound + 1;
9459 return PM_TOKEN_NOT_PROVIDED;
9463static const uint8_t PM_ESCAPE_FLAG_NONE = 0x0;
9464static const uint8_t PM_ESCAPE_FLAG_CONTROL = 0x1;
9465static const uint8_t PM_ESCAPE_FLAG_META = 0x2;
9466static const uint8_t PM_ESCAPE_FLAG_SINGLE = 0x4;
9467static const uint8_t PM_ESCAPE_FLAG_REGEXP = 0x8;
9472static const bool ascii_printable_chars[] = {
9473 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
9474 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9475 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9476 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9477 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9478 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
9479 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9480 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
9484char_is_ascii_printable(
const uint8_t b) {
9485 return (b < 0x80) && ascii_printable_chars[b];
9492static inline uint8_t
9493escape_hexadecimal_digit(
const uint8_t value) {
9494 return (uint8_t) ((value <=
'9') ? (value -
'0') : (value & 0x7) + 9);
9502static inline uint32_t
9503escape_unicode(
pm_parser_t *parser,
const uint8_t *
string,
size_t length) {
9505 for (
size_t index = 0; index < length; index++) {
9506 if (index != 0) value <<= 4;
9507 value |= escape_hexadecimal_digit(
string[index]);
9512 if (value >= 0xD800 && value <= 0xDFFF) {
9513 pm_parser_err(parser,
string,
string + length, PM_ERR_ESCAPE_INVALID_UNICODE);
9523static inline uint8_t
9524escape_byte(uint8_t value,
const uint8_t flags) {
9525 if (flags & PM_ESCAPE_FLAG_CONTROL) value &= 0x9f;
9526 if (flags & PM_ESCAPE_FLAG_META) value |= 0x80;
9534escape_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) {
9538 if (value >= 0x80 || flags & PM_ESCAPE_FLAG_SINGLE) {
9546 if (!pm_buffer_append_unicode_codepoint(buffer, value)) {
9547 pm_parser_err(parser, start, end, PM_ERR_ESCAPE_INVALID_UNICODE);
9548 pm_buffer_append_byte(buffer, 0xEF);
9549 pm_buffer_append_byte(buffer, 0xBF);
9550 pm_buffer_append_byte(buffer, 0xBD);
9562 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_MIXED_ENCODING, parser->
encoding->
name);
9568 pm_buffer_append_byte(buffer,
byte);
9588 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9589 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X",
byte);
9592 escape_write_byte_encoded(parser, buffer,
byte);
9604 width = pm_encoding_utf_8_char_width(parser->
current.end, parser->
end - parser->
current.end);
9608 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(*parser->
current.end++, flags));
9609 }
else if (width > 1) {
9611 pm_buffer_t *b = (flags & PM_ESCAPE_FLAG_REGEXP) ? regular_expression_buffer : buffer;
9612 pm_buffer_append_bytes(b, parser->
current.end, width);
9618 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9628escape_read_warn(
pm_parser_t *parser, uint8_t flags, uint8_t flag,
const char *
type) {
9629#define FLAG(value) ((value & PM_ESCAPE_FLAG_CONTROL) ? "\\C-" : (value & PM_ESCAPE_FLAG_META) ? "\\M-" : "")
9631 PM_PARSER_WARN_TOKEN_FORMAT(
9634 PM_WARN_INVALID_CHARACTER,
9648 uint8_t peeked = peek(parser);
9652 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\\', flags));
9657 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\'', flags));
9662 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\a', flags));
9667 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\b', flags));
9672 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\033', flags));
9677 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\f', flags));
9682 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\n', flags));
9687 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\r', flags));
9692 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
' ', flags));
9697 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\t', flags));
9702 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\v', flags));
9705 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': {
9706 uint8_t value = (uint8_t) (*parser->
current.end -
'0');
9709 if (pm_char_is_octal_digit(peek(parser))) {
9710 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
9713 if (pm_char_is_octal_digit(peek(parser))) {
9714 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
9719 value = escape_byte(value, flags);
9720 escape_write_byte(parser, buffer, regular_expression_buffer, flags, value);
9724 const uint8_t *start = parser->
current.end - 1;
9727 uint8_t
byte = peek(parser);
9729 if (pm_char_is_hexadecimal_digit(
byte)) {
9730 uint8_t value = escape_hexadecimal_digit(
byte);
9733 byte = peek(parser);
9734 if (pm_char_is_hexadecimal_digit(
byte)) {
9735 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(
byte));
9739 value = escape_byte(value, flags);
9740 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9741 if (flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) {
9742 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X", value);
9744 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9748 escape_write_byte_encoded(parser, buffer, value);
9750 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
9756 const uint8_t *start = parser->
current.end - 1;
9760 const uint8_t *start = parser->
current.end - 2;
9761 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9762 }
else if (peek(parser) ==
'{') {
9763 const uint8_t *unicode_codepoints_start = parser->
current.end - 2;
9768 if ((whitespace = pm_strspn_inline_whitespace(parser->
current.end, parser->
end - parser->
current.end)) > 0) {
9769 parser->
current.end += whitespace;
9770 }
else if (peek(parser) ==
'\\' && peek_offset(parser, 1) ==
'n') {
9781 const uint8_t *extra_codepoints_start = NULL;
9782 int codepoints_count = 0;
9785 const uint8_t *unicode_start = parser->
current.end;
9786 size_t hexadecimal_length = pm_strspn_hexadecimal_digit(parser->
current.end, parser->
end - parser->
current.end);
9788 if (hexadecimal_length > 6) {
9790 pm_parser_err(parser, unicode_start, unicode_start + hexadecimal_length, PM_ERR_ESCAPE_INVALID_UNICODE_LONG);
9791 }
else if (hexadecimal_length == 0) {
9794 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9798 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9800 pm_parser_err(parser, parser->
current.end, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE);
9801 pm_parser_err(parser, parser->
current.end, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9807 parser->
current.end += hexadecimal_length;
9809 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count == 2) {
9810 extra_codepoints_start = unicode_start;
9813 uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length);
9814 escape_write_unicode(parser, buffer, flags, unicode_start, parser->
current.end, value);
9821 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count > 1) {
9822 pm_parser_err(parser, extra_codepoints_start, parser->
current.end - 1, PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL);
9826 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_LIST, (
int) (parser->
current.end - start), start);
9827 }
else if (peek(parser) ==
'}') {
9830 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9834 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9836 pm_parser_err(parser, unicode_codepoints_start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9840 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9841 pm_buffer_append_bytes(regular_expression_buffer, unicode_codepoints_start, (
size_t) (parser->
current.end - unicode_codepoints_start));
9844 size_t length = pm_strspn_hexadecimal_digit(parser->
current.end, MIN(parser->
end - parser->
current.end, 4));
9847 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9848 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9850 const uint8_t *start = parser->
current.end - 2;
9851 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9853 }
else if (length == 4) {
9854 uint32_t value = escape_unicode(parser, parser->
current.end, 4);
9856 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9857 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end + 4 - start));
9860 escape_write_unicode(parser, buffer, flags, start, parser->
current.end + 4, value);
9863 parser->
current.end += length;
9865 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9869 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9871 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_UNICODE);
9880 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9881 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9885 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9889 uint8_t peeked = peek(parser);
9893 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9899 if (match(parser,
'u') || match(parser,
'U')) {
9900 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9904 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9908 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9909 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9913 escape_read_warn(parser, flags, 0,
"\\t");
9914 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9917 if (!char_is_ascii_printable(peeked)) {
9918 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9923 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9930 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9931 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9934 if (peek(parser) !=
'-') {
9936 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9942 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9946 uint8_t peeked = peek(parser);
9950 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9956 if (match(parser,
'u') || match(parser,
'U')) {
9957 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9961 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9965 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9966 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9970 escape_read_warn(parser, flags, 0,
"\\t");
9971 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9974 if (!char_is_ascii_printable(peeked)) {
9976 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9981 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9988 if (flags & PM_ESCAPE_FLAG_META) {
9989 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META_REPEAT);
9992 if (peek(parser) !=
'-') {
9994 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
10000 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
10004 uint8_t peeked = peek(parser);
10009 if (match(parser,
'u') || match(parser,
'U')) {
10010 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
10014 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_META);
10018 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_META,
"\\s");
10019 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10023 escape_read_warn(parser, flags & ((uint8_t) ~PM_ESCAPE_FLAG_CONTROL), PM_ESCAPE_FLAG_META,
"\\t");
10024 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10027 if (!char_is_ascii_printable(peeked)) {
10029 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
10034 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10039 if (peek_offset(parser, 1) ==
'\n') {
10041 escape_write_byte_encoded(parser, buffer, escape_byte(
'\n', flags));
10047 if ((flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) && !char_is_ascii_printable(peeked)) {
10049 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
10053 escape_write_escape_encoded(parser, buffer, regular_expression_buffer, flags);
10055 pm_parser_err_current(parser, PM_ERR_INVALID_ESCAPE_CHARACTER);
10087static pm_token_type_t
10089 if (lex_state_end_p(parser)) {
10090 lex_state_set(parser, PM_LEX_STATE_BEG);
10091 return PM_TOKEN_QUESTION_MARK;
10095 pm_parser_err_current(parser, PM_ERR_INCOMPLETE_QUESTION_MARK);
10097 return PM_TOKEN_CHARACTER_LITERAL;
10100 if (pm_char_is_whitespace(*parser->
current.end)) {
10101 lex_state_set(parser, PM_LEX_STATE_BEG);
10102 return PM_TOKEN_QUESTION_MARK;
10105 lex_state_set(parser, PM_LEX_STATE_BEG);
10107 if (match(parser,
'\\')) {
10108 lex_state_set(parser, PM_LEX_STATE_END);
10111 pm_buffer_init_capacity(&buffer, 3);
10113 escape_read(parser, &buffer, NULL, PM_ESCAPE_FLAG_SINGLE);
10116 return PM_TOKEN_CHARACTER_LITERAL;
10125 (parser->
current.end + encoding_width >= parser->
end) ||
10126 !char_is_identifier(parser, parser->
current.end + encoding_width, parser->
end - (parser->
current.end + encoding_width))
10129 lex_state_set(parser, PM_LEX_STATE_END);
10130 parser->
current.end += encoding_width;
10132 return PM_TOKEN_CHARACTER_LITERAL;
10136 return PM_TOKEN_QUESTION_MARK;
10143static pm_token_type_t
10145 pm_token_type_t
type = match(parser,
'@') ? PM_TOKEN_CLASS_VARIABLE : PM_TOKEN_INSTANCE_VARIABLE;
10146 const uint8_t *end = parser->
end;
10149 if ((width = char_is_identifier_start(parser, parser->
current.end, end - parser->
current.end)) > 0) {
10150 parser->
current.end += width;
10152 while ((width = char_is_identifier(parser, parser->
current.end, end - parser->
current.end)) > 0) {
10153 parser->
current.end += width;
10155 }
else if (parser->
current.end < end && pm_char_is_decimal_digit(*parser->
current.end)) {
10156 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE;
10158 diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS_3_3 : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE_3_3;
10162 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, diag_id, (
int) ((parser->
current.end + width) - parser->
current.start), (
const char *) parser->
current.start);
10164 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_CLASS_VARIABLE_BARE : PM_ERR_INSTANCE_VARIABLE_BARE;
10165 pm_parser_err_token(parser, &parser->
current, diag_id);
10171 lex_mode_pop(parser);
10193 if (comment == NULL)
return NULL;
10208static pm_token_type_t
10211 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10213 if (newline == NULL) {
10216 pm_newline_list_append(&parser->
newline_list, newline);
10217 parser->
current.end = newline + 1;
10220 parser->
current.type = PM_TOKEN_EMBDOC_BEGIN;
10221 parser_lex_callback(parser);
10224 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_EMBDOC);
10225 if (comment == NULL)
return PM_TOKEN_EOF;
10229 while (parser->
current.end + 4 <= parser->
end) {
10235 (memcmp(parser->
current.end,
"=end", 4) == 0) &&
10238 pm_char_is_whitespace(parser->
current.end[4]) ||
10239 (parser->
current.end[4] ==
'\0') ||
10240 (parser->
current.end[4] ==
'\004') ||
10241 (parser->
current.end[4] ==
'\032')
10244 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10246 if (newline == NULL) {
10249 pm_newline_list_append(&parser->
newline_list, newline);
10250 parser->
current.end = newline + 1;
10253 parser->
current.type = PM_TOKEN_EMBDOC_END;
10254 parser_lex_callback(parser);
10259 return PM_TOKEN_EMBDOC_END;
10264 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10266 if (newline == NULL) {
10269 pm_newline_list_append(&parser->
newline_list, newline);
10270 parser->
current.end = newline + 1;
10273 parser->
current.type = PM_TOKEN_EMBDOC_LINE;
10274 parser_lex_callback(parser);
10277 pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
10282 return PM_TOKEN_EOF;
10292 parser->
current.type = PM_TOKEN_IGNORED_NEWLINE;
10293 parser_lex_callback(parser);
10317 const uint8_t *cursor = parser->
current.end;
10319 while (cursor < parser->end && *cursor !=
'\n' && *cursor !=
'#') {
10320 if (!pm_char_is_inline_whitespace(*cursor++))
return false;
10383 pm_buffer_append_byte(&token_buffer->
buffer,
byte);
10394static inline size_t
10400 width = pm_encoding_utf_8_char_width(parser->
current.end, parser->
end - parser->
current.end);
10405 return (width == 0 ? 1 : width);
10413 size_t width = parser_char_width(parser);
10414 pm_buffer_append_bytes(&token_buffer->
buffer, parser->
current.end, width);
10415 parser->
current.end += width;
10420 size_t width = parser_char_width(parser);
10421 pm_buffer_append_bytes(&token_buffer->
base.
buffer, parser->
current.end, width);
10423 parser->
current.end += width;
10427pm_slice_ascii_only_p(
const uint8_t *value,
size_t length) {
10428 for (
size_t index = 0; index < length; index++) {
10429 if (value[index] & 0x80)
return false;
10443 pm_string_owned_init(&parser->
current_string, (uint8_t *) pm_buffer_value(&token_buffer->
buffer), pm_buffer_length(&token_buffer->
buffer));
10464 if (token_buffer->
cursor == NULL) {
10467 pm_buffer_append_bytes(&token_buffer->
buffer, token_buffer->
cursor, (
size_t) (parser->
current.end - token_buffer->
cursor));
10468 pm_token_buffer_copy(parser, token_buffer);
10480 pm_regexp_token_buffer_copy(parser, token_buffer);
10484#define PM_TOKEN_BUFFER_DEFAULT_SIZE 16
10496 const uint8_t *start;
10497 if (token_buffer->
cursor == NULL) {
10498 pm_buffer_init_capacity(&token_buffer->
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10499 start = parser->
current.start;
10501 start = token_buffer->
cursor;
10504 const uint8_t *end = parser->
current.end - 1;
10505 assert(end >= start);
10506 pm_buffer_append_bytes(&token_buffer->
buffer, start, (
size_t) (end - start));
10508 token_buffer->
cursor = end;
10513 const uint8_t *start;
10515 pm_buffer_init_capacity(&token_buffer->
base.
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10516 pm_buffer_init_capacity(&token_buffer->
regexp_buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10517 start = parser->
current.start;
10522 const uint8_t *end = parser->
current.end - 1;
10523 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, (
size_t) (end - start));
10524 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, (
size_t) (end - start));
10529#undef PM_TOKEN_BUFFER_DEFAULT_SIZE
10535static inline size_t
10537 size_t whitespace = 0;
10540 case PM_HEREDOC_INDENT_NONE:
10545 case PM_HEREDOC_INDENT_DASH:
10547 *cursor += pm_strspn_inline_whitespace(*cursor, parser->
end - *cursor);
10549 case PM_HEREDOC_INDENT_TILDE:
10552 while (*cursor < parser->end && pm_char_is_inline_whitespace(**cursor)) {
10553 if (**cursor ==
'\t') {
10554 whitespace = (whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
10573 size_t eol_length = match_eol(parser);
10580 parser_flush_heredoc_end(parser);
10586 uint8_t delimiter = *parser->
current.end;
10590 if (eol_length == 2) {
10591 delimiter = *(parser->
current.end + 1);
10594 parser->
current.end += eol_length;
10598 return *parser->
current.end++;
10605#define LEX(token_type) parser->current.type = token_type; parser_lex_callback(parser); return
10624 bool lexed_comment =
false;
10632 case PM_LEX_DEFAULT:
10633 case PM_LEX_EMBEXPR:
10634 case PM_LEX_EMBVAR:
10650 bool space_seen =
false;
10654 bool chomping =
true;
10655 while (parser->
current.end < parser->
end && chomping) {
10656 switch (*parser->
current.end) {
10665 if (match_eol_offset(parser, 1)) {
10668 pm_parser_warn(parser, parser->
current.end, parser->
current.end + 1, PM_WARN_UNEXPECTED_CARRIAGE_RETURN);
10674 size_t eol_length = match_eol_offset(parser, 1);
10680 parser->
current.end += eol_length + 1;
10684 }
else if (pm_char_is_inline_whitespace(*parser->
current.end)) {
10717 switch (*parser->
current.end++) {
10725 const uint8_t *ending = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10726 parser->
current.end = ending == NULL ? parser->
end : ending;
10731 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_INLINE);
10734 if (ending) parser->
current.end++;
10735 parser->
current.type = PM_TOKEN_COMMENT;
10736 parser_lex_callback(parser);
10748 parser_lex_magic_comment_encoding(parser);
10752 lexed_comment =
true;
10758 size_t eol_length = match_eol_at(parser, parser->
current.end - 1);
10770 if (!lexed_comment) {
10771 parser->
current.end += eol_length - 1;
10780 parser_flush_heredoc_end(parser);
10785 switch (lex_state_ignored_p(parser)) {
10786 case PM_IGNORED_NEWLINE_NONE:
10788 case PM_IGNORED_NEWLINE_PATTERN:
10790 if (!lexed_comment) parser_lex_ignored_newline(parser);
10791 lex_state_set(parser, PM_LEX_STATE_BEG);
10793 parser->
current.type = PM_TOKEN_NEWLINE;
10797 case PM_IGNORED_NEWLINE_ALL:
10798 if (!lexed_comment) parser_lex_ignored_newline(parser);
10799 lexed_comment =
false;
10800 goto lex_next_token;
10808 next_content += pm_strspn_inline_whitespace(next_content, parser->
end - next_content);
10810 if (next_content < parser->end) {
10816 if (next_content[0] ==
'#') {
10818 const uint8_t *following = next_newline(next_content, parser->
end - next_content);
10820 while (following && (following + 1 < parser->
end)) {
10822 following += pm_strspn_inline_whitespace(following, parser->
end - following);
10826 if (peek_at(parser, following) !=
'#')
break;
10830 following = next_newline(following, parser->
end - following);
10835 if (lex_state_ignored_p(parser)) {
10836 if (!lexed_comment) parser_lex_ignored_newline(parser);
10837 lexed_comment =
false;
10838 goto lex_next_token;
10844 (peek_at(parser, following) ==
'.') ||
10845 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'.')
10847 if (!lexed_comment) parser_lex_ignored_newline(parser);
10848 lexed_comment =
false;
10849 goto lex_next_token;
10859 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'&') ||
10860 (peek_at(parser, following) ==
'|' && peek_at(parser, following + 1) ==
'|') ||
10861 (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))) ||
10862 (peek_at(parser, following) ==
'o' && peek_at(parser, following + 1) ==
'r' && !char_is_identifier(parser, following + 2, parser->
end - (following + 2)))
10865 if (!lexed_comment) parser_lex_ignored_newline(parser);
10866 lexed_comment =
false;
10867 goto lex_next_token;
10873 if (next_content[0] ==
'.') {
10877 if (peek_at(parser, next_content + 1) ==
'.') {
10878 if (!lexed_comment) parser_lex_ignored_newline(parser);
10879 lex_state_set(parser, PM_LEX_STATE_BEG);
10881 parser->
current.type = PM_TOKEN_NEWLINE;
10885 if (!lexed_comment) parser_lex_ignored_newline(parser);
10886 lex_state_set(parser, PM_LEX_STATE_DOT);
10887 parser->
current.start = next_content;
10888 parser->
current.end = next_content + 1;
10895 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'.') {
10896 if (!lexed_comment) parser_lex_ignored_newline(parser);
10897 lex_state_set(parser, PM_LEX_STATE_DOT);
10898 parser->
current.start = next_content;
10899 parser->
current.end = next_content + 2;
10901 LEX(PM_TOKEN_AMPERSAND_DOT);
10907 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'&') {
10908 if (!lexed_comment) parser_lex_ignored_newline(parser);
10909 lex_state_set(parser, PM_LEX_STATE_BEG);
10910 parser->
current.start = next_content;
10911 parser->
current.end = next_content + 2;
10913 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
10918 if (peek_at(parser, next_content) ==
'|' && peek_at(parser, next_content + 1) ==
'|') {
10919 if (!lexed_comment) parser_lex_ignored_newline(parser);
10920 lex_state_set(parser, PM_LEX_STATE_BEG);
10921 parser->
current.start = next_content;
10922 parser->
current.end = next_content + 2;
10924 LEX(PM_TOKEN_PIPE_PIPE);
10930 peek_at(parser, next_content) ==
'a' &&
10931 peek_at(parser, next_content + 1) ==
'n' &&
10932 peek_at(parser, next_content + 2) ==
'd' &&
10933 !char_is_identifier(parser, next_content + 3, parser->
end - (next_content + 3))
10935 if (!lexed_comment) parser_lex_ignored_newline(parser);
10936 lex_state_set(parser, PM_LEX_STATE_BEG);
10937 parser->
current.start = next_content;
10938 parser->
current.end = next_content + 3;
10941 LEX(PM_TOKEN_KEYWORD_AND);
10947 peek_at(parser, next_content) ==
'o' &&
10948 peek_at(parser, next_content + 1) ==
'r' &&
10949 !char_is_identifier(parser, next_content + 2, parser->
end - (next_content + 2))
10951 if (!lexed_comment) parser_lex_ignored_newline(parser);
10952 lex_state_set(parser, PM_LEX_STATE_BEG);
10953 parser->
current.start = next_content;
10954 parser->
current.end = next_content + 2;
10957 LEX(PM_TOKEN_KEYWORD_OR);
10964 lex_state_set(parser, PM_LEX_STATE_BEG);
10966 parser->
current.type = PM_TOKEN_NEWLINE;
10967 if (!lexed_comment) parser_lex_callback(parser);
10977 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10978 LEX(PM_TOKEN_COMMA);
10982 pm_token_type_t
type = PM_TOKEN_PARENTHESIS_LEFT;
10984 if (space_seen && (lex_state_arg_p(parser) || parser->
lex_state == (PM_LEX_STATE_END | PM_LEX_STATE_LABEL))) {
10985 type = PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES;
10989 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10990 pm_do_loop_stack_push(parser,
false);
10997 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10998 pm_do_loop_stack_pop(parser);
10999 LEX(PM_TOKEN_PARENTHESIS_RIGHT);
11003 lex_state_set(parser, PM_LEX_STATE_BEG);
11005 LEX(PM_TOKEN_SEMICOLON);
11010 pm_token_type_t
type = PM_TOKEN_BRACKET_LEFT;
11012 if (lex_state_operator_p(parser)) {
11013 if (match(parser,
']')) {
11015 lex_state_set(parser, PM_LEX_STATE_ARG);
11016 LEX(match(parser,
'=') ? PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL : PM_TOKEN_BRACKET_LEFT_RIGHT);
11019 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABEL);
11023 if (lex_state_beg_p(parser) || (lex_state_arg_p(parser) && (space_seen || lex_state_p(parser, PM_LEX_STATE_LABELED)))) {
11024 type = PM_TOKEN_BRACKET_LEFT_ARRAY;
11027 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
11028 pm_do_loop_stack_push(parser,
false);
11034 lex_state_set(parser, PM_LEX_STATE_END);
11035 pm_do_loop_stack_pop(parser);
11036 LEX(PM_TOKEN_BRACKET_RIGHT);
11040 pm_token_type_t
type = PM_TOKEN_BRACE_LEFT;
11045 lex_state_set(parser, PM_LEX_STATE_BEG);
11046 type = PM_TOKEN_LAMBDA_BEGIN;
11047 }
else if (lex_state_p(parser, PM_LEX_STATE_LABELED)) {
11049 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
11050 }
else if (lex_state_p(parser, PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_END | PM_LEX_STATE_ENDFN)) {
11053 lex_state_set(parser, PM_LEX_STATE_BEG);
11054 }
else if (lex_state_p(parser, PM_LEX_STATE_ENDARG)) {
11057 lex_state_set(parser, PM_LEX_STATE_BEG);
11060 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
11065 pm_do_loop_stack_push(parser,
false);
11073 pm_do_loop_stack_pop(parser);
11076 lex_mode_pop(parser);
11077 LEX(PM_TOKEN_EMBEXPR_END);
11081 lex_state_set(parser, PM_LEX_STATE_END);
11082 LEX(PM_TOKEN_BRACE_RIGHT);
11086 if (match(parser,
'*')) {
11087 if (match(parser,
'=')) {
11088 lex_state_set(parser, PM_LEX_STATE_BEG);
11089 LEX(PM_TOKEN_STAR_STAR_EQUAL);
11092 pm_token_type_t
type = PM_TOKEN_STAR_STAR;
11094 if (lex_state_spcarg_p(parser, space_seen)) {
11095 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR_STAR);
11096 type = PM_TOKEN_USTAR_STAR;
11097 }
else if (lex_state_beg_p(parser)) {
11098 type = PM_TOKEN_USTAR_STAR;
11099 }
else if (ambiguous_operator_p(parser, space_seen)) {
11100 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"**",
"argument prefix");
11103 if (lex_state_operator_p(parser)) {
11104 lex_state_set(parser, PM_LEX_STATE_ARG);
11106 lex_state_set(parser, PM_LEX_STATE_BEG);
11112 if (match(parser,
'=')) {
11113 lex_state_set(parser, PM_LEX_STATE_BEG);
11114 LEX(PM_TOKEN_STAR_EQUAL);
11117 pm_token_type_t
type = PM_TOKEN_STAR;
11119 if (lex_state_spcarg_p(parser, space_seen)) {
11120 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR);
11121 type = PM_TOKEN_USTAR;
11122 }
else if (lex_state_beg_p(parser)) {
11123 type = PM_TOKEN_USTAR;
11124 }
else if (ambiguous_operator_p(parser, space_seen)) {
11125 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"*",
"argument prefix");
11128 if (lex_state_operator_p(parser)) {
11129 lex_state_set(parser, PM_LEX_STATE_ARG);
11131 lex_state_set(parser, PM_LEX_STATE_BEG);
11139 if (lex_state_operator_p(parser)) {
11140 lex_state_set(parser, PM_LEX_STATE_ARG);
11141 if (match(parser,
'@')) {
11142 LEX(PM_TOKEN_BANG);
11145 lex_state_set(parser, PM_LEX_STATE_BEG);
11148 if (match(parser,
'=')) {
11149 LEX(PM_TOKEN_BANG_EQUAL);
11152 if (match(parser,
'~')) {
11153 LEX(PM_TOKEN_BANG_TILDE);
11156 LEX(PM_TOKEN_BANG);
11161 current_token_starts_line(parser) &&
11163 memcmp(parser->
current.end,
"begin", 5) == 0 &&
11164 (pm_char_is_whitespace(peek_offset(parser, 5)) || (peek_offset(parser, 5) ==
'\0'))
11166 pm_token_type_t
type = lex_embdoc(parser);
11167 if (
type == PM_TOKEN_EOF) {
11171 goto lex_next_token;
11174 if (lex_state_operator_p(parser)) {
11175 lex_state_set(parser, PM_LEX_STATE_ARG);
11177 lex_state_set(parser, PM_LEX_STATE_BEG);
11180 if (match(parser,
'>')) {
11181 LEX(PM_TOKEN_EQUAL_GREATER);
11184 if (match(parser,
'~')) {
11185 LEX(PM_TOKEN_EQUAL_TILDE);
11188 if (match(parser,
'=')) {
11189 LEX(match(parser,
'=') ? PM_TOKEN_EQUAL_EQUAL_EQUAL : PM_TOKEN_EQUAL_EQUAL);
11192 LEX(PM_TOKEN_EQUAL);
11196 if (match(parser,
'<')) {
11198 !lex_state_p(parser, PM_LEX_STATE_DOT | PM_LEX_STATE_CLASS) &&
11199 !lex_state_end_p(parser) &&
11200 (!lex_state_p(parser, PM_LEX_STATE_ARG_ANY) || lex_state_p(parser, PM_LEX_STATE_LABELED) || space_seen)
11202 const uint8_t *end = parser->
current.end;
11207 if (match(parser,
'-')) {
11208 indent = PM_HEREDOC_INDENT_DASH;
11210 else if (match(parser,
'~')) {
11211 indent = PM_HEREDOC_INDENT_TILDE;
11214 if (match(parser,
'`')) {
11215 quote = PM_HEREDOC_QUOTE_BACKTICK;
11217 else if (match(parser,
'"')) {
11218 quote = PM_HEREDOC_QUOTE_DOUBLE;
11220 else if (match(parser,
'\'')) {
11221 quote = PM_HEREDOC_QUOTE_SINGLE;
11224 const uint8_t *ident_start = parser->
current.end;
11229 }
else if (quote == PM_HEREDOC_QUOTE_NONE && (width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) == 0) {
11232 if (quote == PM_HEREDOC_QUOTE_NONE) {
11233 parser->
current.end += width;
11235 while ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end))) {
11236 parser->
current.end += width;
11242 if (*parser->
current.end ==
'\r' || *parser->
current.end ==
'\n')
break;
11247 size_t ident_length = (size_t) (parser->
current.end - ident_start);
11248 bool ident_error =
false;
11250 if (quote != PM_HEREDOC_QUOTE_NONE && !match(parser, (uint8_t) quote)) {
11251 pm_parser_err(parser, ident_start, ident_start + ident_length, PM_ERR_HEREDOC_IDENTIFIER);
11252 ident_error =
true;
11257 .mode = PM_LEX_HEREDOC,
11260 .ident_start = ident_start,
11261 .ident_length = ident_length,
11265 .next_start = parser->
current.end,
11267 .line_continuation =
false
11272 const uint8_t *body_start = next_newline(parser->
current.end, parser->
end - parser->
current.end);
11274 if (body_start == NULL) {
11279 if (!ident_error) pm_parser_err_heredoc_term(parser, ident_start, ident_length);
11280 body_start = parser->
end;
11284 pm_newline_list_append(&parser->
newline_list, body_start);
11293 LEX(PM_TOKEN_HEREDOC_START);
11297 if (match(parser,
'=')) {
11298 lex_state_set(parser, PM_LEX_STATE_BEG);
11299 LEX(PM_TOKEN_LESS_LESS_EQUAL);
11302 if (ambiguous_operator_p(parser, space_seen)) {
11303 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"<<",
"here document");
11306 if (lex_state_operator_p(parser)) {
11307 lex_state_set(parser, PM_LEX_STATE_ARG);
11309 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
11310 lex_state_set(parser, PM_LEX_STATE_BEG);
11313 LEX(PM_TOKEN_LESS_LESS);
11316 if (lex_state_operator_p(parser)) {
11317 lex_state_set(parser, PM_LEX_STATE_ARG);
11319 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
11320 lex_state_set(parser, PM_LEX_STATE_BEG);
11323 if (match(parser,
'=')) {
11324 if (match(parser,
'>')) {
11325 LEX(PM_TOKEN_LESS_EQUAL_GREATER);
11328 LEX(PM_TOKEN_LESS_EQUAL);
11331 LEX(PM_TOKEN_LESS);
11335 if (match(parser,
'>')) {
11336 if (lex_state_operator_p(parser)) {
11337 lex_state_set(parser, PM_LEX_STATE_ARG);
11339 lex_state_set(parser, PM_LEX_STATE_BEG);
11341 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_GREATER_EQUAL : PM_TOKEN_GREATER_GREATER);
11344 if (lex_state_operator_p(parser)) {
11345 lex_state_set(parser, PM_LEX_STATE_ARG);
11347 lex_state_set(parser, PM_LEX_STATE_BEG);
11350 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_EQUAL : PM_TOKEN_GREATER);
11354 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
11355 lex_mode_push_string(parser,
true, label_allowed,
'\0',
'"');
11356 LEX(PM_TOKEN_STRING_BEGIN);
11361 if (lex_state_p(parser, PM_LEX_STATE_FNAME)) {
11362 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11363 LEX(PM_TOKEN_BACKTICK);
11366 if (lex_state_p(parser, PM_LEX_STATE_DOT)) {
11367 if (previous_command_start) {
11368 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11370 lex_state_set(parser, PM_LEX_STATE_ARG);
11373 LEX(PM_TOKEN_BACKTICK);
11376 lex_mode_push_string(parser,
true,
false,
'\0',
'`');
11377 LEX(PM_TOKEN_BACKTICK);
11382 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
11383 lex_mode_push_string(parser,
false, label_allowed,
'\0',
'\'');
11384 LEX(PM_TOKEN_STRING_BEGIN);
11389 LEX(lex_question_mark(parser));
11393 if (match(parser,
'&')) {
11394 lex_state_set(parser, PM_LEX_STATE_BEG);
11396 if (match(parser,
'=')) {
11397 LEX(PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
11400 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
11403 if (match(parser,
'=')) {
11404 lex_state_set(parser, PM_LEX_STATE_BEG);
11405 LEX(PM_TOKEN_AMPERSAND_EQUAL);
11408 if (match(parser,
'.')) {
11409 lex_state_set(parser, PM_LEX_STATE_DOT);
11410 LEX(PM_TOKEN_AMPERSAND_DOT);
11413 pm_token_type_t
type = PM_TOKEN_AMPERSAND;
11414 if (lex_state_spcarg_p(parser, space_seen)) {
11415 if ((peek(parser) !=
':') || (peek_offset(parser, 1) ==
'\0')) {
11416 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
11418 const uint8_t delim = peek_offset(parser, 1);
11420 if ((delim !=
'\'') && (delim !=
'"') && !char_is_identifier(parser, parser->
current.end + 1, parser->
end - (parser->
current.end + 1))) {
11421 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
11425 type = PM_TOKEN_UAMPERSAND;
11426 }
else if (lex_state_beg_p(parser)) {
11427 type = PM_TOKEN_UAMPERSAND;
11428 }
else if (ambiguous_operator_p(parser, space_seen)) {
11429 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"&",
"argument prefix");
11432 if (lex_state_operator_p(parser)) {
11433 lex_state_set(parser, PM_LEX_STATE_ARG);
11435 lex_state_set(parser, PM_LEX_STATE_BEG);
11443 if (match(parser,
'|')) {
11444 if (match(parser,
'=')) {
11445 lex_state_set(parser, PM_LEX_STATE_BEG);
11446 LEX(PM_TOKEN_PIPE_PIPE_EQUAL);
11449 if (lex_state_p(parser, PM_LEX_STATE_BEG)) {
11451 LEX(PM_TOKEN_PIPE);
11454 lex_state_set(parser, PM_LEX_STATE_BEG);
11455 LEX(PM_TOKEN_PIPE_PIPE);
11458 if (match(parser,
'=')) {
11459 lex_state_set(parser, PM_LEX_STATE_BEG);
11460 LEX(PM_TOKEN_PIPE_EQUAL);
11463 if (lex_state_operator_p(parser)) {
11464 lex_state_set(parser, PM_LEX_STATE_ARG);
11466 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
11469 LEX(PM_TOKEN_PIPE);
11473 if (lex_state_operator_p(parser)) {
11474 lex_state_set(parser, PM_LEX_STATE_ARG);
11476 if (match(parser,
'@')) {
11477 LEX(PM_TOKEN_UPLUS);
11480 LEX(PM_TOKEN_PLUS);
11483 if (match(parser,
'=')) {
11484 lex_state_set(parser, PM_LEX_STATE_BEG);
11485 LEX(PM_TOKEN_PLUS_EQUAL);
11489 lex_state_beg_p(parser) ||
11490 (lex_state_spcarg_p(parser, space_seen) ? (pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS),
true) :
false)
11492 lex_state_set(parser, PM_LEX_STATE_BEG);
11494 if (pm_char_is_decimal_digit(peek(parser))) {
11496 pm_token_type_t
type = lex_numeric(parser);
11497 lex_state_set(parser, PM_LEX_STATE_END);
11501 LEX(PM_TOKEN_UPLUS);
11504 if (ambiguous_operator_p(parser, space_seen)) {
11505 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"+",
"unary operator");
11508 lex_state_set(parser, PM_LEX_STATE_BEG);
11509 LEX(PM_TOKEN_PLUS);
11514 if (lex_state_operator_p(parser)) {
11515 lex_state_set(parser, PM_LEX_STATE_ARG);
11517 if (match(parser,
'@')) {
11518 LEX(PM_TOKEN_UMINUS);
11521 LEX(PM_TOKEN_MINUS);
11524 if (match(parser,
'=')) {
11525 lex_state_set(parser, PM_LEX_STATE_BEG);
11526 LEX(PM_TOKEN_MINUS_EQUAL);
11529 if (match(parser,
'>')) {
11530 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11531 LEX(PM_TOKEN_MINUS_GREATER);
11534 bool spcarg = lex_state_spcarg_p(parser, space_seen);
11535 bool is_beg = lex_state_beg_p(parser);
11536 if (!is_beg && spcarg) {
11537 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS);
11540 if (is_beg || spcarg) {
11541 lex_state_set(parser, PM_LEX_STATE_BEG);
11542 LEX(pm_char_is_decimal_digit(peek(parser)) ? PM_TOKEN_UMINUS_NUM : PM_TOKEN_UMINUS);
11545 if (ambiguous_operator_p(parser, space_seen)) {
11546 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"-",
"unary operator");
11549 lex_state_set(parser, PM_LEX_STATE_BEG);
11550 LEX(PM_TOKEN_MINUS);
11555 bool beg_p = lex_state_beg_p(parser);
11557 if (match(parser,
'.')) {
11558 if (match(parser,
'.')) {
11561 if (lex_state_p(parser, PM_LEX_STATE_END)) {
11562 lex_state_set(parser, PM_LEX_STATE_BEG);
11564 lex_state_set(parser, PM_LEX_STATE_ENDARG);
11566 LEX(PM_TOKEN_UDOT_DOT_DOT);
11570 pm_parser_warn_token(parser, &parser->
current, PM_WARN_DOT_DOT_DOT_EOL);
11573 lex_state_set(parser, PM_LEX_STATE_BEG);
11574 LEX(beg_p ? PM_TOKEN_UDOT_DOT_DOT : PM_TOKEN_DOT_DOT_DOT);
11577 lex_state_set(parser, PM_LEX_STATE_BEG);
11578 LEX(beg_p ? PM_TOKEN_UDOT_DOT : PM_TOKEN_DOT_DOT);
11581 lex_state_set(parser, PM_LEX_STATE_DOT);
11596 pm_token_type_t
type = lex_numeric(parser);
11597 lex_state_set(parser, PM_LEX_STATE_END);
11603 if (match(parser,
':')) {
11604 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)) {
11605 lex_state_set(parser, PM_LEX_STATE_BEG);
11606 LEX(PM_TOKEN_UCOLON_COLON);
11609 lex_state_set(parser, PM_LEX_STATE_DOT);
11610 LEX(PM_TOKEN_COLON_COLON);
11613 if (lex_state_end_p(parser) || pm_char_is_whitespace(peek(parser)) || peek(parser) ==
'#') {
11614 lex_state_set(parser, PM_LEX_STATE_BEG);
11615 LEX(PM_TOKEN_COLON);
11618 if (peek(parser) ==
'"' || peek(parser) ==
'\'') {
11619 lex_mode_push_string(parser, peek(parser) ==
'"',
false,
'\0', *parser->
current.end);
11623 lex_state_set(parser, PM_LEX_STATE_FNAME);
11624 LEX(PM_TOKEN_SYMBOL_BEGIN);
11628 if (lex_state_beg_p(parser)) {
11629 lex_mode_push_regexp(parser,
'\0',
'/');
11630 LEX(PM_TOKEN_REGEXP_BEGIN);
11633 if (match(parser,
'=')) {
11634 lex_state_set(parser, PM_LEX_STATE_BEG);
11635 LEX(PM_TOKEN_SLASH_EQUAL);
11638 if (lex_state_spcarg_p(parser, space_seen)) {
11639 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_SLASH);
11640 lex_mode_push_regexp(parser,
'\0',
'/');
11641 LEX(PM_TOKEN_REGEXP_BEGIN);
11644 if (ambiguous_operator_p(parser, space_seen)) {
11645 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"/",
"regexp literal");
11648 if (lex_state_operator_p(parser)) {
11649 lex_state_set(parser, PM_LEX_STATE_ARG);
11651 lex_state_set(parser, PM_LEX_STATE_BEG);
11654 LEX(PM_TOKEN_SLASH);
11658 if (lex_state_operator_p(parser)) {
11659 lex_state_set(parser, PM_LEX_STATE_ARG);
11661 lex_state_set(parser, PM_LEX_STATE_BEG);
11663 LEX(match(parser,
'=') ? PM_TOKEN_CARET_EQUAL : PM_TOKEN_CARET);
11667 if (lex_state_operator_p(parser)) {
11668 (void) match(parser,
'@');
11669 lex_state_set(parser, PM_LEX_STATE_ARG);
11671 lex_state_set(parser, PM_LEX_STATE_BEG);
11674 LEX(PM_TOKEN_TILDE);
11682 if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->
current.end >= parser->
end)) {
11683 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT_EOF);
11684 LEX(PM_TOKEN_PERCENT);
11687 if (!lex_state_beg_p(parser) && match(parser,
'=')) {
11688 lex_state_set(parser, PM_LEX_STATE_BEG);
11689 LEX(PM_TOKEN_PERCENT_EQUAL);
11691 lex_state_beg_p(parser) ||
11692 (lex_state_p(parser, PM_LEX_STATE_FITEM) && (peek(parser) ==
's')) ||
11693 lex_state_spcarg_p(parser, space_seen)
11696 if (*parser->
current.end >= 0x80) {
11697 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11700 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11701 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11702 LEX(PM_TOKEN_STRING_BEGIN);
11707 uint8_t delimiter = peek_offset(parser, 1);
11709 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11710 goto lex_next_token;
11713 switch (peek(parser)) {
11718 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11720 lex_mode_push_list_eof(parser);
11723 LEX(PM_TOKEN_PERCENT_LOWER_I);
11729 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11731 lex_mode_push_list_eof(parser);
11734 LEX(PM_TOKEN_PERCENT_UPPER_I);
11740 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11741 lex_mode_push_regexp(parser, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11743 lex_mode_push_regexp(parser,
'\0',
'\0');
11746 LEX(PM_TOKEN_REGEXP_BEGIN);
11752 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11753 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11755 lex_mode_push_string_eof(parser);
11758 LEX(PM_TOKEN_STRING_BEGIN);
11764 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11765 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11767 lex_mode_push_string_eof(parser);
11770 LEX(PM_TOKEN_STRING_BEGIN);
11776 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11777 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11778 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
11780 lex_mode_push_string_eof(parser);
11783 LEX(PM_TOKEN_SYMBOL_BEGIN);
11789 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11791 lex_mode_push_list_eof(parser);
11794 LEX(PM_TOKEN_PERCENT_LOWER_W);
11800 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11802 lex_mode_push_list_eof(parser);
11805 LEX(PM_TOKEN_PERCENT_UPPER_W);
11811 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11812 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11814 lex_mode_push_string_eof(parser);
11817 LEX(PM_TOKEN_PERCENT_LOWER_X);
11824 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11825 goto lex_next_token;
11829 if (ambiguous_operator_p(parser, space_seen)) {
11830 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"%",
"string literal");
11833 lex_state_set(parser, lex_state_operator_p(parser) ? PM_LEX_STATE_ARG : PM_LEX_STATE_BEG);
11834 LEX(PM_TOKEN_PERCENT);
11839 pm_token_type_t
type = lex_global_variable(parser);
11844 lex_mode_pop(parser);
11847 lex_state_set(parser, PM_LEX_STATE_END);
11853 lex_state_set(parser, parser->
lex_state & PM_LEX_STATE_FNAME ? PM_LEX_STATE_ENDFN : PM_LEX_STATE_END);
11854 LEX(lex_at_variable(parser));
11857 if (*parser->
current.start !=
'_') {
11858 size_t width = char_is_identifier_start(parser, parser->
current.start, parser->
end - parser->
current.start);
11865 if (*parser->
current.start >= 0x80) {
11866 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *parser->
current.start);
11867 }
else if (*parser->
current.start ==
'\\') {
11868 switch (peek_at(parser, parser->
current.start + 1)) {
11871 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped space");
11875 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped form feed");
11879 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped horizontal tab");
11883 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped vertical tab");
11886 if (peek_at(parser, parser->
current.start + 2) !=
'\n') {
11888 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped carriage return");
11893 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"backslash");
11896 }
else if (char_is_ascii_printable(*parser->
current.start)) {
11897 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_PRINTABLE_CHARACTER, *parser->
current.start);
11899 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_CHARACTER, *parser->
current.start);
11902 goto lex_next_token;
11908 pm_token_type_t
type = lex_identifier(parser, previous_command_start);
11916 current_token_starts_line(parser) &&
11917 (memcmp(parser->
current.start,
"__END__", 7) == 0) &&
11918 (parser->
current.end == parser->
end || match_eol(parser))
11923 const uint8_t *cursor = parser->
current.end;
11924 while ((cursor = next_newline(cursor, parser->
end - cursor)) != NULL) {
11925 pm_newline_list_append(&parser->
newline_list, cursor++);
11929 parser->
current.type = PM_TOKEN___END__;
11930 parser_lex_callback(parser);
11940 if (
type == PM_TOKEN_IDENTIFIER ||
type == PM_TOKEN_CONSTANT ||
type == PM_TOKEN_METHOD_NAME) {
11941 if (lex_state_p(parser, PM_LEX_STATE_BEG_ANY | PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_DOT)) {
11942 if (previous_command_start) {
11943 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11945 lex_state_set(parser, PM_LEX_STATE_ARG);
11947 }
else if (parser->
lex_state == PM_LEX_STATE_FNAME) {
11948 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11950 lex_state_set(parser, PM_LEX_STATE_END);
11955 !(last_state & (PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME)) &&
11956 (
type == PM_TOKEN_IDENTIFIER) &&
11957 ((pm_parser_local_depth(parser, &parser->
current) != -1) ||
11958 pm_token_is_numbered_parameter(parser->
current.start, parser->
current.end))
11960 lex_state_set(parser, PM_LEX_STATE_END | PM_LEX_STATE_LABEL);
11967 case PM_LEX_LIST: {
11981 whitespace = pm_strspn_inline_whitespace(parser->
current.end, parser->
end - parser->
current.end);
11982 if (peek_offset(parser, (ptrdiff_t)whitespace) ==
'\n') {
11989 if (whitespace > 0) {
11990 parser->
current.end += whitespace;
11991 if (peek_offset(parser, -1) ==
'\n') {
11993 parser_flush_heredoc_end(parser);
11995 LEX(PM_TOKEN_WORDS_SEP);
12007 const uint8_t *breakpoints = lex_mode->
as.list.
breakpoints;
12008 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12014 while (breakpoint != NULL) {
12017 if (pm_char_is_whitespace(*breakpoint)) {
12018 parser->
current.end = breakpoint;
12019 pm_token_buffer_flush(parser, &token_buffer);
12020 LEX(PM_TOKEN_STRING_CONTENT);
12029 parser->
current.end = breakpoint + 1;
12030 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12037 if (breakpoint > parser->
current.start) {
12038 parser->
current.end = breakpoint;
12039 pm_token_buffer_flush(parser, &token_buffer);
12040 LEX(PM_TOKEN_STRING_CONTENT);
12045 parser->
current.end = breakpoint + 1;
12046 lex_mode_pop(parser);
12047 lex_state_set(parser, PM_LEX_STATE_END);
12048 LEX(PM_TOKEN_STRING_END);
12052 if (*breakpoint ==
'\0') {
12053 breakpoint = pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->
end - (breakpoint + 1),
true);
12060 if (*breakpoint ==
'\\') {
12061 parser->
current.end = breakpoint + 1;
12070 pm_token_buffer_escape(parser, &token_buffer);
12071 uint8_t peeked = peek(parser);
12079 pm_token_buffer_push_byte(&token_buffer, peeked);
12084 if (peek(parser) !=
'\n') {
12085 pm_token_buffer_push_byte(&token_buffer,
'\r');
12090 pm_token_buffer_push_byte(&token_buffer,
'\n');
12096 parser_flush_heredoc_end(parser);
12097 pm_token_buffer_copy(parser, &token_buffer);
12098 LEX(PM_TOKEN_STRING_CONTENT);
12108 pm_token_buffer_push_byte(&token_buffer, peeked);
12111 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12113 pm_token_buffer_push_byte(&token_buffer,
'\\');
12114 pm_token_buffer_push_escaped(&token_buffer, parser);
12121 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12126 if (*breakpoint ==
'#') {
12127 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12129 if (
type == PM_TOKEN_NOT_PROVIDED) {
12134 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12138 if (
type == PM_TOKEN_STRING_CONTENT) {
12139 pm_token_buffer_flush(parser, &token_buffer);
12148 parser->
current.end = breakpoint + 1;
12149 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12155 pm_token_buffer_flush(parser, &token_buffer);
12156 LEX(PM_TOKEN_STRING_CONTENT);
12162 pm_token_buffer_flush(parser, &token_buffer);
12163 LEX(PM_TOKEN_STRING_CONTENT);
12165 case PM_LEX_REGEXP: {
12187 const uint8_t *breakpoints = lex_mode->
as.regexp.
breakpoints;
12188 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12191 while (breakpoint != NULL) {
12193 bool is_terminator = (*breakpoint == term);
12198 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
12199 if (term ==
'\n') {
12200 is_terminator =
true;
12206 if (term ==
'\r') {
12207 is_terminator =
false;
12213 if (is_terminator) {
12215 parser->
current.end = breakpoint + 1;
12216 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12224 if (breakpoint > parser->
current.start) {
12225 parser->
current.end = breakpoint;
12226 pm_regexp_token_buffer_flush(parser, &token_buffer);
12227 LEX(PM_TOKEN_STRING_CONTENT);
12231 size_t eol_length = match_eol_at(parser, breakpoint);
12233 parser->
current.end = breakpoint + eol_length;
12236 parser->
current.end = breakpoint + 1;
12243 lex_mode_pop(parser);
12244 lex_state_set(parser, PM_LEX_STATE_END);
12245 LEX(PM_TOKEN_REGEXP_END);
12250 if (*breakpoint && *breakpoint == lex_mode->
as.regexp.
incrementor) {
12251 parser->
current.end = breakpoint + 1;
12252 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12257 switch (*breakpoint) {
12260 parser->
current.end = breakpoint + 1;
12261 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12264 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12265 parser->
current.end = breakpoint + 1;
12266 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12271 parser->
current.end = breakpoint;
12272 pm_regexp_token_buffer_escape(parser, &token_buffer);
12280 pm_newline_list_append(&parser->
newline_list, breakpoint);
12281 parser->
current.end = breakpoint + 1;
12282 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12286 parser->
current.end = breakpoint + 1;
12287 parser_flush_heredoc_end(parser);
12288 pm_regexp_token_buffer_flush(parser, &token_buffer);
12289 LEX(PM_TOKEN_STRING_CONTENT);
12294 parser->
current.end = breakpoint + 1;
12303 pm_regexp_token_buffer_escape(parser, &token_buffer);
12304 uint8_t peeked = peek(parser);
12309 if (peek(parser) !=
'\n') {
12311 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12313 pm_regexp_token_buffer_push_byte(&token_buffer,
'\r');
12314 pm_token_buffer_push_byte(&token_buffer.
base,
'\r');
12323 parser_flush_heredoc_end(parser);
12324 pm_regexp_token_buffer_copy(parser, &token_buffer);
12325 LEX(PM_TOKEN_STRING_CONTENT);
12346 case '$':
case ')':
case '*':
case '+':
12347 case '.':
case '>':
case '?':
case ']':
12348 case '^':
case '|':
case '}':
12349 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12355 pm_regexp_token_buffer_push_byte(&token_buffer, peeked);
12356 pm_token_buffer_push_byte(&token_buffer.
base, peeked);
12361 if (peeked < 0x80) pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12362 pm_regexp_token_buffer_push_escaped(&token_buffer, parser);
12367 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12373 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12375 if (
type == PM_TOKEN_NOT_PROVIDED) {
12380 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12384 if (
type == PM_TOKEN_STRING_CONTENT) {
12385 pm_regexp_token_buffer_flush(parser, &token_buffer);
12391 assert(
false &&
"unreachable");
12397 pm_regexp_token_buffer_flush(parser, &token_buffer);
12398 LEX(PM_TOKEN_STRING_CONTENT);
12404 pm_regexp_token_buffer_flush(parser, &token_buffer);
12405 LEX(PM_TOKEN_STRING_CONTENT);
12407 case PM_LEX_STRING: {
12426 const uint8_t *breakpoints = lex_mode->
as.string.
breakpoints;
12427 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12433 while (breakpoint != NULL) {
12438 parser->
current.end = breakpoint + 1;
12439 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12444 bool is_terminator = (*breakpoint == term);
12449 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
12450 if (term ==
'\n') {
12451 is_terminator =
true;
12457 if (term ==
'\r') {
12458 is_terminator =
false;
12465 if (is_terminator) {
12469 parser->
current.end = breakpoint + 1;
12470 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12477 if (breakpoint > parser->
current.start) {
12478 parser->
current.end = breakpoint;
12479 pm_token_buffer_flush(parser, &token_buffer);
12480 LEX(PM_TOKEN_STRING_CONTENT);
12485 size_t eol_length = match_eol_at(parser, breakpoint);
12487 parser->
current.end = breakpoint + eol_length;
12490 parser->
current.end = breakpoint + 1;
12493 if (lex_mode->
as.string.
label_allowed && (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')) {
12495 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
12496 lex_mode_pop(parser);
12497 LEX(PM_TOKEN_LABEL_END);
12500 lex_state_set(parser, PM_LEX_STATE_END);
12501 lex_mode_pop(parser);
12502 LEX(PM_TOKEN_STRING_END);
12505 switch (*breakpoint) {
12508 parser->
current.end = breakpoint + 1;
12509 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12512 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12513 parser->
current.end = breakpoint + 1;
12514 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12521 parser->
current.end = breakpoint;
12522 pm_token_buffer_escape(parser, &token_buffer);
12523 token_buffer.
cursor = breakpoint;
12532 pm_newline_list_append(&parser->
newline_list, breakpoint);
12533 parser->
current.end = breakpoint + 1;
12534 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12538 parser->
current.end = breakpoint + 1;
12539 parser_flush_heredoc_end(parser);
12540 pm_token_buffer_flush(parser, &token_buffer);
12541 LEX(PM_TOKEN_STRING_CONTENT);
12544 parser->
current.end = breakpoint + 1;
12553 pm_token_buffer_escape(parser, &token_buffer);
12554 uint8_t peeked = peek(parser);
12558 pm_token_buffer_push_byte(&token_buffer,
'\\');
12563 if (peek(parser) !=
'\n') {
12565 pm_token_buffer_push_byte(&token_buffer,
'\\');
12567 pm_token_buffer_push_byte(&token_buffer,
'\r');
12573 pm_token_buffer_push_byte(&token_buffer,
'\\');
12574 pm_token_buffer_push_byte(&token_buffer,
'\n');
12581 parser_flush_heredoc_end(parser);
12582 pm_token_buffer_copy(parser, &token_buffer);
12583 LEX(PM_TOKEN_STRING_CONTENT);
12593 pm_token_buffer_push_byte(&token_buffer, peeked);
12596 pm_token_buffer_push_byte(&token_buffer, peeked);
12599 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12601 pm_token_buffer_push_byte(&token_buffer,
'\\');
12602 pm_token_buffer_push_escaped(&token_buffer, parser);
12609 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12613 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12615 if (
type == PM_TOKEN_NOT_PROVIDED) {
12620 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12624 if (
type == PM_TOKEN_STRING_CONTENT) {
12625 pm_token_buffer_flush(parser, &token_buffer);
12631 assert(
false &&
"unreachable");
12636 pm_token_buffer_flush(parser, &token_buffer);
12637 LEX(PM_TOKEN_STRING_CONTENT);
12643 pm_token_buffer_flush(parser, &token_buffer);
12644 LEX(PM_TOKEN_STRING_CONTENT);
12646 case PM_LEX_HEREDOC: {
12673 lex_state_set(parser, PM_LEX_STATE_END);
12674 lex_mode_pop(parser);
12675 LEX(PM_TOKEN_HEREDOC_END);
12678 const uint8_t *ident_start = heredoc_lex_mode->
ident_start;
12683 if (current_token_starts_line(parser)) {
12684 const uint8_t *start = parser->
current.start;
12686 if (!line_continuation && (start + ident_length <= parser->end)) {
12687 const uint8_t *newline = next_newline(start, parser->
end - start);
12688 const uint8_t *ident_end = newline;
12689 const uint8_t *terminator_end = newline;
12691 if (newline == NULL) {
12692 terminator_end = parser->
end;
12693 ident_end = parser->
end;
12696 if (newline[-1] ==
'\r') {
12701 const uint8_t *terminator_start = ident_end - ident_length;
12702 const uint8_t *cursor = start;
12704 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12705 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12711 (cursor == terminator_start) &&
12712 (memcmp(terminator_start, ident_start, ident_length) == 0)
12714 if (newline != NULL) {
12715 pm_newline_list_append(&parser->
newline_list, newline);
12718 parser->
current.end = terminator_end;
12726 lex_state_set(parser, PM_LEX_STATE_END);
12727 lex_mode_pop(parser);
12728 LEX(PM_TOKEN_HEREDOC_END);
12732 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, heredoc_lex_mode->
indent);
12734 heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE &&
12737 peek_at(parser, start) !=
'\n'
12746 uint8_t breakpoints[] =
"\r\n\\#";
12749 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12750 breakpoints[3] =
'\0';
12753 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12755 bool was_line_continuation =
false;
12757 while (breakpoint != NULL) {
12758 switch (*breakpoint) {
12761 parser->
current.end = breakpoint + 1;
12762 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12765 parser->
current.end = breakpoint + 1;
12767 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12768 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12775 pm_token_buffer_escape(parser, &token_buffer);
12776 token_buffer.
cursor = breakpoint;
12781 parser_flush_heredoc_end(parser);
12782 parser->
current.end = breakpoint + 1;
12783 pm_token_buffer_flush(parser, &token_buffer);
12784 LEX(PM_TOKEN_STRING_CONTENT);
12787 pm_newline_list_append(&parser->
newline_list, breakpoint);
12791 const uint8_t *start = breakpoint + 1;
12793 if (!was_line_continuation && (start + ident_length <= parser->end)) {
12796 const uint8_t *newline = next_newline(start, parser->
end - start);
12798 if (newline == NULL) {
12799 newline = parser->
end;
12800 }
else if (newline[-1] ==
'\r') {
12805 const uint8_t *terminator_start = newline - ident_length;
12809 const uint8_t *cursor = start;
12811 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12812 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12818 cursor == terminator_start &&
12819 (memcmp(terminator_start, ident_start, ident_length) == 0)
12821 parser->
current.end = breakpoint + 1;
12822 pm_token_buffer_flush(parser, &token_buffer);
12823 LEX(PM_TOKEN_STRING_CONTENT);
12827 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->
as.heredoc.
base.
indent);
12834 if (lex_mode->
as.heredoc.
base.
indent == PM_HEREDOC_INDENT_TILDE) {
12839 parser->
current.end = breakpoint + 1;
12840 pm_token_buffer_flush(parser, &token_buffer);
12841 LEX(PM_TOKEN_STRING_CONTENT);
12846 parser->
current.end = breakpoint + 1;
12847 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12857 parser->
current.end = breakpoint + 1;
12866 pm_token_buffer_escape(parser, &token_buffer);
12867 uint8_t peeked = peek(parser);
12869 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12873 if (peek(parser) !=
'\n') {
12874 pm_token_buffer_push_byte(&token_buffer,
'\\');
12875 pm_token_buffer_push_byte(&token_buffer,
'\r');
12880 pm_token_buffer_push_byte(&token_buffer,
'\\');
12881 pm_token_buffer_push_byte(&token_buffer,
'\n');
12883 breakpoint = parser->
current.end;
12886 pm_token_buffer_push_byte(&token_buffer,
'\\');
12887 pm_token_buffer_push_escaped(&token_buffer, parser);
12894 if (peek(parser) !=
'\n') {
12895 pm_token_buffer_push_byte(&token_buffer,
'\r');
12903 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12904 const uint8_t *end = parser->
current.end;
12909 parser->
current.end = breakpoint;
12910 pm_token_buffer_flush(parser, &token_buffer);
12914 parser->
current.end = end + 1;
12916 LEX(PM_TOKEN_STRING_CONTENT);
12919 was_line_continuation =
true;
12921 breakpoint = parser->
current.end;
12924 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12930 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12934 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12936 if (
type == PM_TOKEN_NOT_PROVIDED) {
12942 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12946 if (
type == PM_TOKEN_STRING_CONTENT) {
12947 pm_token_buffer_flush(parser, &token_buffer);
12953 assert(
false &&
"unreachable");
12956 was_line_continuation =
false;
12961 pm_token_buffer_flush(parser, &token_buffer);
12962 LEX(PM_TOKEN_STRING_CONTENT);
12968 pm_token_buffer_flush(parser, &token_buffer);
12969 LEX(PM_TOKEN_STRING_CONTENT);
12973 assert(
false &&
"unreachable");
12991 PM_BINDING_POWER_UNSET = 0,
12992 PM_BINDING_POWER_STATEMENT = 2,
12993 PM_BINDING_POWER_MODIFIER_RESCUE = 4,
12994 PM_BINDING_POWER_MODIFIER = 6,
12995 PM_BINDING_POWER_COMPOSITION = 8,
12996 PM_BINDING_POWER_NOT = 10,
12997 PM_BINDING_POWER_MATCH = 12,
12998 PM_BINDING_POWER_DEFINED = 14,
12999 PM_BINDING_POWER_MULTI_ASSIGNMENT = 16,
13000 PM_BINDING_POWER_ASSIGNMENT = 18,
13001 PM_BINDING_POWER_TERNARY = 20,
13002 PM_BINDING_POWER_RANGE = 22,
13003 PM_BINDING_POWER_LOGICAL_OR = 24,
13004 PM_BINDING_POWER_LOGICAL_AND = 26,
13005 PM_BINDING_POWER_EQUALITY = 28,
13006 PM_BINDING_POWER_COMPARISON = 30,
13007 PM_BINDING_POWER_BITWISE_OR = 32,
13008 PM_BINDING_POWER_BITWISE_AND = 34,
13009 PM_BINDING_POWER_SHIFT = 36,
13010 PM_BINDING_POWER_TERM = 38,
13011 PM_BINDING_POWER_FACTOR = 40,
13012 PM_BINDING_POWER_UMINUS = 42,
13013 PM_BINDING_POWER_EXPONENT = 44,
13014 PM_BINDING_POWER_UNARY = 46,
13015 PM_BINDING_POWER_INDEX = 48,
13016 PM_BINDING_POWER_CALL = 50,
13017 PM_BINDING_POWER_MAX = 52
13018} pm_binding_power_t;
13041#define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true, false }
13042#define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, false }
13043#define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true, false }
13044#define NON_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, true }
13045#define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false, false }
13049 [PM_TOKEN_KEYWORD_RESCUE_MODIFIER] = { PM_BINDING_POWER_MODIFIER_RESCUE, PM_BINDING_POWER_COMPOSITION,
true,
false },
13052 [PM_TOKEN_KEYWORD_IF_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
13053 [PM_TOKEN_KEYWORD_UNLESS_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
13054 [PM_TOKEN_KEYWORD_UNTIL_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
13055 [PM_TOKEN_KEYWORD_WHILE_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
13058 [PM_TOKEN_KEYWORD_AND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
13059 [PM_TOKEN_KEYWORD_OR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
13062 [PM_TOKEN_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
13063 [PM_TOKEN_KEYWORD_IN] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
13066 [PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
13067 [PM_TOKEN_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
13068 [PM_TOKEN_CARET_EQUAL] = BINDING_POWER_ASSIGNMENT,
13069 [PM_TOKEN_EQUAL] = BINDING_POWER_ASSIGNMENT,
13070 [PM_TOKEN_GREATER_GREATER_EQUAL] = BINDING_POWER_ASSIGNMENT,
13071 [PM_TOKEN_LESS_LESS_EQUAL] = BINDING_POWER_ASSIGNMENT,
13072 [PM_TOKEN_MINUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
13073 [PM_TOKEN_PERCENT_EQUAL] = BINDING_POWER_ASSIGNMENT,
13074 [PM_TOKEN_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
13075 [PM_TOKEN_PIPE_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
13076 [PM_TOKEN_PLUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
13077 [PM_TOKEN_SLASH_EQUAL] = BINDING_POWER_ASSIGNMENT,
13078 [PM_TOKEN_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
13079 [PM_TOKEN_STAR_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
13082 [PM_TOKEN_QUESTION_MARK] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_TERNARY),
13085 [PM_TOKEN_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
13086 [PM_TOKEN_DOT_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
13087 [PM_TOKEN_UDOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
13088 [PM_TOKEN_UDOT_DOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
13091 [PM_TOKEN_PIPE_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_OR),
13094 [PM_TOKEN_AMPERSAND_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_AND),
13097 [PM_TOKEN_BANG_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
13098 [PM_TOKEN_BANG_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
13099 [PM_TOKEN_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
13100 [PM_TOKEN_EQUAL_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
13101 [PM_TOKEN_EQUAL_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
13102 [PM_TOKEN_LESS_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
13105 [PM_TOKEN_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
13106 [PM_TOKEN_GREATER_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
13107 [PM_TOKEN_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
13108 [PM_TOKEN_LESS_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
13111 [PM_TOKEN_CARET] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
13112 [PM_TOKEN_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
13115 [PM_TOKEN_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_AND),
13118 [PM_TOKEN_GREATER_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
13119 [PM_TOKEN_LESS_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
13122 [PM_TOKEN_MINUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
13123 [PM_TOKEN_PLUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
13126 [PM_TOKEN_PERCENT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
13127 [PM_TOKEN_SLASH] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
13128 [PM_TOKEN_STAR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
13129 [PM_TOKEN_USTAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_FACTOR),
13132 [PM_TOKEN_UMINUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UMINUS),
13133 [PM_TOKEN_UMINUS_NUM] = { PM_BINDING_POWER_UMINUS, PM_BINDING_POWER_MAX,
false,
false },
13136 [PM_TOKEN_STAR_STAR] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_EXPONENT),
13137 [PM_TOKEN_USTAR_STAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13140 [PM_TOKEN_BANG] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13141 [PM_TOKEN_TILDE] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13142 [PM_TOKEN_UPLUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13145 [PM_TOKEN_BRACKET_LEFT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_INDEX),
13148 [PM_TOKEN_COLON_COLON] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
13149 [PM_TOKEN_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
13150 [PM_TOKEN_AMPERSAND_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL)
13153#undef BINDING_POWER_ASSIGNMENT
13154#undef LEFT_ASSOCIATIVE
13155#undef RIGHT_ASSOCIATIVE
13156#undef RIGHT_ASSOCIATIVE_UNARY
13170match2(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
13171 return match1(parser, type1) || match1(parser, type2);
13178match3(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3) {
13179 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3);
13186match4(
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) {
13187 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4);
13194match7(
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) {
13195 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7);
13202match8(
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) {
13203 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);
13214 if (match1(parser,
type)) {
13215 parser_lex(parser);
13226accept2(
pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
13227 if (match2(parser, type1, type2)) {
13228 parser_lex(parser);
13247 if (accept1(parser,
type))
return;
13250 pm_parser_err(parser, location, location, diag_id);
13262 if (accept2(parser, type1, type2))
return;
13265 pm_parser_err(parser, location, location, diag_id);
13276expect1_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
13277 if (match1(parser, PM_TOKEN_HEREDOC_END)) {
13278 parser_lex(parser);
13280 pm_parser_err_heredoc_term(parser, ident_start, ident_length);
13287parse_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);
13294parse_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) {
13295 pm_node_t *node = parse_expression(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
13296 pm_assert_value_expression(parser, node);
13319token_begins_expression_p(pm_token_type_t
type) {
13321 case PM_TOKEN_EQUAL_GREATER:
13322 case PM_TOKEN_KEYWORD_IN:
13326 case PM_TOKEN_BRACE_RIGHT:
13327 case PM_TOKEN_BRACKET_RIGHT:
13328 case PM_TOKEN_COLON:
13329 case PM_TOKEN_COMMA:
13330 case PM_TOKEN_EMBEXPR_END:
13332 case PM_TOKEN_LAMBDA_BEGIN:
13333 case PM_TOKEN_KEYWORD_DO:
13334 case PM_TOKEN_KEYWORD_DO_LOOP:
13335 case PM_TOKEN_KEYWORD_END:
13336 case PM_TOKEN_KEYWORD_ELSE:
13337 case PM_TOKEN_KEYWORD_ELSIF:
13338 case PM_TOKEN_KEYWORD_ENSURE:
13339 case PM_TOKEN_KEYWORD_THEN:
13340 case PM_TOKEN_KEYWORD_RESCUE:
13341 case PM_TOKEN_KEYWORD_WHEN:
13342 case PM_TOKEN_NEWLINE:
13343 case PM_TOKEN_PARENTHESIS_RIGHT:
13344 case PM_TOKEN_SEMICOLON:
13350 assert(pm_binding_powers[
type].left == PM_BINDING_POWER_UNSET);
13352 case PM_TOKEN_UAMPERSAND:
13356 case PM_TOKEN_UCOLON_COLON:
13357 case PM_TOKEN_UMINUS:
13358 case PM_TOKEN_UMINUS_NUM:
13359 case PM_TOKEN_UPLUS:
13360 case PM_TOKEN_BANG:
13361 case PM_TOKEN_TILDE:
13362 case PM_TOKEN_UDOT_DOT:
13363 case PM_TOKEN_UDOT_DOT_DOT:
13370 return pm_binding_powers[
type].left == PM_BINDING_POWER_UNSET;
13379parse_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) {
13380 if (accept1(parser, PM_TOKEN_USTAR)) {
13382 pm_node_t *expression = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13383 return (pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
13386 return parse_value_expression(parser, binding_power, accepts_command_call,
false, diag_id, depth);
13400 size_t length = constant->
length;
13401 uint8_t *name =
xcalloc(length + 1,
sizeof(uint8_t));
13402 if (name == NULL)
return;
13404 memcpy(name, constant->
start, length);
13405 name[length] =
'=';
13410 *name_field = pm_constant_pool_insert_owned(&parser->
constant_pool, name, length + 1);
13420parse_unwriteable_target(
pm_parser_t *parser, pm_node_t *target) {
13421 switch (PM_NODE_TYPE(target)) {
13422 case PM_SOURCE_ENCODING_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13423 case PM_FALSE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13424 case PM_SOURCE_FILE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13425 case PM_SOURCE_LINE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13426 case PM_NIL_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13427 case PM_SELF_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13428 case PM_TRUE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13433 pm_local_variable_target_node_t *result = pm_local_variable_target_node_create(parser, &target->
location, name, 0);
13435 pm_node_destroy(parser, target);
13436 return (pm_node_t *) result;
13445parse_target_implicit_parameter(
pm_parser_t *parser, pm_node_t *node) {
13448 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
13449 if (implicit_parameters->
nodes[index] == node) {
13453 if (index != implicit_parameters->
size - 1) {
13454 memcpy(&implicit_parameters->
nodes[index], &implicit_parameters->
nodes[index + 1], (implicit_parameters->
size - index - 1) *
sizeof(pm_node_t *));
13457 implicit_parameters->
size--;
13472parse_target(
pm_parser_t *parser, pm_node_t *target,
bool multiple,
bool splat_parent) {
13473 switch (PM_NODE_TYPE(target)) {
13474 case PM_MISSING_NODE:
13476 case PM_SOURCE_ENCODING_NODE:
13477 case PM_FALSE_NODE:
13478 case PM_SOURCE_FILE_NODE:
13479 case PM_SOURCE_LINE_NODE:
13482 case PM_TRUE_NODE: {
13485 return parse_unwriteable_target(parser, target);
13487 case PM_CLASS_VARIABLE_READ_NODE:
13488 assert(
sizeof(pm_class_variable_target_node_t) ==
sizeof(pm_class_variable_read_node_t));
13489 target->
type = PM_CLASS_VARIABLE_TARGET_NODE;
13491 case PM_CONSTANT_PATH_NODE:
13492 if (context_def_p(parser)) {
13493 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13496 assert(
sizeof(pm_constant_path_target_node_t) ==
sizeof(pm_constant_path_node_t));
13497 target->
type = PM_CONSTANT_PATH_TARGET_NODE;
13500 case PM_CONSTANT_READ_NODE:
13501 if (context_def_p(parser)) {
13502 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13505 assert(
sizeof(pm_constant_target_node_t) ==
sizeof(pm_constant_read_node_t));
13506 target->
type = PM_CONSTANT_TARGET_NODE;
13509 case PM_BACK_REFERENCE_READ_NODE:
13510 case PM_NUMBERED_REFERENCE_READ_NODE:
13511 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13513 case PM_GLOBAL_VARIABLE_READ_NODE:
13514 assert(
sizeof(pm_global_variable_target_node_t) ==
sizeof(pm_global_variable_read_node_t));
13515 target->
type = PM_GLOBAL_VARIABLE_TARGET_NODE;
13517 case PM_LOCAL_VARIABLE_READ_NODE: {
13520 parse_target_implicit_parameter(parser, target);
13523 const pm_local_variable_read_node_t *cast = (
const pm_local_variable_read_node_t *) target;
13524 uint32_t name = cast->
name;
13525 uint32_t depth = cast->
depth;
13526 pm_locals_unread(&pm_parser_scope_find(parser, depth)->locals, name);
13528 assert(
sizeof(pm_local_variable_target_node_t) ==
sizeof(pm_local_variable_read_node_t));
13529 target->
type = PM_LOCAL_VARIABLE_TARGET_NODE;
13533 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
13535 pm_node_t *node = (pm_node_t *) pm_local_variable_target_node_create(parser, &target->
location, name, 0);
13537 parse_target_implicit_parameter(parser, target);
13538 pm_node_destroy(parser, target);
13542 case PM_INSTANCE_VARIABLE_READ_NODE:
13543 assert(
sizeof(pm_instance_variable_target_node_t) ==
sizeof(pm_instance_variable_read_node_t));
13544 target->
type = PM_INSTANCE_VARIABLE_TARGET_NODE;
13546 case PM_MULTI_TARGET_NODE:
13547 if (splat_parent) {
13550 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13554 case PM_SPLAT_NODE: {
13555 pm_splat_node_t *splat = (pm_splat_node_t *) target;
13561 return (pm_node_t *) splat;
13563 case PM_CALL_NODE: {
13564 pm_call_node_t *call = (pm_call_node_t *) target;
13575 (call->
block == NULL)
13590 pm_node_destroy(parser, target);
13592 return (pm_node_t *) pm_local_variable_target_node_create(parser, &message_loc, name, 0);
13596 if (multiple && PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
13597 pm_parser_err_node(parser, (
const pm_node_t *) call, PM_ERR_UNEXPECTED_SAFE_NAVIGATION);
13600 parse_write_name(parser, &call->
name);
13601 return (pm_node_t *) pm_call_target_node_create(parser, call);
13608 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
13609 return (pm_node_t *) pm_index_target_node_create(parser, call);
13617 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13627parse_target_validate(
pm_parser_t *parser, pm_node_t *target,
bool multiple) {
13628 pm_node_t *result = parse_target(parser, target, multiple,
false);
13633 !match1(parser, PM_TOKEN_EQUAL) &&
13635 !(context_p(parser,
PM_CONTEXT_PARENS) && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
13637 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13648parse_shareable_constant_write(
pm_parser_t *parser, pm_node_t *write) {
13651 if (shareable_constant != PM_SCOPE_SHAREABLE_CONSTANT_NONE) {
13652 return (pm_node_t *) pm_shareable_constant_node_create(parser, write, shareable_constant);
13663 switch (PM_NODE_TYPE(target)) {
13664 case PM_MISSING_NODE:
13665 pm_node_destroy(parser, value);
13667 case PM_CLASS_VARIABLE_READ_NODE: {
13668 pm_class_variable_write_node_t *node = pm_class_variable_write_node_create(parser, (pm_class_variable_read_node_t *) target,
operator, value);
13669 pm_node_destroy(parser, target);
13670 return (pm_node_t *) node;
13672 case PM_CONSTANT_PATH_NODE: {
13673 pm_node_t *node = (pm_node_t *) pm_constant_path_write_node_create(parser, (pm_constant_path_node_t *) target,
operator, value);
13675 if (context_def_p(parser)) {
13676 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13679 return parse_shareable_constant_write(parser, node);
13681 case PM_CONSTANT_READ_NODE: {
13682 pm_node_t *node = (pm_node_t *) pm_constant_write_node_create(parser, (pm_constant_read_node_t *) target,
operator, value);
13684 if (context_def_p(parser)) {
13685 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13688 pm_node_destroy(parser, target);
13689 return parse_shareable_constant_write(parser, node);
13691 case PM_BACK_REFERENCE_READ_NODE:
13692 case PM_NUMBERED_REFERENCE_READ_NODE:
13693 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13695 case PM_GLOBAL_VARIABLE_READ_NODE: {
13696 pm_global_variable_write_node_t *node = pm_global_variable_write_node_create(parser, target,
operator, value);
13697 pm_node_destroy(parser, target);
13698 return (pm_node_t *) node;
13700 case PM_LOCAL_VARIABLE_READ_NODE: {
13701 pm_local_variable_read_node_t *local_read = (pm_local_variable_read_node_t *) target;
13706 uint32_t depth = local_read->
depth;
13707 pm_scope_t *scope = pm_parser_scope_find(parser, depth);
13710 pm_diagnostic_id_t diag_id = (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND) ? PM_ERR_EXPRESSION_NOT_WRITABLE_NUMBERED : PM_ERR_PARAMETER_NUMBERED_RESERVED;
13712 parse_target_implicit_parameter(parser, target);
13715 pm_locals_unread(&scope->
locals, name);
13716 pm_node_destroy(parser, target);
13718 return (pm_node_t *) pm_local_variable_write_node_create(parser, name, depth, value, &name_loc,
operator);
13720 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
13722 pm_node_t *node = (pm_node_t *) pm_local_variable_write_node_create(parser, name, 0, value, &target->
location,
operator);
13724 parse_target_implicit_parameter(parser, target);
13725 pm_node_destroy(parser, target);
13729 case PM_INSTANCE_VARIABLE_READ_NODE: {
13730 pm_node_t *write_node = (pm_node_t *) pm_instance_variable_write_node_create(parser, (pm_instance_variable_read_node_t *) target,
operator, value);
13731 pm_node_destroy(parser, target);
13734 case PM_MULTI_TARGET_NODE:
13735 return (pm_node_t *) pm_multi_write_node_create(parser, (pm_multi_target_node_t *) target,
operator, value);
13736 case PM_SPLAT_NODE: {
13737 pm_splat_node_t *splat = (pm_splat_node_t *) target;
13743 pm_multi_target_node_t *multi_target = pm_multi_target_node_create(parser);
13744 pm_multi_target_node_targets_append(parser, multi_target, (pm_node_t *) splat);
13746 return (pm_node_t *) pm_multi_write_node_create(parser, multi_target,
operator, value);
13748 case PM_CALL_NODE: {
13749 pm_call_node_t *call = (pm_call_node_t *) target;
13760 (call->
block == NULL)
13774 pm_parser_local_add_location(parser, message.
start, message.
end, 0);
13775 pm_node_destroy(parser, target);
13778 target = (pm_node_t *) pm_local_variable_write_node_create(parser, constant_id, 0, value, &message,
operator);
13780 pm_refute_numbered_parameter(parser, message.
start, message.
end);
13795 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
13798 pm_arguments_node_arguments_append(arguments, value);
13801 parse_write_name(parser, &call->
name);
13802 pm_node_flag_set((pm_node_t *) call, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
13804 return (pm_node_t *) call;
13811 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
13813 call->
arguments = pm_arguments_node_create(parser);
13816 pm_arguments_node_arguments_append(call->
arguments, value);
13820 call->
name = pm_parser_constant_id_constant(parser,
"[]=", 3);
13824 pm_node_flag_set((pm_node_t *) call, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
13834 pm_node_destroy(parser, value);
13841 pm_parser_err_token(parser,
operator, PM_ERR_WRITE_TARGET_UNEXPECTED);
13853parse_unwriteable_write(
pm_parser_t *parser, pm_node_t *target,
const pm_token_t *equals, pm_node_t *value) {
13854 switch (PM_NODE_TYPE(target)) {
13855 case PM_SOURCE_ENCODING_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13856 case PM_FALSE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13857 case PM_SOURCE_FILE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13858 case PM_SOURCE_LINE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13859 case PM_NIL_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13860 case PM_SELF_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13861 case PM_TRUE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13866 pm_local_variable_write_node_t *result = pm_local_variable_write_node_create(parser, name, 0, value, &target->
location, equals);
13868 pm_node_destroy(parser, target);
13869 return (pm_node_t *) result;
13883parse_targets(
pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13884 bool has_rest = PM_NODE_TYPE_P(first_target, PM_SPLAT_NODE);
13886 pm_multi_target_node_t *result = pm_multi_target_node_create(parser);
13887 pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target,
true,
false));
13889 while (accept1(parser, PM_TOKEN_COMMA)) {
13890 if (accept1(parser, PM_TOKEN_USTAR)) {
13895 pm_parser_err_previous(parser, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
13899 pm_node_t *name = NULL;
13901 if (token_begins_expression_p(parser->
current.type)) {
13902 name = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13903 name = parse_target(parser, name,
true,
true);
13906 pm_node_t *splat = (pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
13907 pm_multi_target_node_targets_append(parser, result, splat);
13909 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
13911 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13912 target = parse_target(parser, target,
true,
false);
13914 pm_multi_target_node_targets_append(parser, result, target);
13915 context_pop(parser);
13916 }
else if (token_begins_expression_p(parser->
current.type)) {
13917 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13918 target = parse_target(parser, target,
true,
false);
13920 pm_multi_target_node_targets_append(parser, result, target);
13921 }
else if (!match1(parser, PM_TOKEN_EOF)) {
13924 pm_node_t *rest = (pm_node_t *) pm_implicit_rest_node_create(parser, &parser->
previous);
13925 pm_multi_target_node_targets_append(parser, result, rest);
13930 return (pm_node_t *) result;
13938parse_targets_validate(
pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13939 pm_node_t *result = parse_targets(parser, first_target, binding_power, depth);
13940 accept1(parser, PM_TOKEN_NEWLINE);
13943 if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
13944 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13953static pm_statements_node_t *
13957 while (accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE));
13960 if (context_terminator(context, &parser->
current))
return NULL;
13962 pm_statements_node_t *statements = pm_statements_node_create(parser);
13966 context_push(parser, context);
13969 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
13970 pm_statements_node_body_append(parser, statements, node,
true);
13983 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
13986 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13987 if (context_terminator(context, &parser->
current))
break;
13997 if (context_terminator(context, &parser->
current))
break;
14009 if (PM_NODE_TYPE_P(node, PM_MISSING_NODE)) {
14010 parser_lex(parser);
14016 if (match1(parser, PM_TOKEN_EOF)) {
14021 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
14022 if (context_terminator(context, &parser->
current))
break;
14023 }
else if (!accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_EOF)) {
14033 context_pop(parser);
14034 bool last_value =
true;
14038 last_value =
false;
14043 pm_void_statements_check(parser, statements, last_value);
14054 const pm_node_t *duplicated = pm_static_literals_add(&parser->
newline_list, parser->
start_line, literals, node,
true);
14056 if (duplicated != NULL) {
14060 pm_diagnostic_list_append_format(
14064 PM_WARN_DUPLICATED_HASH_KEY,
14065 (
int) pm_buffer_length(&buffer),
14066 pm_buffer_value(&buffer),
14070 pm_buffer_free(&buffer);
14080 pm_node_t *previous;
14082 if ((previous = pm_static_literals_add(&parser->
newline_list, parser->
start_line, literals, node,
false)) != NULL) {
14083 pm_diagnostic_list_append_format(
14087 PM_WARN_DUPLICATED_WHEN_CLAUSE,
14099 assert(PM_NODE_TYPE_P(node, PM_HASH_NODE) || PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE));
14100 bool contains_keyword_splat =
false;
14103 pm_node_t *element;
14105 switch (parser->
current.type) {
14106 case PM_TOKEN_USTAR_STAR: {
14107 parser_lex(parser);
14109 pm_node_t *value = NULL;
14111 if (match1(parser, PM_TOKEN_BRACE_LEFT)) {
14117 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
14118 }
else if (token_begins_expression_p(parser->
current.type)) {
14119 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
14121 pm_parser_scope_forwarding_keywords_check(parser, &
operator);
14124 element = (pm_node_t *) pm_assoc_splat_node_create(parser, value, &
operator);
14125 contains_keyword_splat =
true;
14128 case PM_TOKEN_LABEL: {
14130 parser_lex(parser);
14132 pm_node_t *key = (pm_node_t *) pm_symbol_node_label_create(parser, &label);
14133 pm_hash_key_static_literals_add(parser, literals, key);
14136 pm_node_t *value = NULL;
14138 if (token_begins_expression_p(parser->
current.type)) {
14139 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_EXPRESSION_AFTER_LABEL, (uint16_t) (depth + 1));
14142 pm_token_t constant = { .type = PM_TOKEN_CONSTANT, .start = label.
start, .end = label.
end - 1 };
14143 value = (pm_node_t *) pm_constant_read_node_create(parser, &constant);
14146 pm_token_t identifier = { .type = PM_TOKEN_IDENTIFIER, .start = label.
start, .end = label.
end - 1 };
14148 if (identifier.
end[-1] ==
'!' || identifier.
end[-1] ==
'?') {
14149 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, identifier, PM_ERR_INVALID_LOCAL_VARIABLE_READ);
14151 depth = pm_parser_local_depth(parser, &identifier);
14155 value = (pm_node_t *) pm_call_node_variable_call_create(parser, &identifier);
14157 value = (pm_node_t *) pm_local_variable_read_node_create(parser, &identifier, (uint32_t) depth);
14162 value = (pm_node_t *) pm_implicit_node_create(parser, value);
14165 element = (pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
14169 pm_node_t *key = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_HASH_KEY, (uint16_t) (depth + 1));
14173 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
14174 pm_node_flag_set(key, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
14177 pm_hash_key_static_literals_add(parser, literals, key);
14180 if (pm_symbol_node_label_p(key)) {
14181 operator = not_provided(parser);
14183 expect1(parser, PM_TOKEN_EQUAL_GREATER, PM_ERR_HASH_ROCKET);
14187 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
14188 element = (pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
14193 if (PM_NODE_TYPE_P(node, PM_HASH_NODE)) {
14194 pm_hash_node_elements_append((pm_hash_node_t *) node, element);
14196 pm_keyword_hash_node_elements_append((pm_keyword_hash_node_t *) node, element);
14200 if (!accept1(parser, PM_TOKEN_COMMA))
break;
14204 if (match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL))
continue;
14208 if (token_begins_expression_p(parser->
current.type))
continue;
14214 return contains_keyword_splat;
14223 arguments->
arguments = pm_arguments_node_create(parser);
14226 pm_arguments_node_arguments_append(arguments->
arguments, argument);
14233parse_arguments(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_forwarding, pm_token_type_t terminator, uint16_t depth) {
14234 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].left;
14239 match2(parser, terminator, PM_TOKEN_EOF) ||
14240 (binding_power != PM_BINDING_POWER_UNSET && binding_power < PM_BINDING_POWER_RANGE) ||
14246 bool parsed_first_argument =
false;
14247 bool parsed_bare_hash =
false;
14248 bool parsed_block_argument =
false;
14249 bool parsed_forwarding_arguments =
false;
14251 while (!match1(parser, PM_TOKEN_EOF)) {
14252 if (parsed_forwarding_arguments) {
14253 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES);
14256 pm_node_t *argument = NULL;
14258 switch (parser->
current.type) {
14259 case PM_TOKEN_USTAR_STAR:
14260 case PM_TOKEN_LABEL: {
14261 if (parsed_bare_hash) {
14262 pm_parser_err_current(parser, PM_ERR_ARGUMENT_BARE_HASH);
14265 pm_keyword_hash_node_t *hash = pm_keyword_hash_node_create(parser);
14266 argument = (pm_node_t *) hash;
14269 bool contains_keyword_splat = parse_assocs(parser, &hash_keys, (pm_node_t *) hash, (uint16_t) (depth + 1));
14271 parse_arguments_append(parser, arguments, argument);
14273 pm_node_flags_t flags = PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
14274 if (contains_keyword_splat) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
14275 pm_node_flag_set((pm_node_t *) arguments->
arguments, flags);
14277 pm_static_literals_free(&hash_keys);
14278 parsed_bare_hash =
true;
14282 case PM_TOKEN_UAMPERSAND: {
14283 parser_lex(parser);
14285 pm_node_t *expression = NULL;
14287 if (token_begins_expression_p(parser->
current.type)) {
14288 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14290 pm_parser_scope_forwarding_block_check(parser, &
operator);
14293 argument = (pm_node_t *) pm_block_argument_node_create(parser, &
operator, expression);
14294 if (parsed_block_argument) {
14295 parse_arguments_append(parser, arguments, argument);
14297 arguments->
block = argument;
14300 if (match1(parser, PM_TOKEN_COMMA)) {
14301 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK);
14304 parsed_block_argument =
true;
14307 case PM_TOKEN_USTAR: {
14308 parser_lex(parser);
14311 if (match4(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_SEMICOLON, PM_TOKEN_BRACKET_RIGHT)) {
14312 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
14313 argument = (pm_node_t *) pm_splat_node_create(parser, &
operator, NULL);
14314 if (parsed_bare_hash) {
14315 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
14318 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT, (uint16_t) (depth + 1));
14320 if (parsed_bare_hash) {
14321 pm_parser_err(parser,
operator.start, expression->
location.
end, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
14324 argument = (pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
14327 parse_arguments_append(parser, arguments, argument);
14330 case PM_TOKEN_UDOT_DOT_DOT: {
14331 if (accepts_forwarding) {
14332 parser_lex(parser);
14334 if (token_begins_expression_p(parser->
current.type)) {
14339 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_RANGE,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
14344 if (PM_NODE_TYPE_P(right, PM_RANGE_NODE)) {
14345 pm_range_node_t *range = (pm_range_node_t *) right;
14346 pm_parser_err(parser, range->operator_loc.start, range->operator_loc.end, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
14349 argument = (pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
14351 pm_parser_scope_forwarding_all_check(parser, &parser->
previous);
14352 if (parsed_first_argument && terminator == PM_TOKEN_EOF) {
14353 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORWARDING_UNBOUND);
14356 argument = (pm_node_t *) pm_forwarding_arguments_node_create(parser, &parser->
previous);
14357 parse_arguments_append(parser, arguments, argument);
14358 pm_node_flag_set((pm_node_t *) arguments->
arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING);
14360 parsed_forwarding_arguments =
true;
14367 if (argument == NULL) {
14368 argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, !parsed_first_argument,
true, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14371 bool contains_keywords =
false;
14372 bool contains_keyword_splat =
false;
14374 if (pm_symbol_node_label_p(argument) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
14375 if (parsed_bare_hash) {
14376 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
14380 if (parser->
previous.
type == PM_TOKEN_EQUAL_GREATER) {
14383 operator = not_provided(parser);
14386 pm_keyword_hash_node_t *bare_hash = pm_keyword_hash_node_create(parser);
14387 contains_keywords =
true;
14391 pm_hash_key_static_literals_add(parser, &hash_keys, argument);
14394 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
14395 argument = (pm_node_t *) pm_assoc_node_create(parser, argument, &
operator, value);
14397 pm_keyword_hash_node_elements_append(bare_hash, argument);
14398 argument = (pm_node_t *) bare_hash;
14401 if (accept1(parser, PM_TOKEN_COMMA) && (
14402 token_begins_expression_p(parser->
current.type) ||
14403 match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL)
14405 contains_keyword_splat = parse_assocs(parser, &hash_keys, (pm_node_t *) bare_hash, (uint16_t) (depth + 1));
14408 pm_static_literals_free(&hash_keys);
14409 parsed_bare_hash =
true;
14412 parse_arguments_append(parser, arguments, argument);
14414 pm_node_flags_t flags = 0;
14415 if (contains_keywords) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
14416 if (contains_keyword_splat) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
14417 pm_node_flag_set((pm_node_t *) arguments->
arguments, flags);
14423 parsed_first_argument =
true;
14426 if (PM_NODE_TYPE_P(argument, PM_MISSING_NODE) || parser->
recovering)
break;
14431 bool accepted_newline =
false;
14432 if (terminator != PM_TOKEN_EOF) {
14433 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
14436 if (parser->
previous.
type == PM_TOKEN_COMMA && parsed_bare_hash) {
14440 }
else if (accept1(parser, PM_TOKEN_COMMA)) {
14443 if (accepted_newline) {
14444 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14454 if (match1(parser, terminator))
break;
14468static pm_multi_target_node_t *
14469parse_required_destructured_parameter(
pm_parser_t *parser) {
14470 expect1(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_ERR_EXPECT_LPAREN_REQ_PARAMETER);
14472 pm_multi_target_node_t *node = pm_multi_target_node_create(parser);
14473 pm_multi_target_node_opening_set(node, &parser->
previous);
14482 if (node->
lefts.
size > 0 && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
14483 param = (pm_node_t *) pm_implicit_rest_node_create(parser, &parser->
previous);
14484 pm_multi_target_node_targets_append(parser, node, param);
14485 pm_parser_err_current(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14489 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
14490 param = (pm_node_t *) parse_required_destructured_parameter(parser);
14491 }
else if (accept1(parser, PM_TOKEN_USTAR)) {
14493 pm_node_t *value = NULL;
14495 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14497 value = (pm_node_t *) pm_required_parameter_node_create(parser, &name);
14498 if (pm_parser_parameter_name_check(parser, &name)) {
14499 pm_node_flag_set_repeated_parameter(value);
14501 pm_parser_local_add_token(parser, &name, 1);
14504 param = (pm_node_t *) pm_splat_node_create(parser, &star, value);
14506 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EXPECT_IDENT_REQ_PARAMETER);
14509 param = (pm_node_t *) pm_required_parameter_node_create(parser, &name);
14510 if (pm_parser_parameter_name_check(parser, &name)) {
14511 pm_node_flag_set_repeated_parameter(param);
14513 pm_parser_local_add_token(parser, &name, 1);
14516 pm_multi_target_node_targets_append(parser, node, param);
14517 }
while (accept1(parser, PM_TOKEN_COMMA));
14519 accept1(parser, PM_TOKEN_NEWLINE);
14520 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN_REQ_PARAMETER);
14521 pm_multi_target_node_closing_set(node, &parser->
previous);
14531 PM_PARAMETERS_NO_CHANGE = 0,
14532 PM_PARAMETERS_ORDER_NOTHING_AFTER = 1,
14533 PM_PARAMETERS_ORDER_KEYWORDS_REST,
14534 PM_PARAMETERS_ORDER_KEYWORDS,
14535 PM_PARAMETERS_ORDER_REST,
14536 PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14537 PM_PARAMETERS_ORDER_OPTIONAL,
14538 PM_PARAMETERS_ORDER_NAMED,
14539 PM_PARAMETERS_ORDER_NONE,
14540} pm_parameters_order_t;
14545static pm_parameters_order_t parameters_ordering[PM_TOKEN_MAXIMUM] = {
14546 [0] = PM_PARAMETERS_NO_CHANGE,
14547 [PM_TOKEN_UAMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14548 [PM_TOKEN_AMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14549 [PM_TOKEN_UDOT_DOT_DOT] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14550 [PM_TOKEN_IDENTIFIER] = PM_PARAMETERS_ORDER_NAMED,
14551 [PM_TOKEN_PARENTHESIS_LEFT] = PM_PARAMETERS_ORDER_NAMED,
14552 [PM_TOKEN_EQUAL] = PM_PARAMETERS_ORDER_OPTIONAL,
14553 [PM_TOKEN_LABEL] = PM_PARAMETERS_ORDER_KEYWORDS,
14554 [PM_TOKEN_USTAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14555 [PM_TOKEN_STAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14556 [PM_TOKEN_USTAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST,
14557 [PM_TOKEN_STAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST
14569 pm_parameters_order_t state = parameters_ordering[token->type];
14570 if (state == PM_PARAMETERS_NO_CHANGE)
return true;
14574 if (*current == PM_PARAMETERS_ORDER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14575 *current = PM_PARAMETERS_ORDER_AFTER_OPTIONAL;
14577 }
else if (*current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14581 if (token->type == PM_TOKEN_USTAR && *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14582 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_STAR);
14584 }
else if (token->type == PM_TOKEN_UDOT_DOT_DOT && (*current >= PM_PARAMETERS_ORDER_KEYWORDS_REST && *current <= PM_PARAMETERS_ORDER_AFTER_OPTIONAL)) {
14585 pm_parser_err_token(parser, token, *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL ? PM_ERR_PARAMETER_FORWARDING_AFTER_REST : PM_ERR_PARAMETER_ORDER);
14587 }
else if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
14589 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_ORDER);
14593 if (state < *current) *current = state;
14600static pm_parameters_node_t *
14603 pm_binding_power_t binding_power,
14604 bool uses_parentheses,
14605 bool allows_trailing_comma,
14606 bool allows_forwarding_parameters,
14607 bool accepts_blocks_in_defaults,
14611 pm_do_loop_stack_push(parser,
false);
14613 pm_parameters_node_t *params = pm_parameters_node_create(parser);
14614 pm_parameters_order_t order = PM_PARAMETERS_ORDER_NONE;
14617 bool parsing =
true;
14619 switch (parser->
current.type) {
14620 case PM_TOKEN_PARENTHESIS_LEFT: {
14621 update_parameter_state(parser, &parser->
current, &order);
14622 pm_node_t *param = (pm_node_t *) parse_required_destructured_parameter(parser);
14624 if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14625 pm_parameters_node_requireds_append(params, param);
14627 pm_parameters_node_posts_append(params, param);
14631 case PM_TOKEN_UAMPERSAND:
14632 case PM_TOKEN_AMPERSAND: {
14633 update_parameter_state(parser, &parser->
current, &order);
14634 parser_lex(parser);
14639 bool repeated =
false;
14640 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14642 repeated = pm_parser_parameter_name_check(parser, &name);
14643 pm_parser_local_add_token(parser, &name, 1);
14645 name = not_provided(parser);
14649 pm_block_parameter_node_t *param = pm_block_parameter_node_create(parser, &name, &
operator);
14651 pm_node_flag_set_repeated_parameter((pm_node_t *)param);
14653 if (params->
block == NULL) {
14654 pm_parameters_node_block_set(params, param);
14656 pm_parser_err_node(parser, (pm_node_t *) param, PM_ERR_PARAMETER_BLOCK_MULTI);
14657 pm_parameters_node_posts_append(params, (pm_node_t *) param);
14662 case PM_TOKEN_UDOT_DOT_DOT: {
14663 if (!allows_forwarding_parameters) {
14664 pm_parser_err_current(parser, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
14667 bool succeeded = update_parameter_state(parser, &parser->
current, &order);
14668 parser_lex(parser);
14671 pm_forwarding_parameter_node_t *param = pm_forwarding_parameter_node_create(parser, &parser->
previous);
14677 pm_parameters_node_posts_append(params, keyword_rest);
14678 if (succeeded) pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD);
14682 pm_parameters_node_keyword_rest_set(params, (pm_node_t *) param);
14685 case PM_TOKEN_CLASS_VARIABLE:
14686 case PM_TOKEN_IDENTIFIER:
14687 case PM_TOKEN_CONSTANT:
14688 case PM_TOKEN_INSTANCE_VARIABLE:
14689 case PM_TOKEN_GLOBAL_VARIABLE:
14690 case PM_TOKEN_METHOD_NAME: {
14691 parser_lex(parser);
14693 case PM_TOKEN_CONSTANT:
14694 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14696 case PM_TOKEN_INSTANCE_VARIABLE:
14697 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
14699 case PM_TOKEN_GLOBAL_VARIABLE:
14700 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
14702 case PM_TOKEN_CLASS_VARIABLE:
14703 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
14705 case PM_TOKEN_METHOD_NAME:
14706 pm_parser_err_previous(parser, PM_ERR_PARAMETER_METHOD_NAME);
14711 if (parser->
current.type == PM_TOKEN_EQUAL) {
14712 update_parameter_state(parser, &parser->
current, &order);
14714 update_parameter_state(parser, &parser->
previous, &order);
14718 bool repeated = pm_parser_parameter_name_check(parser, &name);
14719 pm_parser_local_add_token(parser, &name, 1);
14721 if (match1(parser, PM_TOKEN_EQUAL)) {
14724 parser_lex(parser);
14729 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14730 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
14731 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14733 pm_optional_parameter_node_t *param = pm_optional_parameter_node_create(parser, &name, &
operator, value);
14736 pm_node_flag_set_repeated_parameter((pm_node_t *) param);
14738 pm_parameters_node_optionals_append(params, param);
14744 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, name, PM_ERR_PARAMETER_CIRCULAR);
14747 context_pop(parser);
14756 }
else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14757 pm_required_parameter_node_t *param = pm_required_parameter_node_create(parser, &name);
14759 pm_node_flag_set_repeated_parameter((pm_node_t *)param);
14761 pm_parameters_node_requireds_append(params, (pm_node_t *) param);
14763 pm_required_parameter_node_t *param = pm_required_parameter_node_create(parser, &name);
14765 pm_node_flag_set_repeated_parameter((pm_node_t *)param);
14767 pm_parameters_node_posts_append(params, (pm_node_t *) param);
14772 case PM_TOKEN_LABEL: {
14773 if (!uses_parentheses && !in_block) parser->
in_keyword_arg =
true;
14774 update_parameter_state(parser, &parser->
current, &order);
14777 parser_lex(parser);
14784 pm_parser_err(parser, local.
start, local.
end, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14785 }
else if (local.
end[-1] ==
'!' || local.
end[-1] ==
'?') {
14786 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
14789 bool repeated = pm_parser_parameter_name_check(parser, &local);
14790 pm_parser_local_add_token(parser, &local, 1);
14792 switch (parser->
current.type) {
14793 case PM_TOKEN_COMMA:
14794 case PM_TOKEN_PARENTHESIS_RIGHT:
14795 case PM_TOKEN_PIPE: {
14796 context_pop(parser);
14798 pm_node_t *param = (pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14800 pm_node_flag_set_repeated_parameter(param);
14803 pm_parameters_node_keywords_append(params, param);
14806 case PM_TOKEN_SEMICOLON:
14807 case PM_TOKEN_NEWLINE: {
14808 context_pop(parser);
14810 if (uses_parentheses) {
14815 pm_node_t *param = (pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14817 pm_node_flag_set_repeated_parameter(param);
14820 pm_parameters_node_keywords_append(params, param);
14826 if (token_begins_expression_p(parser->
current.type)) {
14830 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14831 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT_KW, (uint16_t) (depth + 1));
14832 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14835 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_PARAMETER_CIRCULAR);
14838 param = (pm_node_t *) pm_optional_keyword_parameter_node_create(parser, &name, value);
14841 param = (pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14845 pm_node_flag_set_repeated_parameter(param);
14848 context_pop(parser);
14849 pm_parameters_node_keywords_append(params, param);
14864 case PM_TOKEN_USTAR:
14865 case PM_TOKEN_STAR: {
14866 update_parameter_state(parser, &parser->
current, &order);
14867 parser_lex(parser);
14871 bool repeated =
false;
14873 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14875 repeated = pm_parser_parameter_name_check(parser, &name);
14876 pm_parser_local_add_token(parser, &name, 1);
14878 name = not_provided(parser);
14882 pm_node_t *param = (pm_node_t *) pm_rest_parameter_node_create(parser, &
operator, &name);
14884 pm_node_flag_set_repeated_parameter(param);
14887 if (params->
rest == NULL) {
14888 pm_parameters_node_rest_set(params, param);
14890 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_SPLAT_MULTI);
14891 pm_parameters_node_posts_append(params, param);
14896 case PM_TOKEN_STAR_STAR:
14897 case PM_TOKEN_USTAR_STAR: {
14898 pm_parameters_order_t previous_order = order;
14899 update_parameter_state(parser, &parser->
current, &order);
14900 parser_lex(parser);
14905 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
14906 if (previous_order <= PM_PARAMETERS_ORDER_KEYWORDS) {
14907 pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_NO_KW);
14910 param = (pm_node_t *) pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous);
14914 bool repeated =
false;
14915 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14917 repeated = pm_parser_parameter_name_check(parser, &name);
14918 pm_parser_local_add_token(parser, &name, 1);
14920 name = not_provided(parser);
14924 param = (pm_node_t *) pm_keyword_rest_parameter_node_create(parser, &
operator, &name);
14926 pm_node_flag_set_repeated_parameter(param);
14931 pm_parameters_node_keyword_rest_set(params, param);
14933 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI);
14934 pm_parameters_node_posts_append(params, param);
14941 if (allows_trailing_comma && order >= PM_PARAMETERS_ORDER_NAMED) {
14944 pm_node_t *param = (pm_node_t *) pm_implicit_rest_node_create(parser, &parser->
previous);
14946 if (params->
rest == NULL) {
14947 pm_parameters_node_rest_set(params, param);
14949 pm_parser_err_node(parser, (pm_node_t *) param, PM_ERR_PARAMETER_SPLAT_MULTI);
14950 pm_parameters_node_posts_append(params, (pm_node_t *) param);
14953 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14964 if (!parsing)
break;
14966 bool accepted_newline =
false;
14967 if (uses_parentheses) {
14968 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
14971 if (accept1(parser, PM_TOKEN_COMMA)) {
14974 if (accepted_newline) {
14975 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14983 pm_do_loop_stack_pop(parser);
14987 pm_node_destroy(parser, (pm_node_t *) params);
15019token_column(
const pm_parser_t *parser,
size_t newline_index,
const pm_token_t *token,
bool break_on_non_space) {
15021 const uint8_t *end = token->start;
15025 newline_index == 0 &&
15026 parser->
start[0] == 0xef &&
15027 parser->
start[1] == 0xbb &&
15028 parser->
start[2] == 0xbf
15031 int64_t column = 0;
15032 for (; cursor < end; cursor++) {
15035 column = ((column / PM_TAB_WHITESPACE_SIZE) + 1) * PM_TAB_WHITESPACE_SIZE;
15042 if (break_on_non_space)
return -1;
15055parser_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) {
15060 size_t closing_newline_index = token_newline_index(parser);
15061 if (opening_newline_index == closing_newline_index)
return;
15066 int64_t opening_column = token_column(parser, opening_newline_index, opening_token, !if_after_else);
15067 if (!if_after_else && (opening_column == -1))
return;
15074 int64_t closing_column = token_column(parser, closing_newline_index, closing_token,
true);
15075 if ((closing_column == -1) || (opening_column == closing_column))
return;
15079 if (allow_indent && (closing_column > opening_column))
return;
15082 PM_PARSER_WARN_FORMAT(
15084 closing_token->
start,
15085 closing_token->
end,
15086 PM_WARN_INDENTATION_MISMATCH,
15087 (
int) (closing_token->
end - closing_token->
start),
15088 (
const char *) closing_token->
start,
15089 (
int) (opening_token->
end - opening_token->
start),
15090 (
const char *) opening_token->
start,
15091 ((int32_t) opening_newline_index) + parser->
start_line
15096 PM_RESCUES_BEGIN = 1,
15103} pm_rescues_type_t;
15110parse_rescues(
pm_parser_t *parser,
size_t opening_newline_index,
const pm_token_t *opening, pm_begin_node_t *parent_node, pm_rescues_type_t
type, uint16_t depth) {
15111 pm_rescue_node_t *current = NULL;
15113 while (match1(parser, PM_TOKEN_KEYWORD_RESCUE)) {
15114 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15115 parser_lex(parser);
15117 pm_rescue_node_t *rescue = pm_rescue_node_create(parser, &parser->
previous);
15119 switch (parser->
current.type) {
15120 case PM_TOKEN_EQUAL_GREATER: {
15124 parser_lex(parser);
15125 pm_rescue_node_operator_set(rescue, &parser->
previous);
15127 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15128 reference = parse_target(parser, reference,
false,
false);
15130 pm_rescue_node_reference_set(rescue, reference);
15133 case PM_TOKEN_NEWLINE:
15134 case PM_TOKEN_SEMICOLON:
15135 case PM_TOKEN_KEYWORD_THEN:
15140 if (token_begins_expression_p(parser->
current.type) || match1(parser, PM_TOKEN_USTAR)) {
15145 pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED,
false, PM_ERR_RESCUE_EXPRESSION, (uint16_t) (depth + 1));
15146 pm_rescue_node_exceptions_append(rescue, expression);
15150 if (match3(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_THEN))
break;
15154 if (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
15155 pm_rescue_node_operator_set(rescue, &parser->
previous);
15157 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15158 reference = parse_target(parser, reference,
false,
false);
15160 pm_rescue_node_reference_set(rescue, reference);
15163 }
while (accept1(parser, PM_TOKEN_COMMA));
15168 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
15169 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
15173 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_RESCUE_TERM);
15177 if (!match3(parser, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_END)) {
15178 pm_accepts_block_stack_push(parser,
true);
15192 pm_statements_node_t *statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15193 if (statements != NULL) pm_rescue_node_statements_set(rescue, statements);
15195 pm_accepts_block_stack_pop(parser);
15196 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15199 if (current == NULL) {
15200 pm_begin_node_rescue_clause_set(parent_node, rescue);
15202 pm_rescue_node_subsequent_set(current, rescue);
15211 if (current != NULL) {
15215 while (clause != NULL) {
15222 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
15223 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15224 opening_newline_index = token_newline_index(parser);
15226 else_keyword = parser->
current;
15227 opening = &else_keyword;
15229 parser_lex(parser);
15230 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15232 pm_statements_node_t *else_statements = NULL;
15233 if (!match2(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_ENSURE)) {
15234 pm_accepts_block_stack_push(parser,
true);
15248 else_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15249 pm_accepts_block_stack_pop(parser);
15251 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15254 pm_else_node_t *else_clause = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
current);
15255 pm_begin_node_else_clause_set(parent_node, else_clause);
15259 if (current == NULL) pm_parser_err_node(parser, (pm_node_t *) else_clause, PM_ERR_BEGIN_LONELY_ELSE);
15262 if (match1(parser, PM_TOKEN_KEYWORD_ENSURE)) {
15263 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15266 parser_lex(parser);
15267 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15269 pm_statements_node_t *ensure_statements = NULL;
15270 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
15271 pm_accepts_block_stack_push(parser,
true);
15285 ensure_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15286 pm_accepts_block_stack_pop(parser);
15288 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15291 pm_ensure_node_t *ensure_clause = pm_ensure_node_create(parser, &ensure_keyword, ensure_statements, &parser->
current);
15292 pm_begin_node_ensure_clause_set(parent_node, ensure_clause);
15295 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
15296 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15297 pm_begin_node_end_keyword_set(parent_node, &parser->
current);
15300 pm_begin_node_end_keyword_set(parent_node, &end_keyword);
15308static pm_begin_node_t *
15309parse_rescues_implicit_begin(
pm_parser_t *parser,
size_t opening_newline_index,
const pm_token_t *opening,
const uint8_t *start, pm_statements_node_t *statements, pm_rescues_type_t
type, uint16_t depth) {
15310 pm_token_t begin_keyword = not_provided(parser);
15311 pm_begin_node_t *node = pm_begin_node_create(parser, &begin_keyword, statements);
15313 parse_rescues(parser, opening_newline_index, opening, node,
type, (uint16_t) (depth + 1));
15322static pm_block_parameters_node_t *
15323parse_block_parameters(
15325 bool allows_trailing_comma,
15327 bool is_lambda_literal,
15328 bool accepts_blocks_in_defaults,
15331 pm_parameters_node_t *parameters = NULL;
15332 if (!match1(parser, PM_TOKEN_SEMICOLON)) {
15333 parameters = parse_parameters(
15335 is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
15337 allows_trailing_comma,
15339 accepts_blocks_in_defaults,
15341 (uint16_t) (depth + 1)
15345 pm_block_parameters_node_t *block_parameters = pm_block_parameters_node_create(parser, parameters, opening);
15346 if ((opening->
type != PM_TOKEN_NOT_PROVIDED)) {
15347 accept1(parser, PM_TOKEN_NEWLINE);
15349 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
15351 switch (parser->
current.type) {
15352 case PM_TOKEN_CONSTANT:
15353 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
15354 parser_lex(parser);
15356 case PM_TOKEN_INSTANCE_VARIABLE:
15357 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
15358 parser_lex(parser);
15360 case PM_TOKEN_GLOBAL_VARIABLE:
15361 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
15362 parser_lex(parser);
15364 case PM_TOKEN_CLASS_VARIABLE:
15365 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
15366 parser_lex(parser);
15369 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_BLOCK_PARAM_LOCAL_VARIABLE);
15373 bool repeated = pm_parser_parameter_name_check(parser, &parser->
previous);
15374 pm_parser_local_add_token(parser, &parser->
previous, 1);
15376 pm_block_local_variable_node_t *local = pm_block_local_variable_node_create(parser, &parser->
previous);
15377 if (repeated) pm_node_flag_set_repeated_parameter((pm_node_t *) local);
15379 pm_block_parameters_node_append_local(block_parameters, local);
15380 }
while (accept1(parser, PM_TOKEN_COMMA));
15384 return block_parameters;
15392outer_scope_using_numbered_parameters_p(
pm_parser_t *parser) {
15394 if (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND)
return true;
15405static const char *
const pm_numbered_parameter_names[] = {
15406 "_1",
"_2",
"_3",
"_4",
"_5",
"_6",
"_7",
"_8",
"_9"
15420 if (parameters != NULL) {
15422 if (implicit_parameters->
size > 0) {
15423 pm_node_t *node = implicit_parameters->
nodes[0];
15425 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
15426 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_ORDINARY);
15427 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
15428 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_ORDINARY);
15430 assert(
false &&
"unreachable");
15439 if (implicit_parameters->
size == 0) {
15446 uint8_t numbered_parameter = 0;
15447 bool it_parameter =
false;
15449 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
15450 pm_node_t *node = implicit_parameters->
nodes[index];
15452 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
15453 if (it_parameter) {
15454 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_IT);
15455 }
else if (outer_scope_using_numbered_parameters_p(parser)) {
15456 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_OUTER_BLOCK);
15458 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK);
15460 numbered_parameter = MAX(numbered_parameter, (uint8_t) (node->
location.
start[1] -
'0'));
15462 assert(
false &&
"unreachable");
15464 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
15465 if (numbered_parameter > 0) {
15466 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_NUMBERED);
15468 it_parameter =
true;
15473 if (numbered_parameter > 0) {
15477 scope->
parameters |= PM_SCOPE_PARAMETERS_NUMBERED_INNER;
15481 return (pm_node_t *) pm_numbered_parameters_node_create(parser, &location, numbered_parameter);
15484 if (it_parameter) {
15485 return (pm_node_t *) pm_it_parameters_node_create(parser, opening, closing);
15494static pm_block_node_t *
15495parse_block(
pm_parser_t *parser, uint16_t depth) {
15497 accept1(parser, PM_TOKEN_NEWLINE);
15499 pm_accepts_block_stack_push(parser,
true);
15500 pm_parser_scope_push(parser,
false);
15502 pm_block_parameters_node_t *block_parameters = NULL;
15504 if (accept1(parser, PM_TOKEN_PIPE)) {
15506 if (match1(parser, PM_TOKEN_PIPE)) {
15507 block_parameters = pm_block_parameters_node_create(parser, NULL, &block_parameters_opening);
15509 parser_lex(parser);
15511 block_parameters = parse_block_parameters(parser,
true, &block_parameters_opening,
false,
true, (uint16_t) (depth + 1));
15512 accept1(parser, PM_TOKEN_NEWLINE);
15514 expect1(parser, PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM);
15517 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
15520 accept1(parser, PM_TOKEN_NEWLINE);
15521 pm_node_t *statements = NULL;
15523 if (opening.
type == PM_TOKEN_BRACE_LEFT) {
15524 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
15528 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE);
15530 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
15531 if (!match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE)) {
15532 pm_accepts_block_stack_push(parser,
true);
15534 pm_accepts_block_stack_pop(parser);
15537 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
15538 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
15539 statements = (pm_node_t *) parse_rescues_implicit_begin(parser, 0, NULL, opening.
start, (pm_statements_node_t *) statements, PM_RESCUES_BLOCK, (uint16_t) (depth + 1));
15543 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END);
15547 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
15548 pm_node_t *parameters = parse_blocklike_parameters(parser, (pm_node_t *) block_parameters, &opening, &parser->
previous);
15550 pm_parser_scope_pop(parser);
15551 pm_accepts_block_stack_pop(parser);
15553 return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->
previous);
15562parse_arguments_list(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_block,
bool accepts_command_call, uint16_t depth) {
15563 bool found =
false;
15565 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
15569 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
15572 pm_accepts_block_stack_push(parser,
true);
15573 parse_arguments(parser, arguments, accepts_block, PM_TOKEN_PARENTHESIS_RIGHT, (uint16_t) (depth + 1));
15575 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
15581 pm_accepts_block_stack_pop(parser);
15584 }
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)) {
15586 pm_accepts_block_stack_push(parser,
false);
15591 parse_arguments(parser, arguments, accepts_block, PM_TOKEN_EOF, (uint16_t) (depth + 1));
15596 if (parser->
previous.
type == PM_TOKEN_COMMA && !match1(parser, PM_TOKEN_SEMICOLON)) {
15600 pm_accepts_block_stack_pop(parser);
15606 if (accepts_block) {
15607 pm_block_node_t *block = NULL;
15609 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
15611 block = parse_block(parser, (uint16_t) (depth + 1));
15612 pm_arguments_validate_block(parser, arguments, block);
15613 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
15615 block = parse_block(parser, (uint16_t) (depth + 1));
15618 if (block != NULL) {
15620 arguments->
block = (pm_node_t *) block;
15622 pm_parser_err_node(parser, (pm_node_t *) block, PM_ERR_ARGUMENT_BLOCK_MULTI);
15624 if (arguments->
block != NULL) {
15626 arguments->
arguments = pm_arguments_node_create(parser);
15628 pm_arguments_node_arguments_append(arguments->
arguments, arguments->
block);
15630 arguments->
block = (pm_node_t *) block;
15643parse_return(
pm_parser_t *parser, pm_node_t *node) {
15644 bool in_sclass =
false;
15646 switch (context_node->
context) {
15691 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15713 assert(
false &&
"unreachable");
15718 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15727parse_block_exit(
pm_parser_t *parser, pm_node_t *node) {
15729 switch (context_node->
context) {
15803 assert(
false &&
"unreachable");
15813static pm_node_list_t *
15814push_block_exits(
pm_parser_t *parser, pm_node_list_t *current_block_exits) {
15817 return previous_block_exits;
15826flush_block_exits(
pm_parser_t *parser, pm_node_list_t *previous_block_exits) {
15827 pm_node_t *block_exit;
15831 switch (PM_NODE_TYPE(block_exit)) {
15832 case PM_BREAK_NODE:
type =
"break";
break;
15833 case PM_NEXT_NODE:
type =
"next";
break;
15834 case PM_REDO_NODE:
type =
"redo";
break;
15835 default: assert(
false &&
"unreachable");
type =
"";
break;
15838 PM_PARSER_ERR_NODE_FORMAT(parser, block_exit, PM_ERR_INVALID_BLOCK_EXIT,
type);
15849pop_block_exits(
pm_parser_t *parser, pm_node_list_t *previous_block_exits) {
15850 if (match2(parser, PM_TOKEN_KEYWORD_WHILE_MODIFIER, PM_TOKEN_KEYWORD_UNTIL_MODIFIER)) {
15855 }
else if (previous_block_exits != NULL) {
15867 flush_block_exits(parser, previous_block_exits);
15871static inline pm_node_t *
15875 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, error_id, (uint16_t) (depth + 1));
15878 bool predicate_closed = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15880 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
15881 predicate_closed =
true;
15885 if (!predicate_closed) {
15886 pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
15889 context_pop(parser);
15893static inline pm_node_t *
15894parse_conditional(
pm_parser_t *parser,
pm_context_t context,
size_t opening_newline_index,
bool if_after_else, uint16_t depth) {
15895 pm_node_list_t current_block_exits = { 0 };
15896 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
15899 pm_token_t then_keyword = not_provided(parser);
15901 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context, &then_keyword, (uint16_t) (depth + 1));
15902 pm_statements_node_t *statements = NULL;
15904 if (!match3(parser, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
15905 pm_accepts_block_stack_push(parser,
true);
15906 statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15907 pm_accepts_block_stack_pop(parser);
15908 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15911 pm_token_t end_keyword = not_provided(parser);
15912 pm_node_t *parent = NULL;
15916 parent = (pm_node_t *) pm_if_node_create(parser, &keyword, predicate, &then_keyword, statements, NULL, &end_keyword);
15919 parent = (pm_node_t *) pm_unless_node_create(parser, &keyword, predicate, &then_keyword, statements);
15922 assert(
false &&
"unreachable");
15926 pm_node_t *current = parent;
15931 while (match1(parser, PM_TOKEN_KEYWORD_ELSIF)) {
15932 if (parser_end_of_line_p(parser)) {
15933 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
15936 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15938 parser_lex(parser);
15940 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER,
PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1));
15941 pm_accepts_block_stack_push(parser,
true);
15943 pm_statements_node_t *statements = parse_statements(parser,
PM_CONTEXT_ELSIF, (uint16_t) (depth + 1));
15944 pm_accepts_block_stack_pop(parser);
15945 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15947 pm_node_t *elsif = (pm_node_t *) pm_if_node_create(parser, &elsif_keyword, predicate, &then_keyword, statements, NULL, &end_keyword);
15948 ((pm_if_node_t *) current)->subsequent = elsif;
15953 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
15954 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15955 opening_newline_index = token_newline_index(parser);
15957 parser_lex(parser);
15960 pm_accepts_block_stack_push(parser,
true);
15961 pm_statements_node_t *else_statements = parse_statements(parser,
PM_CONTEXT_ELSE, (uint16_t) (depth + 1));
15962 pm_accepts_block_stack_pop(parser);
15964 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15965 parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword,
false,
false);
15966 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE);
15968 pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
previous);
15972 ((pm_if_node_t *) current)->subsequent = (pm_node_t *) else_node;
15975 ((pm_unless_node_t *) parent)->else_clause = else_node;
15978 assert(
false &&
"unreachable");
15982 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else,
false);
15983 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM);
15989 pm_node_t *current = parent;
15990 bool recursing =
true;
15992 while (recursing) {
15993 switch (PM_NODE_TYPE(current)) {
15995 pm_if_node_end_keyword_loc_set((pm_if_node_t *) current, &parser->
previous);
15996 current = ((pm_if_node_t *) current)->subsequent;
15997 recursing = current != NULL;
16000 pm_else_node_end_keyword_loc_set((pm_else_node_t *) current, &parser->
previous);
16012 pm_unless_node_end_keyword_loc_set((pm_unless_node_t *) parent, &parser->
previous);
16015 assert(
false &&
"unreachable");
16019 pop_block_exits(parser, previous_block_exits);
16020 pm_node_list_free(¤t_block_exits);
16029#define PM_CASE_KEYWORD PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
16030 case PM_TOKEN_KEYWORD_ALIAS: case PM_TOKEN_KEYWORD_AND: case PM_TOKEN_KEYWORD_BEGIN: case PM_TOKEN_KEYWORD_BEGIN_UPCASE: \
16031 case PM_TOKEN_KEYWORD_BREAK: case PM_TOKEN_KEYWORD_CASE: case PM_TOKEN_KEYWORD_CLASS: case PM_TOKEN_KEYWORD_DEF: \
16032 case PM_TOKEN_KEYWORD_DEFINED: case PM_TOKEN_KEYWORD_DO: case PM_TOKEN_KEYWORD_DO_LOOP: case PM_TOKEN_KEYWORD_ELSE: \
16033 case PM_TOKEN_KEYWORD_ELSIF: case PM_TOKEN_KEYWORD_END: case PM_TOKEN_KEYWORD_END_UPCASE: case PM_TOKEN_KEYWORD_ENSURE: \
16034 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD_FOR: case PM_TOKEN_KEYWORD_IF: case PM_TOKEN_KEYWORD_IN: \
16035 case PM_TOKEN_KEYWORD_MODULE: case PM_TOKEN_KEYWORD_NEXT: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_NOT: \
16036 case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_KEYWORD_REDO: case PM_TOKEN_KEYWORD_RESCUE: case PM_TOKEN_KEYWORD_RETRY: \
16037 case PM_TOKEN_KEYWORD_RETURN: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_SUPER: case PM_TOKEN_KEYWORD_THEN: \
16038 case PM_TOKEN_KEYWORD_TRUE: case PM_TOKEN_KEYWORD_UNDEF: case PM_TOKEN_KEYWORD_UNLESS: case PM_TOKEN_KEYWORD_UNTIL: \
16039 case PM_TOKEN_KEYWORD_WHEN: case PM_TOKEN_KEYWORD_WHILE: case PM_TOKEN_KEYWORD_YIELD
16045#define PM_CASE_OPERATOR PM_TOKEN_AMPERSAND: case PM_TOKEN_BACKTICK: case PM_TOKEN_BANG_EQUAL: \
16046 case PM_TOKEN_BANG_TILDE: case PM_TOKEN_BANG: case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL: \
16047 case PM_TOKEN_BRACKET_LEFT_RIGHT: case PM_TOKEN_CARET: case PM_TOKEN_EQUAL_EQUAL_EQUAL: case PM_TOKEN_EQUAL_EQUAL: \
16048 case PM_TOKEN_EQUAL_TILDE: case PM_TOKEN_GREATER_EQUAL: case PM_TOKEN_GREATER_GREATER: case PM_TOKEN_GREATER: \
16049 case PM_TOKEN_LESS_EQUAL_GREATER: case PM_TOKEN_LESS_EQUAL: case PM_TOKEN_LESS_LESS: case PM_TOKEN_LESS: \
16050 case PM_TOKEN_MINUS: case PM_TOKEN_PERCENT: case PM_TOKEN_PIPE: case PM_TOKEN_PLUS: case PM_TOKEN_SLASH: \
16051 case PM_TOKEN_STAR_STAR: case PM_TOKEN_STAR: case PM_TOKEN_TILDE: case PM_TOKEN_UAMPERSAND: case PM_TOKEN_UMINUS: \
16052 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_UPLUS: case PM_TOKEN_USTAR: case PM_TOKEN_USTAR_STAR
16059#define PM_CASE_PRIMITIVE PM_TOKEN_INTEGER: case PM_TOKEN_INTEGER_IMAGINARY: case PM_TOKEN_INTEGER_RATIONAL: \
16060 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: case PM_TOKEN_FLOAT: case PM_TOKEN_FLOAT_IMAGINARY: \
16061 case PM_TOKEN_FLOAT_RATIONAL: case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY: case PM_TOKEN_SYMBOL_BEGIN: \
16062 case PM_TOKEN_REGEXP_BEGIN: case PM_TOKEN_BACKTICK: case PM_TOKEN_PERCENT_LOWER_X: case PM_TOKEN_PERCENT_LOWER_I: \
16063 case PM_TOKEN_PERCENT_LOWER_W: case PM_TOKEN_PERCENT_UPPER_I: case PM_TOKEN_PERCENT_UPPER_W: \
16064 case PM_TOKEN_STRING_BEGIN: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_TRUE: \
16065 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
16066 case PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_MINUS_GREATER: case PM_TOKEN_HEREDOC_START: \
16067 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_CHARACTER_LITERAL
16073#define PM_CASE_PARAMETER PM_TOKEN_UAMPERSAND: case PM_TOKEN_AMPERSAND: case PM_TOKEN_UDOT_DOT_DOT: \
16074 case PM_TOKEN_IDENTIFIER: case PM_TOKEN_LABEL: case PM_TOKEN_USTAR: case PM_TOKEN_STAR: case PM_TOKEN_STAR_STAR: \
16075 case PM_TOKEN_USTAR_STAR: case PM_TOKEN_CONSTANT: case PM_TOKEN_INSTANCE_VARIABLE: case PM_TOKEN_GLOBAL_VARIABLE: \
16076 case PM_TOKEN_CLASS_VARIABLE
16082#define PM_CASE_WRITABLE PM_CLASS_VARIABLE_READ_NODE: case PM_CONSTANT_PATH_NODE: \
16083 case PM_CONSTANT_READ_NODE: case PM_GLOBAL_VARIABLE_READ_NODE: case PM_LOCAL_VARIABLE_READ_NODE: \
16084 case PM_INSTANCE_VARIABLE_READ_NODE: case PM_MULTI_TARGET_NODE: case PM_BACK_REFERENCE_READ_NODE: \
16085 case PM_NUMBERED_REFERENCE_READ_NODE: case PM_IT_LOCAL_VARIABLE_READ_NODE
16089PM_STATIC_ASSERT(__LINE__, ((
int) PM_STRING_FLAGS_FORCED_UTF8_ENCODING) == ((
int) PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING),
"Expected the flags to match.");
16095static inline pm_node_flags_t
16096parse_unescaped_encoding(
const pm_parser_t *parser) {
16101 return PM_STRING_FLAGS_FORCED_UTF8_ENCODING;
16107 return PM_STRING_FLAGS_FORCED_BINARY_ENCODING;
16118parse_string_part(
pm_parser_t *parser, uint16_t depth) {
16119 switch (parser->
current.type) {
16126 case PM_TOKEN_STRING_CONTENT: {
16130 pm_node_t *node = (pm_node_t *) pm_string_node_create_current_string(parser, &opening, &parser->
current, &closing);
16131 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16133 parser_lex(parser);
16142 case PM_TOKEN_EMBEXPR_BEGIN: {
16151 lex_state_set(parser, PM_LEX_STATE_BEG);
16152 parser_lex(parser);
16155 pm_statements_node_t *statements = NULL;
16157 if (!match1(parser, PM_TOKEN_EMBEXPR_END)) {
16158 pm_accepts_block_stack_push(parser,
true);
16160 pm_accepts_block_stack_pop(parser);
16164 lex_state_set(parser, state);
16166 expect1(parser, PM_TOKEN_EMBEXPR_END, PM_ERR_EMBEXPR_END);
16172 if (statements != NULL && statements->
body.
size == 1) {
16173 pm_node_flag_unset(statements->
body.
nodes[0], PM_NODE_FLAG_NEWLINE);
16176 return (pm_node_t *) pm_embedded_statements_node_create(parser, &opening, statements, &closing);
16185 case PM_TOKEN_EMBVAR: {
16190 lex_state_set(parser, PM_LEX_STATE_BEG);
16191 parser_lex(parser);
16194 pm_node_t *variable;
16196 switch (parser->
current.type) {
16199 case PM_TOKEN_BACK_REFERENCE:
16200 parser_lex(parser);
16201 variable = (pm_node_t *) pm_back_reference_read_node_create(parser, &parser->
previous);
16205 case PM_TOKEN_NUMBERED_REFERENCE:
16206 parser_lex(parser);
16207 variable = (pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->
previous);
16211 case PM_TOKEN_GLOBAL_VARIABLE:
16212 parser_lex(parser);
16213 variable = (pm_node_t *) pm_global_variable_read_node_create(parser, &parser->
previous);
16217 case PM_TOKEN_INSTANCE_VARIABLE:
16218 parser_lex(parser);
16219 variable = (pm_node_t *) pm_instance_variable_read_node_create(parser, &parser->
previous);
16223 case PM_TOKEN_CLASS_VARIABLE:
16224 parser_lex(parser);
16225 variable = (pm_node_t *) pm_class_variable_read_node_create(parser, &parser->
previous);
16231 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EMBVAR_INVALID);
16232 variable = (pm_node_t *) pm_missing_node_create(parser, parser->
current.start, parser->
current.end);
16236 return (pm_node_t *) pm_embedded_variable_node_create(parser, &
operator, variable);
16239 parser_lex(parser);
16240 pm_parser_err_previous(parser, PM_ERR_CANNOT_PARSE_STRING_PART);
16250static const uint8_t *
16251parse_operator_symbol_name(
const pm_token_t *name) {
16252 switch (name->
type) {
16253 case PM_TOKEN_TILDE:
16254 case PM_TOKEN_BANG:
16255 if (name->
end[-1] ==
'@')
return name->
end - 1;
16265 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, opening, &parser->
current, &closing);
16267 const uint8_t *end = parse_operator_symbol_name(&parser->
current);
16269 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16270 parser_lex(parser);
16273 pm_node_flag_set((pm_node_t *) symbol, PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING);
16275 return (pm_node_t *) symbol;
16287 if (lex_mode->
mode != PM_LEX_STRING) {
16288 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16290 switch (parser->
current.type) {
16291 case PM_CASE_OPERATOR:
16292 return parse_operator_symbol(parser, &opening, next_state == PM_LEX_STATE_NONE ? PM_LEX_STATE_ENDFN : next_state);
16293 case PM_TOKEN_IDENTIFIER:
16294 case PM_TOKEN_CONSTANT:
16295 case PM_TOKEN_INSTANCE_VARIABLE:
16296 case PM_TOKEN_METHOD_NAME:
16297 case PM_TOKEN_CLASS_VARIABLE:
16298 case PM_TOKEN_GLOBAL_VARIABLE:
16299 case PM_TOKEN_NUMBERED_REFERENCE:
16300 case PM_TOKEN_BACK_REFERENCE:
16301 case PM_CASE_KEYWORD:
16302 parser_lex(parser);
16305 expect2(parser, PM_TOKEN_IDENTIFIER, PM_TOKEN_METHOD_NAME, PM_ERR_SYMBOL_INVALID);
16310 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &parser->
previous, &closing);
16313 pm_node_flag_set((pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16315 return (pm_node_t *) symbol;
16320 if (match1(parser, PM_TOKEN_STRING_END)) {
16321 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16322 parser_lex(parser);
16326 return (pm_node_t *) pm_symbol_node_create(parser, &opening, &content, &closing);
16330 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
16334 if (part && PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16335 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16336 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16338 return (pm_node_t *) pm_string_node_to_symbol_node(parser, (pm_string_node_t *) part, &opening, &parser->
previous);
16341 pm_interpolated_symbol_node_t *symbol = pm_interpolated_symbol_node_create(parser, &opening, NULL, &opening);
16342 if (part) pm_interpolated_symbol_node_append(symbol, part);
16344 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16345 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16346 pm_interpolated_symbol_node_append(symbol, part);
16350 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16351 if (match1(parser, PM_TOKEN_EOF)) {
16352 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16354 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16357 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
16358 return (pm_node_t *) symbol;
16364 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16367 parser_lex(parser);
16378 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16379 pm_interpolated_symbol_node_t *symbol = pm_interpolated_symbol_node_create(parser, &opening, NULL, &opening);
16382 pm_node_t *part = (pm_node_t *) pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &unescaped);
16383 pm_interpolated_symbol_node_append(symbol, part);
16385 part = (pm_node_t *) pm_string_node_create_unescaped(parser, &bounds, &parser->
current, &bounds, &parser->
current_string);
16386 pm_interpolated_symbol_node_append(symbol, part);
16388 if (next_state != PM_LEX_STATE_NONE) {
16389 lex_state_set(parser, next_state);
16392 parser_lex(parser);
16393 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
16395 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
16396 return (pm_node_t *) symbol;
16400 pm_string_shared_init(&unescaped, content.
start, content.
end);
16403 if (next_state != PM_LEX_STATE_NONE) {
16404 lex_state_set(parser, next_state);
16407 if (match1(parser, PM_TOKEN_EOF)) {
16408 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_DYNAMIC);
16410 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
16413 return (pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
false));
16420static inline pm_node_t *
16421parse_undef_argument(
pm_parser_t *parser, uint16_t depth) {
16422 switch (parser->
current.type) {
16423 case PM_CASE_OPERATOR: {
16424 const pm_token_t opening = not_provided(parser);
16425 return parse_operator_symbol(parser, &opening, PM_LEX_STATE_NONE);
16427 case PM_CASE_KEYWORD:
16428 case PM_TOKEN_CONSTANT:
16429 case PM_TOKEN_IDENTIFIER:
16430 case PM_TOKEN_METHOD_NAME: {
16431 parser_lex(parser);
16435 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &parser->
previous, &closing);
16438 pm_node_flag_set((pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16440 return (pm_node_t *) symbol;
16442 case PM_TOKEN_SYMBOL_BEGIN: {
16444 parser_lex(parser);
16446 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16449 pm_parser_err_current(parser, PM_ERR_UNDEF_ARGUMENT);
16450 return (pm_node_t *) pm_missing_node_create(parser, parser->
current.start, parser->
current.end);
16460static inline pm_node_t *
16461parse_alias_argument(
pm_parser_t *parser,
bool first, uint16_t depth) {
16462 switch (parser->
current.type) {
16463 case PM_CASE_OPERATOR: {
16464 const pm_token_t opening = not_provided(parser);
16465 return parse_operator_symbol(parser, &opening, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
16467 case PM_CASE_KEYWORD:
16468 case PM_TOKEN_CONSTANT:
16469 case PM_TOKEN_IDENTIFIER:
16470 case PM_TOKEN_METHOD_NAME: {
16471 if (first) lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
16472 parser_lex(parser);
16476 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &parser->
previous, &closing);
16479 pm_node_flag_set((pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16481 return (pm_node_t *) symbol;
16483 case PM_TOKEN_SYMBOL_BEGIN: {
16485 parser_lex(parser);
16487 return parse_symbol(parser, &lex_mode, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16489 case PM_TOKEN_BACK_REFERENCE:
16490 parser_lex(parser);
16491 return (pm_node_t *) pm_back_reference_read_node_create(parser, &parser->
previous);
16492 case PM_TOKEN_NUMBERED_REFERENCE:
16493 parser_lex(parser);
16494 return (pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->
previous);
16495 case PM_TOKEN_GLOBAL_VARIABLE:
16496 parser_lex(parser);
16497 return (pm_node_t *) pm_global_variable_read_node_create(parser, &parser->
previous);
16499 pm_parser_err_current(parser, PM_ERR_ALIAS_ARGUMENT);
16500 return (pm_node_t *) pm_missing_node_create(parser, parser->
current.start, parser->
current.end);
16514 if (!is_numbered_param && ((depth = pm_parser_local_depth_constant_id(parser, name_id)) != -1)) {
16515 return (pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, (uint32_t) depth,
false);
16519 if (!current_scope->
closed && !(current_scope->
parameters & PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED)) {
16520 if (is_numbered_param) {
16525 uint8_t maximum = (uint8_t) (parser->
previous.
start[1] -
'0');
16526 for (uint8_t number = 1; number <= maximum; number++) {
16527 pm_parser_local_add_constant(parser, pm_numbered_parameter_names[number - 1], 2);
16530 if (!match1(parser, PM_TOKEN_EQUAL)) {
16534 pm_node_t *node = (pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, 0,
false);
16539 pm_node_t *node = (pm_node_t *) pm_it_local_variable_read_node_create(parser, &parser->
previous);
16554 pm_node_flags_t flags = 0;
16556 if (!match1(parser, PM_TOKEN_PARENTHESIS_LEFT) && (parser->
previous.
end[-1] !=
'!') && (parser->
previous.
end[-1] !=
'?')) {
16557 pm_node_t *node = parse_variable(parser);
16558 if (node != NULL)
return node;
16559 flags |= PM_CALL_NODE_FLAGS_VARIABLE_CALL;
16562 pm_call_node_t *node = pm_call_node_variable_call_create(parser, &parser->
previous);
16563 pm_node_flag_set((pm_node_t *)node, flags);
16565 return (pm_node_t *) node;
16574parse_method_definition_name(
pm_parser_t *parser) {
16575 switch (parser->
current.type) {
16576 case PM_CASE_KEYWORD:
16577 case PM_TOKEN_CONSTANT:
16578 case PM_TOKEN_METHOD_NAME:
16579 parser_lex(parser);
16581 case PM_TOKEN_IDENTIFIER:
16582 pm_refute_numbered_parameter(parser, parser->
current.start, parser->
current.end);
16583 parser_lex(parser);
16585 case PM_CASE_OPERATOR:
16586 lex_state_set(parser, PM_LEX_STATE_ENDFN);
16587 parser_lex(parser);
16596parse_heredoc_dedent_string(
pm_string_t *
string,
size_t common_whitespace) {
16599 pm_string_ensure_owned(
string);
16604 size_t dest_length = pm_string_length(
string);
16605 const uint8_t *source_cursor = (uint8_t *) string->
source;
16606 const uint8_t *source_end = source_cursor + dest_length;
16611 size_t trimmed_whitespace = 0;
16617 while ((source_cursor < source_end) && pm_char_is_inline_whitespace(*source_cursor) && trimmed_whitespace < common_whitespace) {
16618 if (*source_cursor ==
'\t') {
16619 trimmed_whitespace = (trimmed_whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
16620 if (trimmed_whitespace > common_whitespace)
break;
16622 trimmed_whitespace++;
16629 memmove((uint8_t *) string->source, source_cursor, (
size_t) (source_end - source_cursor));
16630 string->length = dest_length;
16637parse_heredoc_dedent(
pm_parser_t *parser, pm_node_list_t *nodes,
size_t common_whitespace) {
16640 bool dedent_next =
true;
16645 size_t write_index = 0;
16652 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE)) {
16653 nodes->
nodes[write_index++] = node;
16654 dedent_next =
false;
16658 pm_string_node_t *string_node = ((pm_string_node_t *) node);
16660 parse_heredoc_dedent_string(&string_node->
unescaped, common_whitespace);
16664 pm_node_destroy(parser, node);
16666 nodes->
nodes[write_index++] = node;
16670 dedent_next =
true;
16673 nodes->
size = write_index;
16680parse_strings_empty_content(
const uint8_t *location) {
16681 return (
pm_token_t) { .type = PM_TOKEN_STRING_CONTENT, .start = location, .end = location };
16687static inline pm_node_t *
16688parse_strings(
pm_parser_t *parser, pm_node_t *current,
bool accepts_label, uint16_t depth) {
16689 assert(parser->
current.type == PM_TOKEN_STRING_BEGIN);
16690 bool concating =
false;
16692 while (match1(parser, PM_TOKEN_STRING_BEGIN)) {
16693 pm_node_t *node = NULL;
16698 assert(lex_mode->
mode == PM_LEX_STRING);
16700 bool label_allowed = lex_mode->
as.string.
label_allowed && accepts_label;
16703 parser_lex(parser);
16705 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16706 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16711 pm_string_node_t *
string = pm_string_node_create(parser, &opening, &content, &parser->
previous);
16714 node = (pm_node_t *)
string;
16715 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16720 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &content, &parser->
previous);
16723 node = (pm_node_t *) symbol;
16725 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16726 }
else if (!lex_interpolation) {
16732 if (match1(parser, PM_TOKEN_EOF)) {
16734 content = not_provided(parser);
16737 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_EXPECT_STRING_CONTENT);
16752 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16753 pm_node_list_t parts = { 0 };
16755 pm_token_t delimiters = not_provided(parser);
16756 pm_node_t *part = (pm_node_t *) pm_string_node_create_unescaped(parser, &delimiters, &content, &delimiters, &unescaped);
16757 pm_node_list_append(&parts, part);
16760 part = (pm_node_t *) pm_string_node_create_current_string(parser, &delimiters, &parser->
current, &delimiters);
16761 pm_node_list_append(&parts, part);
16762 parser_lex(parser);
16763 }
while (match1(parser, PM_TOKEN_STRING_CONTENT));
16765 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16766 node = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16768 pm_node_list_free(&parts);
16769 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16770 node = (pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true));
16771 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16772 }
else if (match1(parser, PM_TOKEN_EOF)) {
16773 pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
16774 node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
16775 }
else if (accept1(parser, PM_TOKEN_STRING_END)) {
16776 node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped);
16781 node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped);
16783 }
else if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16790 parser_lex(parser);
16792 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16793 node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
16794 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16800 if (!accept1(parser, PM_TOKEN_STRING_END)) {
16802 if (location > parser->
start && location[-1] ==
'\n') location--;
16803 pm_parser_err(parser, location, location, PM_ERR_STRING_LITERAL_EOF);
16808 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16809 node = (pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true));
16810 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16814 pm_node_list_t parts = { 0 };
16815 pm_token_t string_opening = not_provided(parser);
16816 pm_token_t string_closing = not_provided(parser);
16818 pm_node_t *part = (pm_node_t *) pm_string_node_create_unescaped(parser, &string_opening, &parser->
previous, &string_closing, &unescaped);
16819 pm_node_flag_set(part, parse_unescaped_encoding(parser));
16820 pm_node_list_append(&parts, part);
16822 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16823 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16824 pm_node_list_append(&parts, part);
16828 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16829 node = (pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous);
16830 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16831 }
else if (match1(parser, PM_TOKEN_EOF)) {
16832 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16833 node = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current);
16835 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16836 node = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16839 pm_node_list_free(&parts);
16845 pm_node_list_t parts = { 0 };
16848 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16849 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16850 pm_node_list_append(&parts, part);
16854 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16855 node = (pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous);
16856 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16857 }
else if (match1(parser, PM_TOKEN_EOF)) {
16858 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16859 node = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current);
16861 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16862 node = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16865 pm_node_list_free(&parts);
16868 if (current == NULL) {
16872 if (PM_NODE_TYPE_P(node, PM_SYMBOL_NODE) || PM_NODE_TYPE_P(node, PM_INTERPOLATED_SYMBOL_NODE)) {
16883 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE) && !PM_NODE_TYPE_P(node, PM_INTERPOLATED_STRING_NODE)) {
16884 pm_parser_err_node(parser, node, PM_ERR_STRING_CONCATENATION);
16890 if (!PM_NODE_TYPE_P(current, PM_STRING_NODE) && !PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
16891 pm_parser_err_node(parser, current, PM_ERR_STRING_CONCATENATION);
16897 pm_interpolated_string_node_t *container = pm_interpolated_string_node_create(parser, &bounds, NULL, &bounds);
16898 pm_interpolated_string_node_append(container, current);
16899 current = (pm_node_t *) container;
16902 pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current, node);
16909#define PM_PARSE_PATTERN_SINGLE 0
16910#define PM_PARSE_PATTERN_TOP 1
16911#define PM_PARSE_PATTERN_MULTI 2
16924 if (*location->
start ==
'_')
return;
16926 if (pm_constant_id_list_includes(captures, capture)) {
16927 pm_parser_err(parser, location->
start, location->
end, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
16929 pm_constant_id_list_append(captures, capture);
16940 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
16942 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
16943 node = (pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
16949 if (!match2(parser, PM_TOKEN_BRACKET_LEFT, PM_TOKEN_PARENTHESIS_LEFT)) {
16955 pm_node_t *inner = NULL;
16957 if (accept1(parser, PM_TOKEN_BRACKET_LEFT)) {
16959 accept1(parser, PM_TOKEN_NEWLINE);
16961 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
16962 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16963 accept1(parser, PM_TOKEN_NEWLINE);
16964 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET);
16969 parser_lex(parser);
16971 accept1(parser, PM_TOKEN_NEWLINE);
16973 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
16974 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
16975 accept1(parser, PM_TOKEN_NEWLINE);
16976 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
16985 return (pm_node_t *) pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
16992 switch (PM_NODE_TYPE(inner)) {
16993 case PM_ARRAY_PATTERN_NODE: {
16994 pm_array_pattern_node_t *pattern_node = (pm_array_pattern_node_t *) inner;
17001 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17002 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17004 return (pm_node_t *) pattern_node;
17009 case PM_FIND_PATTERN_NODE: {
17010 pm_find_pattern_node_t *pattern_node = (pm_find_pattern_node_t *) inner;
17017 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17018 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17020 return (pm_node_t *) pattern_node;
17025 case PM_HASH_PATTERN_NODE: {
17026 pm_hash_pattern_node_t *pattern_node = (pm_hash_pattern_node_t *) inner;
17033 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17034 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17036 return (pm_node_t *) pattern_node;
17048 pm_array_pattern_node_t *pattern_node = pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
17049 pm_array_pattern_node_requireds_append(pattern_node, inner);
17050 return (pm_node_t *) pattern_node;
17056static pm_splat_node_t *
17060 pm_node_t *name = NULL;
17065 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
17067 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &identifier);
17070 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17071 pm_parser_local_add(parser, constant_id, identifier.
start, identifier.
end, 0);
17074 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&identifier));
17075 name = (pm_node_t *) pm_local_variable_target_node_create(
17077 &PM_LOCATION_TOKEN_VALUE(&identifier),
17079 (uint32_t) (depth == -1 ? 0 : depth)
17084 return pm_splat_node_create(parser, &
operator, name);
17092 assert(parser->
current.type == PM_TOKEN_USTAR_STAR);
17093 parser_lex(parser);
17096 pm_node_t *value = NULL;
17098 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
17099 return (pm_node_t *) pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous);
17102 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
17106 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17110 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17111 value = (pm_node_t *) pm_local_variable_target_node_create(
17113 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17115 (uint32_t) (depth == -1 ? 0 : depth)
17119 return (pm_node_t *) pm_assoc_splat_node_create(parser, value, &
operator);
17127pm_slice_is_valid_local(
const pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
17128 ptrdiff_t length = end - start;
17129 if (length == 0)
return false;
17132 size_t width = char_is_identifier_start(parser, start, end - start);
17133 if (width == 0)
return false;
17139 if (pm_encoding_utf_8_isupper_char(start, length))
return false;
17144 const uint8_t *cursor = start + width;
17145 while ((width = char_is_identifier(parser, cursor, end - cursor))) cursor += width;
17146 return cursor == end;
17155 const pm_location_t *value_loc = &((pm_symbol_node_t *) key)->value_loc;
17160 if (pm_slice_is_valid_local(parser, value_loc->
start, value_loc->
end)) {
17161 depth = pm_parser_local_depth_constant_id(parser, constant_id);
17163 pm_parser_err(parser, key->base.location.start, key->base.location.end, PM_ERR_PATTERN_HASH_KEY_LOCALS);
17165 if ((value_loc->
end > value_loc->
start) && ((value_loc->
end[-1] ==
'!') || (value_loc->
end[-1] ==
'?'))) {
17166 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);
17171 pm_parser_local_add(parser, constant_id, value_loc->
start, value_loc->
end, 0);
17174 parse_pattern_capture(parser, captures, constant_id, value_loc);
17175 pm_local_variable_target_node_t *target = pm_local_variable_target_node_create(
17179 (uint32_t) (depth == -1 ? 0 : depth)
17182 return (pm_node_t *) pm_implicit_node_create(parser, (pm_node_t *) target);
17192 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
17199static pm_hash_pattern_node_t *
17201 pm_node_list_t assocs = { 0 };
17203 pm_node_t *rest = NULL;
17205 switch (PM_NODE_TYPE(first_node)) {
17206 case PM_ASSOC_SPLAT_NODE:
17207 case PM_NO_KEYWORDS_PARAMETER_NODE:
17210 case PM_SYMBOL_NODE: {
17211 if (pm_symbol_node_label_p(first_node)) {
17212 parse_pattern_hash_key(parser, &keys, first_node);
17215 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)) {
17218 value = parse_pattern_hash_implicit_value(parser, captures, (pm_symbol_node_t *) first_node);
17222 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17226 pm_node_t *assoc = (pm_node_t *) pm_assoc_node_create(parser, first_node, &
operator, value);
17228 pm_node_list_append(&assocs, assoc);
17237 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;
17238 pm_parser_err_node(parser, first_node, diag_id);
17241 pm_node_t *value = (pm_node_t *) pm_missing_node_create(parser, first_node->
location.
start, first_node->
location.
end);
17242 pm_node_t *assoc = (pm_node_t *) pm_assoc_node_create(parser, first_node, &
operator, value);
17244 pm_node_list_append(&assocs, assoc);
17250 while (accept1(parser, PM_TOKEN_COMMA)) {
17252 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)) {
17254 if (rest != NULL) {
17255 pm_parser_err_token(parser, &parser->
current, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17261 if (match1(parser, PM_TOKEN_USTAR_STAR)) {
17262 pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures);
17264 if (rest == NULL) {
17267 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17268 pm_node_list_append(&assocs, assoc);
17273 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
17274 key = parse_strings(parser, NULL,
true, (uint16_t) (depth + 1));
17276 if (PM_NODE_TYPE_P(key, PM_INTERPOLATED_SYMBOL_NODE)) {
17277 pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
17278 }
else if (!pm_symbol_node_label_p(key)) {
17279 pm_parser_err_node(parser, key, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17282 expect1(parser, PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17283 key = (pm_node_t *) pm_symbol_node_label_create(parser, &parser->
previous);
17286 parse_pattern_hash_key(parser, &keys, key);
17287 pm_node_t *value = NULL;
17289 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)) {
17290 value = parse_pattern_hash_implicit_value(parser, captures, (pm_symbol_node_t *) key);
17292 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17296 pm_node_t *assoc = (pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
17298 if (rest != NULL) {
17299 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17302 pm_node_list_append(&assocs, assoc);
17306 pm_hash_pattern_node_t *node = pm_hash_pattern_node_node_list_create(parser, &assocs, rest);
17309 pm_static_literals_free(&keys);
17318 switch (parser->
current.type) {
17319 case PM_TOKEN_IDENTIFIER:
17320 case PM_TOKEN_METHOD_NAME: {
17321 parser_lex(parser);
17325 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17329 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17330 return (pm_node_t *) pm_local_variable_target_node_create(
17332 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17334 (uint32_t) (depth == -1 ? 0 : depth)
17337 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
17339 parser_lex(parser);
17341 if (accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17344 return (pm_node_t *) pm_array_pattern_node_empty_create(parser, &opening, &parser->
previous);
17349 pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
17351 accept1(parser, PM_TOKEN_NEWLINE);
17352 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET);
17355 switch (PM_NODE_TYPE(inner)) {
17356 case PM_ARRAY_PATTERN_NODE: {
17357 pm_array_pattern_node_t *pattern_node = (pm_array_pattern_node_t *) inner;
17362 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17363 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17365 return (pm_node_t *) pattern_node;
17370 case PM_FIND_PATTERN_NODE: {
17371 pm_find_pattern_node_t *pattern_node = (pm_find_pattern_node_t *) inner;
17376 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17377 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17379 return (pm_node_t *) pattern_node;
17388 pm_array_pattern_node_t *node = pm_array_pattern_node_empty_create(parser, &opening, &closing);
17389 pm_array_pattern_node_requireds_append(node, inner);
17390 return (pm_node_t *) node;
17392 case PM_TOKEN_BRACE_LEFT: {
17396 pm_hash_pattern_node_t *node;
17398 parser_lex(parser);
17400 if (accept1(parser, PM_TOKEN_BRACE_RIGHT)) {
17403 node = pm_hash_pattern_node_empty_create(parser, &opening, &parser->
previous);
17405 pm_node_t *first_node;
17407 switch (parser->
current.type) {
17408 case PM_TOKEN_LABEL:
17409 parser_lex(parser);
17410 first_node = (pm_node_t *) pm_symbol_node_label_create(parser, &parser->
previous);
17412 case PM_TOKEN_USTAR_STAR:
17413 first_node = parse_pattern_keyword_rest(parser, captures);
17415 case PM_TOKEN_STRING_BEGIN:
17416 first_node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, PM_ERR_PATTERN_HASH_KEY_LABEL, (uint16_t) (depth + 1));
17420 parser_lex(parser);
17427 node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
17429 accept1(parser, PM_TOKEN_NEWLINE);
17430 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE);
17436 node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17437 node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17441 return (pm_node_t *) node;
17443 case PM_TOKEN_UDOT_DOT:
17444 case PM_TOKEN_UDOT_DOT_DOT: {
17446 parser_lex(parser);
17450 switch (parser->
current.type) {
17451 case PM_CASE_PRIMITIVE: {
17452 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
17453 return (pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
17456 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
17457 pm_node_t *right = (pm_node_t *) pm_missing_node_create(parser,
operator.start,
operator.end);
17458 return (pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
17462 case PM_CASE_PRIMITIVE: {
17463 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, diag_id, (uint16_t) (depth + 1));
17466 if (pm_symbol_node_label_p(node))
return node;
17469 if (PM_NODE_TYPE(node) == PM_CALL_NODE) {
17470 pm_parser_err_node(parser, node, diag_id);
17472 pm_node_destroy(parser, node);
17473 return (pm_node_t *) missing_node;
17477 if (accept2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
17483 switch (parser->
current.type) {
17484 case PM_CASE_PRIMITIVE: {
17485 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
17486 return (pm_node_t *) pm_range_node_create(parser, node, &
operator, right);
17489 return (pm_node_t *) pm_range_node_create(parser, node, &
operator, NULL);
17495 case PM_TOKEN_CARET: {
17496 parser_lex(parser);
17501 switch (parser->
current.type) {
17502 case PM_TOKEN_IDENTIFIER: {
17503 parser_lex(parser);
17504 pm_node_t *variable = (pm_node_t *) parse_variable(parser);
17506 if (variable == NULL) {
17507 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
previous, PM_ERR_NO_LOCAL_VARIABLE);
17508 variable = (pm_node_t *) pm_local_variable_read_node_missing_create(parser, &parser->
previous, 0);
17511 return (pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17513 case PM_TOKEN_INSTANCE_VARIABLE: {
17514 parser_lex(parser);
17515 pm_node_t *variable = (pm_node_t *) pm_instance_variable_read_node_create(parser, &parser->
previous);
17517 return (pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17519 case PM_TOKEN_CLASS_VARIABLE: {
17520 parser_lex(parser);
17521 pm_node_t *variable = (pm_node_t *) pm_class_variable_read_node_create(parser, &parser->
previous);
17523 return (pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17525 case PM_TOKEN_GLOBAL_VARIABLE: {
17526 parser_lex(parser);
17527 pm_node_t *variable = (pm_node_t *) pm_global_variable_read_node_create(parser, &parser->
previous);
17529 return (pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17531 case PM_TOKEN_NUMBERED_REFERENCE: {
17532 parser_lex(parser);
17533 pm_node_t *variable = (pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->
previous);
17535 return (pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17537 case PM_TOKEN_BACK_REFERENCE: {
17538 parser_lex(parser);
17539 pm_node_t *variable = (pm_node_t *) pm_back_reference_read_node_create(parser, &parser->
previous);
17541 return (pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17543 case PM_TOKEN_PARENTHESIS_LEFT: {
17548 parser_lex(parser);
17550 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN, (uint16_t) (depth + 1));
17553 accept1(parser, PM_TOKEN_NEWLINE);
17554 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
17555 return (pm_node_t *) pm_pinned_expression_node_create(parser, expression, &
operator, &lparen, &parser->
previous);
17560 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
17561 pm_node_t *variable = (pm_node_t *) pm_missing_node_create(parser,
operator.start,
operator.end);
17562 return (pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17566 case PM_TOKEN_UCOLON_COLON: {
17568 parser_lex(parser);
17570 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
17571 pm_constant_path_node_t *node = pm_constant_path_node_create(parser, NULL, &delimiter, &parser->
previous);
17573 return parse_pattern_constant_path(parser, captures, (pm_node_t *) node, (uint16_t) (depth + 1));
17575 case PM_TOKEN_CONSTANT: {
17577 parser_lex(parser);
17579 pm_node_t *node = (pm_node_t *) pm_constant_read_node_create(parser, &constant);
17580 return parse_pattern_constant_path(parser, captures, node, (uint16_t) (depth + 1));
17583 pm_parser_err_current(parser, diag_id);
17584 return (pm_node_t *) pm_missing_node_create(parser, parser->
current.start, parser->
current.end);
17594 pm_node_t *node = first_node;
17596 while ((node == NULL) || accept1(parser, PM_TOKEN_PIPE)) {
17599 switch (parser->
current.type) {
17600 case PM_TOKEN_IDENTIFIER:
17601 case PM_TOKEN_BRACKET_LEFT_ARRAY:
17602 case PM_TOKEN_BRACE_LEFT:
17603 case PM_TOKEN_CARET:
17604 case PM_TOKEN_CONSTANT:
17605 case PM_TOKEN_UCOLON_COLON:
17606 case PM_TOKEN_UDOT_DOT:
17607 case PM_TOKEN_UDOT_DOT_DOT:
17608 case PM_CASE_PRIMITIVE: {
17609 if (node == NULL) {
17610 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17612 pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
17613 node = (pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17618 case PM_TOKEN_PARENTHESIS_LEFT:
17619 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
17621 parser_lex(parser);
17623 pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
17624 accept1(parser, PM_TOKEN_NEWLINE);
17625 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
17626 pm_node_t *right = (pm_node_t *) pm_parentheses_node_create(parser, &opening, body, &parser->
previous, 0);
17628 if (node == NULL) {
17631 node = (pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17637 pm_parser_err_current(parser, diag_id);
17638 pm_node_t *right = (pm_node_t *) pm_missing_node_create(parser, parser->
current.start, parser->
current.end);
17640 if (node == NULL) {
17643 node = (pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17653 while (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
17655 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_PATTERN_IDENT_AFTER_HROCKET);
17660 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17664 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17665 pm_local_variable_target_node_t *target = pm_local_variable_target_node_create(
17667 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17669 (uint32_t) (depth == -1 ? 0 : depth)
17672 node = (pm_node_t *) pm_capture_pattern_node_create(parser, node, target, &
operator);
17683 pm_node_t *node = NULL;
17685 bool leading_rest =
false;
17686 bool trailing_rest =
false;
17688 switch (parser->
current.type) {
17689 case PM_TOKEN_LABEL: {
17690 parser_lex(parser);
17691 pm_node_t *key = (pm_node_t *) pm_symbol_node_label_create(parser, &parser->
previous);
17692 node = (pm_node_t *) parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1));
17694 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17695 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17700 case PM_TOKEN_USTAR_STAR: {
17701 node = parse_pattern_keyword_rest(parser, captures);
17702 node = (pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17704 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17705 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17710 case PM_TOKEN_STRING_BEGIN: {
17713 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17715 if (pm_symbol_node_label_p(node)) {
17716 node = (pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17718 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17719 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17725 node = parse_pattern_primitives(parser, captures, node, diag_id, (uint16_t) (depth + 1));
17728 case PM_TOKEN_USTAR: {
17729 if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
17730 parser_lex(parser);
17731 node = (pm_node_t *) parse_pattern_rest(parser, captures);
17732 leading_rest =
true;
17738 node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1));
17744 if (pm_symbol_node_label_p(node)) {
17745 return (pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17748 if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser, PM_TOKEN_COMMA)) {
17752 pm_node_list_t nodes = { 0 };
17753 pm_node_list_append(&nodes, node);
17756 while (accept1(parser, PM_TOKEN_COMMA)) {
17758 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)) {
17759 node = (pm_node_t *) pm_implicit_rest_node_create(parser, &parser->
previous);
17760 pm_node_list_append(&nodes, node);
17761 trailing_rest =
true;
17765 if (accept1(parser, PM_TOKEN_USTAR)) {
17766 node = (pm_node_t *) parse_pattern_rest(parser, captures);
17771 if (trailing_rest) {
17772 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
17775 trailing_rest =
true;
17777 node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
17780 pm_node_list_append(&nodes, node);
17787 if (leading_rest && PM_NODE_TYPE_P(nodes.
nodes[nodes.
size - 1], PM_SPLAT_NODE)) {
17788 node = (pm_node_t *) pm_find_pattern_node_create(parser, &nodes);
17790 if (nodes.
size == 2) {
17791 pm_parser_err_node(parser, node, PM_ERR_PATTERN_FIND_MISSING_INNER);
17794 node = (pm_node_t *) pm_array_pattern_node_node_list_create(parser, &nodes);
17796 if (leading_rest && trailing_rest) {
17797 pm_parser_err_node(parser, node, PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS);
17802 }
else if (leading_rest) {
17805 node = (pm_node_t *) pm_array_pattern_node_rest_create(parser, node);
17817parse_negative_numeric(pm_node_t *node) {
17818 switch (PM_NODE_TYPE(node)) {
17819 case PM_INTEGER_NODE: {
17820 pm_integer_node_t *cast = (pm_integer_node_t *) node;
17825 case PM_FLOAT_NODE: {
17826 pm_float_node_t *cast = (pm_float_node_t *) node;
17831 case PM_RATIONAL_NODE: {
17832 pm_rational_node_t *cast = (pm_rational_node_t *) node;
17837 case PM_IMAGINARY_NODE:
17839 parse_negative_numeric(((pm_imaginary_node_t *) node)->numeric);
17842 assert(
false &&
"unreachable");
17855 case PM_ERR_HASH_KEY: {
17859 case PM_ERR_HASH_VALUE:
17860 case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: {
17864 case PM_ERR_UNARY_RECEIVER: {
17869 case PM_ERR_UNARY_DISALLOWED:
17870 case PM_ERR_EXPECT_ARGUMENT: {
17875 pm_parser_err_previous(parser, diag_id);
17884parse_retry(
pm_parser_t *parser,
const pm_node_t *node) {
17885#define CONTEXT_NONE 0
17886#define CONTEXT_THROUGH_ENSURE 1
17887#define CONTEXT_THROUGH_ELSE 2
17890 int context = CONTEXT_NONE;
17892 while (context_node != NULL) {
17893 switch (context_node->
context) {
17914 if (context == CONTEXT_NONE) {
17915 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_WITHOUT_RESCUE);
17916 }
else if (context == CONTEXT_THROUGH_ENSURE) {
17917 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ENSURE);
17918 }
else if (context == CONTEXT_THROUGH_ELSE) {
17919 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ELSE);
17931 context = CONTEXT_THROUGH_ELSE;
17942 context = CONTEXT_THROUGH_ENSURE;
17946 assert(
false &&
"unreachable");
17976 context_node = context_node->
prev;
17980#undef CONTEXT_ENSURE
17988parse_yield(
pm_parser_t *parser,
const pm_node_t *node) {
17991 while (context_node != NULL) {
17992 switch (context_node->
context) {
18017 pm_parser_err_node(parser, node, PM_ERR_INVALID_YIELD);
18021 assert(
false &&
"unreachable");
18062 context_node = context_node->
prev;
18094parse_regular_expression_error(
const uint8_t *start,
const uint8_t *end,
const char *message,
void *data) {
18098 if (callback_data->
shared) {
18104 PM_PARSER_ERR_FORMAT(callback_data->
parser, location.
start, location.
end, PM_ERR_REGEXP_PARSE_ERROR, message);
18111parse_regular_expression_errors(
pm_parser_t *parser, pm_regular_expression_node_t *node) {
18117 .shared = unescaped->
type == PM_STRING_SHARED
18120 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);
18126static inline pm_node_t *
18127parse_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) {
18128 switch (parser->
current.type) {
18129 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
18130 parser_lex(parser);
18132 pm_array_node_t *array = pm_array_node_create(parser, &parser->
previous);
18133 pm_accepts_block_stack_push(parser,
true);
18134 bool parsed_bare_hash =
false;
18136 while (!match2(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_EOF)) {
18137 bool accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
18141 if (accepted_newline && match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
18147 if (accept1(parser, PM_TOKEN_COMMA)) {
18150 if (accepted_newline) {
18151 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
18167 if (match1(parser, PM_TOKEN_BRACKET_RIGHT))
break;
18169 pm_node_t *element;
18171 if (accept1(parser, PM_TOKEN_USTAR)) {
18173 pm_node_t *expression = NULL;
18175 if (match3(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_EOF)) {
18176 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
18178 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
18181 element = (pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
18182 }
else if (match2(parser, PM_TOKEN_LABEL, PM_TOKEN_USTAR_STAR)) {
18183 if (parsed_bare_hash) {
18184 pm_parser_err_current(parser, PM_ERR_EXPRESSION_BARE_HASH);
18187 element = (pm_node_t *) pm_keyword_hash_node_create(parser);
18190 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)) {
18191 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
18194 pm_static_literals_free(&hash_keys);
18195 parsed_bare_hash =
true;
18197 element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_ARRAY_EXPRESSION, (uint16_t) (depth + 1));
18199 if (pm_symbol_node_label_p(element) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
18200 if (parsed_bare_hash) {
18201 pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
18204 pm_keyword_hash_node_t *hash = pm_keyword_hash_node_create(parser);
18206 pm_hash_key_static_literals_add(parser, &hash_keys, element);
18209 if (parser->
previous.
type == PM_TOKEN_EQUAL_GREATER) {
18212 operator = not_provided(parser);
18215 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
18216 pm_node_t *assoc = (pm_node_t *) pm_assoc_node_create(parser, element, &
operator, value);
18217 pm_keyword_hash_node_elements_append(hash, assoc);
18219 element = (pm_node_t *) hash;
18220 if (accept1(parser, PM_TOKEN_COMMA) && !match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
18221 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
18224 pm_static_literals_free(&hash_keys);
18225 parsed_bare_hash =
true;
18229 pm_array_node_elements_append(array, element);
18230 if (PM_NODE_TYPE_P(element, PM_MISSING_NODE))
break;
18233 accept1(parser, PM_TOKEN_NEWLINE);
18235 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
18241 pm_array_node_close_set(array, &parser->
previous);
18242 pm_accepts_block_stack_pop(parser);
18244 return (pm_node_t *) array;
18246 case PM_TOKEN_PARENTHESIS_LEFT:
18247 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
18249 pm_node_flags_t flags = 0;
18251 pm_node_list_t current_block_exits = { 0 };
18252 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18254 parser_lex(parser);
18256 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
18257 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
18258 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
18265 if (match2(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_EOF)) {
18266 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
18268 pop_block_exits(parser, previous_block_exits);
18269 pm_node_list_free(¤t_block_exits);
18271 return (pm_node_t *) pm_parentheses_node_create(parser, &opening, NULL, &parser->
previous, flags);
18276 pm_accepts_block_stack_push(parser,
true);
18278 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
18279 context_pop(parser);
18284 bool terminator_found =
false;
18286 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
18287 terminator_found =
true;
18288 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
18289 }
else if (accept1(parser, PM_TOKEN_NEWLINE)) {
18290 terminator_found =
true;
18293 if (terminator_found) {
18295 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
18296 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
18297 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
18306 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18307 if (opening.
type == PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
18308 lex_state_set(parser, PM_LEX_STATE_ENDARG);
18311 parser_lex(parser);
18312 pm_accepts_block_stack_pop(parser);
18314 pop_block_exits(parser, previous_block_exits);
18315 pm_node_list_free(¤t_block_exits);
18317 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) || PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
18321 pm_multi_target_node_t *multi_target;
18323 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) && ((pm_multi_target_node_t *) statement)->lparen_loc.start == NULL) {
18324 multi_target = (pm_multi_target_node_t *) statement;
18326 multi_target = pm_multi_target_node_create(parser);
18327 pm_multi_target_node_targets_append(parser, multi_target, statement);
18330 pm_location_t lparen_loc = PM_LOCATION_TOKEN_VALUE(&opening);
18339 if (match1(parser, PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
18340 result = parse_targets(parser, (pm_node_t *) multi_target, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18341 accept1(parser, PM_TOKEN_NEWLINE);
18343 result = (pm_node_t *) multi_target;
18352 }
else if (binding_power != PM_BINDING_POWER_STATEMENT) {
18355 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
18356 }
else if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
18360 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
18369 pm_statements_node_t *statements = pm_statements_node_create(parser);
18370 pm_statements_node_body_append(parser, statements, statement,
true);
18372 return (pm_node_t *) pm_parentheses_node_create(parser, &opening, (pm_node_t *) statements, &parser->
previous, flags);
18379 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
18381 pm_statements_node_t *statements = pm_statements_node_create(parser);
18382 pm_statements_node_body_append(parser, statements, statement,
true);
18386 if (!terminator_found && !match1(parser, PM_TOKEN_EOF)) {
18392 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
18393 pm_statements_node_body_append(parser, statements, node,
true);
18400 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) parser->
recovering =
false;
18406 if (PM_NODE_TYPE_P(node, PM_MISSING_NODE))
break;
18410 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18411 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18412 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
break;
18413 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18415 }
else if (!match1(parser, PM_TOKEN_EOF)) {
18422 context_pop(parser);
18423 pm_accepts_block_stack_pop(parser);
18424 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
18433 if (PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
18434 pm_multi_target_node_t *multi_target = pm_multi_target_node_create(parser);
18435 pm_multi_target_node_targets_append(parser, multi_target, statement);
18437 statement = (pm_node_t *) multi_target;
18441 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE)) {
18443 pm_token_t operator = { .type = PM_TOKEN_EQUAL, .start = offset, .end = offset };
18444 pm_node_t *value = (pm_node_t *) pm_missing_node_create(parser, offset, offset);
18446 statement = (pm_node_t *) pm_multi_write_node_create(parser, (pm_multi_target_node_t *) statement, &
operator, value);
18449 pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
18453 pop_block_exits(parser, previous_block_exits);
18454 pm_node_list_free(¤t_block_exits);
18456 pm_void_statements_check(parser, statements,
true);
18457 return (pm_node_t *) pm_parentheses_node_create(parser, &opening, (pm_node_t *) statements, &parser->
previous, flags);
18459 case PM_TOKEN_BRACE_LEFT: {
18470 pm_accepts_block_stack_push(parser,
true);
18471 parser_lex(parser);
18473 pm_hash_node_t *node = pm_hash_node_create(parser, &parser->
previous);
18475 if (!match2(parser, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_EOF)) {
18476 if (current_hash_keys != NULL) {
18477 parse_assocs(parser, current_hash_keys, (pm_node_t *) node, (uint16_t) (depth + 1));
18480 parse_assocs(parser, &hash_keys, (pm_node_t *) node, (uint16_t) (depth + 1));
18481 pm_static_literals_free(&hash_keys);
18484 accept1(parser, PM_TOKEN_NEWLINE);
18487 pm_accepts_block_stack_pop(parser);
18488 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM);
18489 pm_hash_node_closing_loc_set(node, &parser->
previous);
18491 return (pm_node_t *) node;
18493 case PM_TOKEN_CHARACTER_LITERAL: {
18494 parser_lex(parser);
18497 opening.
type = PM_TOKEN_STRING_BEGIN;
18501 content.
type = PM_TOKEN_STRING_CONTENT;
18505 pm_node_t *node = (pm_node_t *) pm_string_node_create_current_string(parser, &opening, &content, &closing);
18506 pm_node_flag_set(node, parse_unescaped_encoding(parser));
18510 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
18511 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18516 case PM_TOKEN_CLASS_VARIABLE: {
18517 parser_lex(parser);
18518 pm_node_t *node = (pm_node_t *) pm_class_variable_read_node_create(parser, &parser->
previous);
18520 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18521 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18526 case PM_TOKEN_CONSTANT: {
18527 parser_lex(parser);
18533 match1(parser, PM_TOKEN_PARENTHESIS_LEFT) ||
18534 (accepts_command_call && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
18535 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
18536 match1(parser, PM_TOKEN_BRACE_LEFT)
18539 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18540 return (pm_node_t *) pm_call_node_fcall_create(parser, &constant, &arguments);
18543 pm_node_t *node = (pm_node_t *) pm_constant_read_node_create(parser, &parser->
previous);
18545 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
18548 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18553 case PM_TOKEN_UCOLON_COLON: {
18554 parser_lex(parser);
18557 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
18558 pm_node_t *node = (pm_node_t *) pm_constant_path_node_create(parser, NULL, &delimiter, &parser->
previous);
18560 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
18561 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18566 case PM_TOKEN_UDOT_DOT:
18567 case PM_TOKEN_UDOT_DOT_DOT: {
18569 parser_lex(parser);
18571 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));
18577 if (match2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
18578 pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
18581 return (pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
18583 case PM_TOKEN_FLOAT:
18584 parser_lex(parser);
18585 return (pm_node_t *) pm_float_node_create(parser, &parser->
previous);
18586 case PM_TOKEN_FLOAT_IMAGINARY:
18587 parser_lex(parser);
18588 return (pm_node_t *) pm_float_node_imaginary_create(parser, &parser->
previous);
18589 case PM_TOKEN_FLOAT_RATIONAL:
18590 parser_lex(parser);
18591 return (pm_node_t *) pm_float_node_rational_create(parser, &parser->
previous);
18592 case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY:
18593 parser_lex(parser);
18594 return (pm_node_t *) pm_float_node_rational_imaginary_create(parser, &parser->
previous);
18595 case PM_TOKEN_NUMBERED_REFERENCE: {
18596 parser_lex(parser);
18597 pm_node_t *node = (pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->
previous);
18599 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18600 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18605 case PM_TOKEN_GLOBAL_VARIABLE: {
18606 parser_lex(parser);
18607 pm_node_t *node = (pm_node_t *) pm_global_variable_read_node_create(parser, &parser->
previous);
18609 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18610 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18615 case PM_TOKEN_BACK_REFERENCE: {
18616 parser_lex(parser);
18617 pm_node_t *node = (pm_node_t *) pm_back_reference_read_node_create(parser, &parser->
previous);
18619 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18620 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18625 case PM_TOKEN_IDENTIFIER:
18626 case PM_TOKEN_METHOD_NAME: {
18627 parser_lex(parser);
18629 pm_node_t *node = parse_variable_call(parser);
18631 if (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
18636 pm_call_node_t *call = (pm_call_node_t *) node;
18639 if (parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1))) {
18642 pm_node_flag_unset((pm_node_t *)call, PM_CALL_NODE_FLAGS_VARIABLE_CALL);
18649 const uint8_t *end = pm_arguments_end(&arguments);
18660 (accepts_command_call && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
18661 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
18662 match1(parser, PM_TOKEN_BRACE_LEFT)
18665 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18666 pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
18668 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
18672 parse_target_implicit_parameter(parser, node);
18678 assert(PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE));
18680 if (pm_token_is_numbered_parameter(identifier.
start, identifier.
end)) {
18681 parse_target_implicit_parameter(parser, node);
18683 pm_local_variable_read_node_t *cast = (pm_local_variable_read_node_t *) node;
18684 pm_locals_unread(&pm_parser_scope_find(parser, cast->
depth)->locals, cast->
name);
18688 pm_node_destroy(parser, node);
18689 return (pm_node_t *) fcall;
18693 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
18694 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18699 case PM_TOKEN_HEREDOC_START: {
18705 size_t common_whitespace = (size_t) -1;
18708 parser_lex(parser);
18714 if (match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18720 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18721 node = (pm_node_t *) pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->
previous, &
PM_STRING_EMPTY);
18723 node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &
PM_STRING_EMPTY);
18727 }
else if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) == NULL) {
18735 }
else if (PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18740 pm_node_flag_set(part, parse_unescaped_encoding(parser));
18741 pm_string_node_t *cast = (pm_string_node_t *) part;
18743 cast->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
18747 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18748 assert(
sizeof(pm_string_node_t) ==
sizeof(pm_x_string_node_t));
18749 cast->
base.
type = PM_X_STRING_NODE;
18752 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18753 parse_heredoc_dedent_string(&cast->
unescaped, common_whitespace);
18756 node = (pm_node_t *) cast;
18762 pm_node_list_t parts = { 0 };
18763 pm_node_list_append(&parts, part);
18765 while (!match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18766 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
18767 pm_node_list_append(&parts, part);
18773 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18774 pm_interpolated_x_string_node_t *cast = pm_interpolated_xstring_node_create(parser, &opening, &opening);
18775 cast->
parts = parts;
18778 pm_interpolated_xstring_node_closing_set(cast, &parser->
previous);
18781 node = (pm_node_t *) cast;
18783 pm_interpolated_string_node_t *cast = pm_interpolated_string_node_create(parser, &opening, &parts, &opening);
18784 pm_node_list_free(&parts);
18787 pm_interpolated_string_node_closing_set(cast, &parser->
previous);
18790 node = (pm_node_t *) cast;
18795 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18796 pm_node_list_t *nodes;
18797 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18798 nodes = &((pm_interpolated_x_string_node_t *) node)->parts;
18800 nodes = &((pm_interpolated_string_node_t *) node)->parts;
18803 parse_heredoc_dedent(parser, nodes, common_whitespace);
18807 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
18808 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18813 case PM_TOKEN_INSTANCE_VARIABLE: {
18814 parser_lex(parser);
18815 pm_node_t *node = (pm_node_t *) pm_instance_variable_read_node_create(parser, &parser->
previous);
18817 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18818 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18823 case PM_TOKEN_INTEGER: {
18825 parser_lex(parser);
18826 return (pm_node_t *) pm_integer_node_create(parser, base, &parser->
previous);
18828 case PM_TOKEN_INTEGER_IMAGINARY: {
18830 parser_lex(parser);
18831 return (pm_node_t *) pm_integer_node_imaginary_create(parser, base, &parser->
previous);
18833 case PM_TOKEN_INTEGER_RATIONAL: {
18835 parser_lex(parser);
18836 return (pm_node_t *) pm_integer_node_rational_create(parser, base, &parser->
previous);
18838 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: {
18840 parser_lex(parser);
18841 return (pm_node_t *) pm_integer_node_rational_imaginary_create(parser, base, &parser->
previous);
18843 case PM_TOKEN_KEYWORD___ENCODING__:
18844 parser_lex(parser);
18845 return (pm_node_t *) pm_source_encoding_node_create(parser, &parser->
previous);
18846 case PM_TOKEN_KEYWORD___FILE__:
18847 parser_lex(parser);
18848 return (pm_node_t *) pm_source_file_node_create(parser, &parser->
previous);
18849 case PM_TOKEN_KEYWORD___LINE__:
18850 parser_lex(parser);
18851 return (pm_node_t *) pm_source_line_node_create(parser, &parser->
previous);
18852 case PM_TOKEN_KEYWORD_ALIAS: {
18853 if (binding_power != PM_BINDING_POWER_STATEMENT) {
18854 pm_parser_err_current(parser, PM_ERR_STATEMENT_ALIAS);
18857 parser_lex(parser);
18860 pm_node_t *new_name = parse_alias_argument(parser,
true, (uint16_t) (depth + 1));
18861 pm_node_t *old_name = parse_alias_argument(parser,
false, (uint16_t) (depth + 1));
18863 switch (PM_NODE_TYPE(new_name)) {
18864 case PM_BACK_REFERENCE_READ_NODE:
18865 case PM_NUMBERED_REFERENCE_READ_NODE:
18866 case PM_GLOBAL_VARIABLE_READ_NODE: {
18867 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)) {
18868 if (PM_NODE_TYPE_P(old_name, PM_NUMBERED_REFERENCE_READ_NODE)) {
18869 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE);
18872 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18875 return (pm_node_t *) pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name);
18877 case PM_SYMBOL_NODE:
18878 case PM_INTERPOLATED_SYMBOL_NODE: {
18879 if (!PM_NODE_TYPE_P(old_name, PM_SYMBOL_NODE) && !PM_NODE_TYPE_P(old_name, PM_INTERPOLATED_SYMBOL_NODE)) {
18880 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18885 return (pm_node_t *) pm_alias_method_node_create(parser, &keyword, new_name, old_name);
18888 case PM_TOKEN_KEYWORD_CASE: {
18889 size_t opening_newline_index = token_newline_index(parser);
18890 parser_lex(parser);
18893 pm_node_t *predicate = NULL;
18895 pm_node_list_t current_block_exits = { 0 };
18896 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18898 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18899 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18901 }
else if (match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_END)) {
18903 }
else if (!token_begins_expression_p(parser->
current.type)) {
18906 predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CASE_EXPRESSION_AFTER_CASE, (uint16_t) (depth + 1));
18907 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18910 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
18911 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18912 parser_lex(parser);
18914 pop_block_exits(parser, previous_block_exits);
18915 pm_node_list_free(¤t_block_exits);
18917 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18918 return (pm_node_t *) pm_case_node_create(parser, &case_keyword, predicate, &parser->
previous);
18923 pm_token_t end_keyword = not_provided(parser);
18926 if (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18927 pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, &end_keyword);
18933 while (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18934 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18935 parser_lex(parser);
18938 pm_when_node_t *when_node = pm_when_node_create(parser, &when_keyword);
18941 if (accept1(parser, PM_TOKEN_USTAR)) {
18943 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
18945 pm_splat_node_t *splat_node = pm_splat_node_create(parser, &
operator, expression);
18946 pm_when_node_conditions_append(when_node, (pm_node_t *) splat_node);
18948 if (PM_NODE_TYPE_P(expression, PM_MISSING_NODE))
break;
18950 pm_node_t *condition = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_CASE_EXPRESSION_AFTER_WHEN, (uint16_t) (depth + 1));
18951 pm_when_node_conditions_append(when_node, condition);
18955 if (PM_NODE_TYPE_P(condition, PM_MISSING_NODE))
break;
18959 if (PM_NODE_TYPE_P(condition, PM_STRING_NODE)) {
18960 pm_node_flag_set(condition, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
18961 }
else if (PM_NODE_TYPE_P(condition, PM_SOURCE_FILE_NODE)) {
18962 pm_node_flag_set(condition, PM_NODE_FLAG_STATIC_LITERAL);
18965 pm_when_clause_static_literals_add(parser, &literals, condition);
18967 }
while (accept1(parser, PM_TOKEN_COMMA));
18969 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18970 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
18971 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
18974 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_WHEN_DELIMITER);
18975 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
18978 if (!match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18979 pm_statements_node_t *statements = parse_statements(parser,
PM_CONTEXT_CASE_WHEN, (uint16_t) (depth + 1));
18980 if (statements != NULL) {
18981 pm_when_node_statements_set(when_node, statements);
18985 pm_case_node_condition_append(case_node, (pm_node_t *) when_node);
18991 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18994 pm_static_literals_free(&literals);
18995 node = (pm_node_t *) case_node;
18997 pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate, &end_keyword);
19001 if (predicate == NULL) {
19002 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MATCH_MISSING_PREDICATE);
19008 while (match1(parser, PM_TOKEN_KEYWORD_IN)) {
19009 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
19014 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
19016 parser_lex(parser);
19021 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));
19024 pm_constant_id_list_free(&captures);
19029 if (accept1(parser, PM_TOKEN_KEYWORD_IF_MODIFIER)) {
19031 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
19032 pattern = (pm_node_t *) pm_if_node_modifier_create(parser, pattern, &keyword, predicate);
19033 }
else if (accept1(parser, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) {
19035 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
19036 pattern = (pm_node_t *) pm_unless_node_modifier_create(parser, pattern, &keyword, predicate);
19043 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
19044 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
19047 then_keyword = not_provided(parser);
19050 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_IN_DELIMITER);
19056 pm_statements_node_t *statements;
19057 if (match3(parser, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19065 pm_node_t *condition = (pm_node_t *) pm_in_node_create(parser, pattern, statements, &in_keyword, &then_keyword);
19066 pm_case_match_node_condition_append(case_node, condition);
19072 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
19075 node = (pm_node_t *) case_node;
19078 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19079 if (accept1(parser, PM_TOKEN_KEYWORD_ELSE)) {
19081 pm_else_node_t *else_node;
19083 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19084 else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser,
PM_CONTEXT_ELSE, (uint16_t) (depth + 1)), &parser->
current);
19086 else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->
current);
19089 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
19090 pm_case_node_else_clause_set((pm_case_node_t *) node, else_node);
19092 pm_case_match_node_else_clause_set((pm_case_match_node_t *) node, else_node);
19096 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
19097 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM);
19099 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
19100 pm_case_node_end_keyword_loc_set((pm_case_node_t *) node, &parser->
previous);
19102 pm_case_match_node_end_keyword_loc_set((pm_case_match_node_t *) node, &parser->
previous);
19105 pop_block_exits(parser, previous_block_exits);
19106 pm_node_list_free(¤t_block_exits);
19110 case PM_TOKEN_KEYWORD_BEGIN: {
19111 size_t opening_newline_index = token_newline_index(parser);
19112 parser_lex(parser);
19115 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19117 pm_node_list_t current_block_exits = { 0 };
19118 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19119 pm_statements_node_t *begin_statements = NULL;
19121 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19122 pm_accepts_block_stack_push(parser,
true);
19123 begin_statements = parse_statements(parser,
PM_CONTEXT_BEGIN, (uint16_t) (depth + 1));
19124 pm_accepts_block_stack_pop(parser);
19125 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19128 pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
19129 parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
19130 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM);
19133 pm_begin_node_end_keyword_set(begin_node, &parser->
previous);
19135 pop_block_exits(parser, previous_block_exits);
19136 pm_node_list_free(¤t_block_exits);
19138 return (pm_node_t *) begin_node;
19140 case PM_TOKEN_KEYWORD_BEGIN_UPCASE: {
19141 pm_node_list_t current_block_exits = { 0 };
19142 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19144 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19145 pm_parser_err_current(parser, PM_ERR_STATEMENT_PREEXE_BEGIN);
19148 parser_lex(parser);
19151 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_BEGIN_UPCASE_BRACE);
19153 pm_statements_node_t *statements = parse_statements(parser,
PM_CONTEXT_PREEXE, (uint16_t) (depth + 1));
19155 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM);
19158 pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
19161 flush_block_exits(parser, previous_block_exits);
19162 pm_node_list_free(¤t_block_exits);
19164 return (pm_node_t *) pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous);
19166 case PM_TOKEN_KEYWORD_BREAK:
19167 case PM_TOKEN_KEYWORD_NEXT:
19168 case PM_TOKEN_KEYWORD_RETURN: {
19169 parser_lex(parser);
19175 token_begins_expression_p(parser->
current.type) ||
19176 match2(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)
19178 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].left;
19180 if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
19182 parse_arguments(parser, &arguments,
false, PM_TOKEN_EOF, (uint16_t) (depth + 1));
19185 if (!accepts_command_call && arguments.
arguments != NULL) {
19191 switch (keyword.
type) {
19192 case PM_TOKEN_KEYWORD_BREAK: {
19193 pm_node_t *node = (pm_node_t *) pm_break_node_create(parser, &keyword, arguments.
arguments);
19197 case PM_TOKEN_KEYWORD_NEXT: {
19198 pm_node_t *node = (pm_node_t *) pm_next_node_create(parser, &keyword, arguments.
arguments);
19202 case PM_TOKEN_KEYWORD_RETURN: {
19203 pm_node_t *node = (pm_node_t *) pm_return_node_create(parser, &keyword, arguments.
arguments);
19204 parse_return(parser, node);
19208 assert(
false &&
"unreachable");
19212 case PM_TOKEN_KEYWORD_SUPER: {
19213 parser_lex(parser);
19217 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
19222 ((arguments.
block == NULL) || PM_NODE_TYPE_P(arguments.
block, PM_BLOCK_NODE))
19224 return (pm_node_t *) pm_forwarding_super_node_create(parser, &keyword, &arguments);
19227 return (pm_node_t *) pm_super_node_create(parser, &keyword, &arguments);
19229 case PM_TOKEN_KEYWORD_YIELD: {
19230 parser_lex(parser);
19234 parse_arguments_list(parser, &arguments,
false, accepts_command_call, (uint16_t) (depth + 1));
19240 if (arguments.
block != NULL) {
19241 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
19242 pm_node_destroy(parser, arguments.
block);
19243 arguments.
block = NULL;
19251 case PM_TOKEN_KEYWORD_CLASS: {
19252 size_t opening_newline_index = token_newline_index(parser);
19253 parser_lex(parser);
19256 pm_do_loop_stack_push(parser,
false);
19258 pm_node_list_t current_block_exits = { 0 };
19259 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19261 if (accept1(parser, PM_TOKEN_LESS_LESS)) {
19263 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));
19265 pm_parser_scope_push(parser,
true);
19266 if (!match2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
19270 pm_node_t *statements = NULL;
19271 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19272 pm_accepts_block_stack_push(parser,
true);
19273 statements = (pm_node_t *) parse_statements(parser,
PM_CONTEXT_SCLASS, (uint16_t) (depth + 1));
19274 pm_accepts_block_stack_pop(parser);
19277 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
19278 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
19279 statements = (pm_node_t *) parse_rescues_implicit_begin(parser, opening_newline_index, &class_keyword, class_keyword.
start, (pm_statements_node_t *) statements, PM_RESCUES_SCLASS, (uint16_t) (depth + 1));
19281 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
19284 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
19289 pm_parser_scope_pop(parser);
19290 pm_do_loop_stack_pop(parser);
19292 flush_block_exits(parser, previous_block_exits);
19293 pm_node_list_free(¤t_block_exits);
19295 return (pm_node_t *) pm_singleton_class_node_create(parser, &locals, &class_keyword, &
operator, expression, statements, &parser->
previous);
19298 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_CLASS_NAME, (uint16_t) (depth + 1));
19300 if (name.
type != PM_TOKEN_CONSTANT) {
19301 pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME);
19305 pm_node_t *superclass;
19307 if (match1(parser, PM_TOKEN_LESS)) {
19308 inheritance_operator = parser->
current;
19309 lex_state_set(parser, PM_LEX_STATE_BEG);
19312 parser_lex(parser);
19314 superclass = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CLASS_SUPERCLASS, (uint16_t) (depth + 1));
19316 inheritance_operator = not_provided(parser);
19320 pm_parser_scope_push(parser,
true);
19322 if (inheritance_operator.
type != PM_TOKEN_NOT_PROVIDED) {
19323 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CLASS_UNEXPECTED_END);
19325 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19327 pm_node_t *statements = NULL;
19329 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19330 pm_accepts_block_stack_push(parser,
true);
19331 statements = (pm_node_t *) parse_statements(parser,
PM_CONTEXT_CLASS, (uint16_t) (depth + 1));
19332 pm_accepts_block_stack_pop(parser);
19335 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
19336 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
19337 statements = (pm_node_t *) parse_rescues_implicit_begin(parser, opening_newline_index, &class_keyword, class_keyword.
start, (pm_statements_node_t *) statements, PM_RESCUES_CLASS, (uint16_t) (depth + 1));
19339 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
19342 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
19344 if (context_def_p(parser)) {
19345 pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
19351 pm_parser_scope_pop(parser);
19352 pm_do_loop_stack_pop(parser);
19354 if (!PM_NODE_TYPE_P(constant_path, PM_CONSTANT_PATH_NODE) && !(PM_NODE_TYPE_P(constant_path, PM_CONSTANT_READ_NODE))) {
19355 pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
19358 pop_block_exits(parser, previous_block_exits);
19359 pm_node_list_free(¤t_block_exits);
19361 return (pm_node_t *) pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, &inheritance_operator, superclass, statements, &parser->
previous);
19363 case PM_TOKEN_KEYWORD_DEF: {
19364 pm_node_list_t current_block_exits = { 0 };
19365 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19368 size_t opening_newline_index = token_newline_index(parser);
19370 pm_node_t *receiver = NULL;
19378 parser_lex(parser);
19382 bool valid_name =
true;
19384 switch (parser->
current.type) {
19385 case PM_CASE_OPERATOR:
19386 pm_parser_scope_push(parser,
true);
19387 lex_state_set(parser, PM_LEX_STATE_ENDFN);
19388 parser_lex(parser);
19392 case PM_TOKEN_IDENTIFIER: {
19393 parser_lex(parser);
19395 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
19396 receiver = parse_variable_call(parser);
19398 pm_parser_scope_push(parser,
true);
19399 lex_state_set(parser, PM_LEX_STATE_FNAME);
19400 parser_lex(parser);
19403 name = parse_method_definition_name(parser);
19406 pm_parser_scope_push(parser,
true);
19413 case PM_TOKEN_INSTANCE_VARIABLE:
19414 case PM_TOKEN_CLASS_VARIABLE:
19415 case PM_TOKEN_GLOBAL_VARIABLE:
19416 valid_name =
false;
19418 case PM_TOKEN_CONSTANT:
19419 case PM_TOKEN_KEYWORD_NIL:
19420 case PM_TOKEN_KEYWORD_SELF:
19421 case PM_TOKEN_KEYWORD_TRUE:
19422 case PM_TOKEN_KEYWORD_FALSE:
19423 case PM_TOKEN_KEYWORD___FILE__:
19424 case PM_TOKEN_KEYWORD___LINE__:
19425 case PM_TOKEN_KEYWORD___ENCODING__: {
19426 pm_parser_scope_push(parser,
true);
19427 parser_lex(parser);
19431 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
19432 lex_state_set(parser, PM_LEX_STATE_FNAME);
19433 parser_lex(parser);
19436 switch (identifier.
type) {
19437 case PM_TOKEN_CONSTANT:
19438 receiver = (pm_node_t *) pm_constant_read_node_create(parser, &identifier);
19440 case PM_TOKEN_INSTANCE_VARIABLE:
19441 receiver = (pm_node_t *) pm_instance_variable_read_node_create(parser, &identifier);
19443 case PM_TOKEN_CLASS_VARIABLE:
19444 receiver = (pm_node_t *) pm_class_variable_read_node_create(parser, &identifier);
19446 case PM_TOKEN_GLOBAL_VARIABLE:
19447 receiver = (pm_node_t *) pm_global_variable_read_node_create(parser, &identifier);
19449 case PM_TOKEN_KEYWORD_NIL:
19450 receiver = (pm_node_t *) pm_nil_node_create(parser, &identifier);
19452 case PM_TOKEN_KEYWORD_SELF:
19453 receiver = (pm_node_t *) pm_self_node_create(parser, &identifier);
19455 case PM_TOKEN_KEYWORD_TRUE:
19456 receiver = (pm_node_t *) pm_true_node_create(parser, &identifier);
19458 case PM_TOKEN_KEYWORD_FALSE:
19459 receiver = (pm_node_t *) pm_false_node_create(parser, &identifier);
19461 case PM_TOKEN_KEYWORD___FILE__:
19462 receiver = (pm_node_t *) pm_source_file_node_create(parser, &identifier);
19464 case PM_TOKEN_KEYWORD___LINE__:
19465 receiver = (pm_node_t *) pm_source_line_node_create(parser, &identifier);
19467 case PM_TOKEN_KEYWORD___ENCODING__:
19468 receiver = (pm_node_t *) pm_source_encoding_node_create(parser, &identifier);
19474 name = parse_method_definition_name(parser);
19484 case PM_TOKEN_PARENTHESIS_LEFT: {
19489 context_pop(parser);
19490 parser_lex(parser);
19493 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEF_RECEIVER, (uint16_t) (depth + 1));
19495 accept1(parser, PM_TOKEN_NEWLINE);
19496 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19499 lex_state_set(parser, PM_LEX_STATE_FNAME);
19500 expect2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON, PM_ERR_DEF_RECEIVER_TERM);
19503 receiver = (pm_node_t *) pm_parentheses_node_create(parser, &lparen, expression, &rparen, 0);
19507 pm_parser_scope_push(parser,
true);
19509 name = parse_method_definition_name(parser);
19513 pm_parser_scope_push(parser,
true);
19514 name = parse_method_definition_name(parser);
19520 pm_parameters_node_t *params;
19522 switch (parser->
current.type) {
19523 case PM_TOKEN_PARENTHESIS_LEFT: {
19524 parser_lex(parser);
19527 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19530 params = parse_parameters(parser, PM_BINDING_POWER_DEFINED,
true,
false,
true,
true,
false, (uint16_t) (depth + 1));
19533 lex_state_set(parser, PM_LEX_STATE_BEG);
19536 context_pop(parser);
19537 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19546 case PM_CASE_PARAMETER: {
19549 if (parser->
current.type == PM_TOKEN_LABEL) {
19550 lex_state_set(parser, parser->
lex_state | PM_LEX_STATE_LABEL);
19553 lparen = not_provided(parser);
19554 rparen = not_provided(parser);
19555 params = parse_parameters(parser, PM_BINDING_POWER_DEFINED,
false,
false,
true,
true,
false, (uint16_t) (depth + 1));
19557 context_pop(parser);
19561 lparen = not_provided(parser);
19562 rparen = not_provided(parser);
19565 context_pop(parser);
19570 pm_node_t *statements = NULL;
19574 if (accept1(parser, PM_TOKEN_EQUAL)) {
19575 if (token_is_setter_name(&name)) {
19576 pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
19581 pm_do_loop_stack_push(parser,
false);
19582 statements = (pm_node_t *) pm_statements_node_create(parser);
19584 bool allow_command_call;
19586 allow_command_call = accepts_command_call;
19589 allow_command_call = binding_power == PM_BINDING_POWER_ASSIGNMENT || binding_power < PM_BINDING_POWER_COMPOSITION;
19592 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_DEFINED + 1, allow_command_call,
false, PM_ERR_DEF_ENDLESS, (uint16_t) (depth + 1));
19594 if (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
19598 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));
19599 context_pop(parser);
19601 statement = (pm_node_t *) pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value);
19604 pm_statements_node_body_append(parser, (pm_statements_node_t *) statements, statement,
false);
19605 pm_do_loop_stack_pop(parser);
19606 context_pop(parser);
19607 end_keyword = not_provided(parser);
19609 equal = not_provided(parser);
19611 if (lparen.
type == PM_TOKEN_NOT_PROVIDED) {
19612 lex_state_set(parser, PM_LEX_STATE_BEG);
19614 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_DEF_PARAMS_TERM);
19616 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19619 pm_accepts_block_stack_push(parser,
true);
19620 pm_do_loop_stack_push(parser,
false);
19622 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19623 pm_accepts_block_stack_push(parser,
true);
19624 statements = (pm_node_t *) parse_statements(parser,
PM_CONTEXT_DEF, (uint16_t) (depth + 1));
19625 pm_accepts_block_stack_pop(parser);
19628 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
19629 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
19630 statements = (pm_node_t *) parse_rescues_implicit_begin(parser, opening_newline_index, &def_keyword, def_keyword.
start, (pm_statements_node_t *) statements, PM_RESCUES_DEF, (uint16_t) (depth + 1));
19632 parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword,
false,
false);
19635 pm_accepts_block_stack_pop(parser);
19636 pm_do_loop_stack_pop(parser);
19638 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_DEF_TERM);
19644 pm_parser_scope_pop(parser);
19651 pm_constant_id_t name_id = pm_parser_constant_id_location(parser, name.
start, parse_operator_symbol_name(&name));
19653 flush_block_exits(parser, previous_block_exits);
19654 pm_node_list_free(¤t_block_exits);
19656 return (pm_node_t *) pm_def_node_create(
19672 case PM_TOKEN_KEYWORD_DEFINED: {
19673 parser_lex(parser);
19678 pm_node_t *expression;
19681 bool newline = accept1(parser, PM_TOKEN_NEWLINE);
19683 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19686 if (newline && accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19687 expression = (pm_node_t *) pm_parentheses_node_create(parser, &lparen, NULL, &parser->
previous, 0);
19688 lparen = not_provided(parser);
19689 rparen = not_provided(parser);
19691 expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19694 rparen = not_provided(parser);
19696 accept1(parser, PM_TOKEN_NEWLINE);
19697 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19702 lparen = not_provided(parser);
19703 rparen = not_provided(parser);
19704 expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19707 context_pop(parser);
19708 return (pm_node_t *) pm_defined_node_create(
19713 &PM_LOCATION_TOKEN_VALUE(&keyword)
19716 case PM_TOKEN_KEYWORD_END_UPCASE: {
19717 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19718 pm_parser_err_current(parser, PM_ERR_STATEMENT_POSTEXE_END);
19721 parser_lex(parser);
19724 if (context_def_p(parser)) {
19725 pm_parser_warn_token(parser, &keyword, PM_WARN_END_IN_METHOD);
19728 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_END_UPCASE_BRACE);
19730 pm_statements_node_t *statements = parse_statements(parser,
PM_CONTEXT_POSTEXE, (uint16_t) (depth + 1));
19732 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM);
19733 return (pm_node_t *) pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous);
19735 case PM_TOKEN_KEYWORD_FALSE:
19736 parser_lex(parser);
19737 return (pm_node_t *) pm_false_node_create(parser, &parser->
previous);
19738 case PM_TOKEN_KEYWORD_FOR: {
19739 size_t opening_newline_index = token_newline_index(parser);
19740 parser_lex(parser);
19748 if (accept1(parser, PM_TOKEN_USTAR)) {
19750 pm_node_t *name = NULL;
19752 if (token_begins_expression_p(parser->
current.type)) {
19753 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19756 index = (pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
19757 }
else if (token_begins_expression_p(parser->
current.type)) {
19758 index = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
19760 pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX);
19761 index = (pm_node_t *) pm_missing_node_create(parser, for_keyword.
start, for_keyword.
end);
19765 if (match1(parser, PM_TOKEN_COMMA)) {
19766 index = parse_targets(parser, index, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19768 index = parse_target(parser, index,
false,
false);
19771 context_pop(parser);
19772 pm_do_loop_stack_push(parser,
true);
19774 expect1(parser, PM_TOKEN_KEYWORD_IN, PM_ERR_FOR_IN);
19777 pm_node_t *collection = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_FOR_COLLECTION, (uint16_t) (depth + 1));
19778 pm_do_loop_stack_pop(parser);
19781 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19784 do_keyword = not_provided(parser);
19785 if (!match2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE)) {
19790 pm_statements_node_t *statements = NULL;
19791 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19792 statements = parse_statements(parser,
PM_CONTEXT_FOR, (uint16_t) (depth + 1));
19795 parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword,
false,
false);
19796 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM);
19798 return (pm_node_t *) pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, &do_keyword, &parser->
previous);
19800 case PM_TOKEN_KEYWORD_IF:
19801 if (parser_end_of_line_p(parser)) {
19802 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
19805 size_t opening_newline_index = token_newline_index(parser);
19806 bool if_after_else = parser->
previous.
type == PM_TOKEN_KEYWORD_ELSE;
19807 parser_lex(parser);
19809 return parse_conditional(parser,
PM_CONTEXT_IF, opening_newline_index, if_after_else, (uint16_t) (depth + 1));
19810 case PM_TOKEN_KEYWORD_UNDEF: {
19811 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19812 pm_parser_err_current(parser, PM_ERR_STATEMENT_UNDEF);
19815 parser_lex(parser);
19816 pm_undef_node_t *undef = pm_undef_node_create(parser, &parser->
previous);
19817 pm_node_t *name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19819 if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) {
19820 pm_node_destroy(parser, name);
19822 pm_undef_node_append(undef, name);
19824 while (match1(parser, PM_TOKEN_COMMA)) {
19825 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
19826 parser_lex(parser);
19827 name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19829 if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) {
19830 pm_node_destroy(parser, name);
19834 pm_undef_node_append(undef, name);
19838 return (pm_node_t *) undef;
19840 case PM_TOKEN_KEYWORD_NOT: {
19841 parser_lex(parser);
19845 pm_node_t *receiver = NULL;
19850 if (!accepts_command_call && !match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19851 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES)) {
19852 pm_parser_err(parser, parser->
previous.
end, parser->
previous.
end + 1, PM_ERR_EXPECT_LPAREN_AFTER_NOT_LPAREN);
19854 accept1(parser, PM_TOKEN_NEWLINE);
19855 pm_parser_err_current(parser, PM_ERR_EXPECT_LPAREN_AFTER_NOT_OTHER);
19858 return (pm_node_t *) pm_missing_node_create(parser, parser->
current.start, parser->
current.end);
19861 accept1(parser, PM_TOKEN_NEWLINE);
19863 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19866 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19867 receiver = (pm_node_t *) pm_parentheses_node_create(parser, &lparen, NULL, &parser->
previous, 0);
19869 arguments.
opening_loc = PM_LOCATION_TOKEN_VALUE(&lparen);
19870 receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19873 accept1(parser, PM_TOKEN_NEWLINE);
19874 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19879 receiver = parse_expression(parser, PM_BINDING_POWER_NOT,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19882 return (pm_node_t *) pm_call_node_not_create(parser, receiver, &message, &arguments);
19884 case PM_TOKEN_KEYWORD_UNLESS: {
19885 size_t opening_newline_index = token_newline_index(parser);
19886 parser_lex(parser);
19888 return parse_conditional(parser,
PM_CONTEXT_UNLESS, opening_newline_index,
false, (uint16_t) (depth + 1));
19890 case PM_TOKEN_KEYWORD_MODULE: {
19891 pm_node_list_t current_block_exits = { 0 };
19892 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19894 size_t opening_newline_index = token_newline_index(parser);
19895 parser_lex(parser);
19898 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_MODULE_NAME, (uint16_t) (depth + 1));
19903 if (PM_NODE_TYPE_P(constant_path, PM_MISSING_NODE)) {
19904 pop_block_exits(parser, previous_block_exits);
19905 pm_node_list_free(¤t_block_exits);
19908 return (pm_node_t *) pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing);
19911 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
19914 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
19915 constant_path = (pm_node_t *) pm_constant_path_node_create(parser, constant_path, &double_colon, &parser->
previous);
19922 if (name.
type != PM_TOKEN_CONSTANT) {
19923 pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
19926 pm_parser_scope_push(parser,
true);
19927 accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE);
19928 pm_node_t *statements = NULL;
19930 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19931 pm_accepts_block_stack_push(parser,
true);
19932 statements = (pm_node_t *) parse_statements(parser,
PM_CONTEXT_MODULE, (uint16_t) (depth + 1));
19933 pm_accepts_block_stack_pop(parser);
19936 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
19937 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
19938 statements = (pm_node_t *) parse_rescues_implicit_begin(parser, opening_newline_index, &module_keyword, module_keyword.
start, (pm_statements_node_t *) statements, PM_RESCUES_MODULE, (uint16_t) (depth + 1));
19940 parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword,
false,
false);
19946 pm_parser_scope_pop(parser);
19947 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM);
19949 if (context_def_p(parser)) {
19950 pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
19953 pop_block_exits(parser, previous_block_exits);
19954 pm_node_list_free(¤t_block_exits);
19956 return (pm_node_t *) pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->
previous);
19958 case PM_TOKEN_KEYWORD_NIL:
19959 parser_lex(parser);
19960 return (pm_node_t *) pm_nil_node_create(parser, &parser->
previous);
19961 case PM_TOKEN_KEYWORD_REDO: {
19962 parser_lex(parser);
19964 pm_node_t *node = (pm_node_t *) pm_redo_node_create(parser, &parser->
previous);
19969 case PM_TOKEN_KEYWORD_RETRY: {
19970 parser_lex(parser);
19972 pm_node_t *node = (pm_node_t *) pm_retry_node_create(parser, &parser->
previous);
19973 parse_retry(parser, node);
19977 case PM_TOKEN_KEYWORD_SELF:
19978 parser_lex(parser);
19979 return (pm_node_t *) pm_self_node_create(parser, &parser->
previous);
19980 case PM_TOKEN_KEYWORD_TRUE:
19981 parser_lex(parser);
19982 return (pm_node_t *) pm_true_node_create(parser, &parser->
previous);
19983 case PM_TOKEN_KEYWORD_UNTIL: {
19984 size_t opening_newline_index = token_newline_index(parser);
19987 pm_do_loop_stack_push(parser,
true);
19989 parser_lex(parser);
19991 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
19993 pm_do_loop_stack_pop(parser);
19994 context_pop(parser);
19997 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
20000 do_keyword = not_provided(parser);
20001 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
20004 pm_statements_node_t *statements = NULL;
20005 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
20006 pm_accepts_block_stack_push(parser,
true);
20007 statements = parse_statements(parser,
PM_CONTEXT_UNTIL, (uint16_t) (depth + 1));
20008 pm_accepts_block_stack_pop(parser);
20009 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
20012 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
20013 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM);
20015 return (pm_node_t *) pm_until_node_create(parser, &keyword, &do_keyword, &parser->
previous, predicate, statements, 0);
20017 case PM_TOKEN_KEYWORD_WHILE: {
20018 size_t opening_newline_index = token_newline_index(parser);
20021 pm_do_loop_stack_push(parser,
true);
20023 parser_lex(parser);
20025 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
20027 pm_do_loop_stack_pop(parser);
20028 context_pop(parser);
20031 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
20034 do_keyword = not_provided(parser);
20035 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
20038 pm_statements_node_t *statements = NULL;
20039 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
20040 pm_accepts_block_stack_push(parser,
true);
20041 statements = parse_statements(parser,
PM_CONTEXT_WHILE, (uint16_t) (depth + 1));
20042 pm_accepts_block_stack_pop(parser);
20043 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
20046 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
20047 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM);
20049 return (pm_node_t *) pm_while_node_create(parser, &keyword, &do_keyword, &parser->
previous, predicate, statements, 0);
20051 case PM_TOKEN_PERCENT_LOWER_I: {
20052 parser_lex(parser);
20054 pm_array_node_t *array = pm_array_node_create(parser, &opening);
20056 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20057 accept1(parser, PM_TOKEN_WORDS_SEP);
20058 if (match1(parser, PM_TOKEN_STRING_END))
break;
20060 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20063 pm_array_node_elements_append(array, (pm_node_t *) pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing));
20066 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_LOWER_ELEMENT);
20070 if (match1(parser, PM_TOKEN_EOF)) {
20071 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
20074 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_LOWER_TERM);
20076 pm_array_node_close_set(array, &closing);
20078 return (pm_node_t *) array;
20080 case PM_TOKEN_PERCENT_UPPER_I: {
20081 parser_lex(parser);
20083 pm_array_node_t *array = pm_array_node_create(parser, &opening);
20087 pm_node_t *current = NULL;
20089 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20090 switch (parser->
current.type) {
20091 case PM_TOKEN_WORDS_SEP: {
20092 if (current == NULL) {
20098 pm_array_node_elements_append(array, current);
20102 parser_lex(parser);
20105 case PM_TOKEN_STRING_CONTENT: {
20109 if (current == NULL) {
20113 current = (pm_node_t *) pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing);
20114 parser_lex(parser);
20115 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
20119 pm_node_t *
string = (pm_node_t *) pm_string_node_create_current_string(parser, &opening, &parser->
current, &closing);
20120 parser_lex(parser);
20122 pm_interpolated_symbol_node_append((pm_interpolated_symbol_node_t *) current,
string);
20123 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20127 pm_symbol_node_t *cast = (pm_symbol_node_t *) current;
20131 pm_node_t *first_string = (pm_node_t *) pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &cast->
unescaped);
20132 pm_node_t *second_string = (pm_node_t *) pm_string_node_create_current_string(parser, &opening, &parser->
previous, &closing);
20133 parser_lex(parser);
20135 pm_interpolated_symbol_node_t *interpolated = pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
20136 pm_interpolated_symbol_node_append(interpolated, first_string);
20137 pm_interpolated_symbol_node_append(interpolated, second_string);
20140 current = (pm_node_t *) interpolated;
20142 assert(
false &&
"unreachable");
20147 case PM_TOKEN_EMBVAR: {
20148 bool start_location_set =
false;
20149 if (current == NULL) {
20155 current = (pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
20156 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20162 pm_interpolated_symbol_node_t *interpolated = pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
20164 current = (pm_node_t *) pm_symbol_node_to_string_node(parser, (pm_symbol_node_t *) current);
20165 pm_interpolated_symbol_node_append(interpolated, current);
20167 start_location_set =
true;
20168 current = (pm_node_t *) interpolated;
20174 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20175 pm_interpolated_symbol_node_append((pm_interpolated_symbol_node_t *) current, part);
20176 if (!start_location_set) {
20181 case PM_TOKEN_EMBEXPR_BEGIN: {
20182 bool start_location_set =
false;
20183 if (current == NULL) {
20189 current = (pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
20190 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20197 pm_interpolated_symbol_node_t *interpolated = pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
20199 current = (pm_node_t *) pm_symbol_node_to_string_node(parser, (pm_symbol_node_t *) current);
20200 pm_interpolated_symbol_node_append(interpolated, current);
20202 start_location_set =
true;
20203 current = (pm_node_t *) interpolated;
20204 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
20208 assert(
false &&
"unreachable");
20211 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20212 pm_interpolated_symbol_node_append((pm_interpolated_symbol_node_t *) current, part);
20213 if (!start_location_set) {
20219 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_UPPER_ELEMENT);
20220 parser_lex(parser);
20227 pm_array_node_elements_append(array, current);
20231 if (match1(parser, PM_TOKEN_EOF)) {
20232 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_UPPER_TERM);
20235 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_UPPER_TERM);
20237 pm_array_node_close_set(array, &closing);
20239 return (pm_node_t *) array;
20241 case PM_TOKEN_PERCENT_LOWER_W: {
20242 parser_lex(parser);
20244 pm_array_node_t *array = pm_array_node_create(parser, &opening);
20247 accept1(parser, PM_TOKEN_WORDS_SEP);
20249 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20250 accept1(parser, PM_TOKEN_WORDS_SEP);
20251 if (match1(parser, PM_TOKEN_STRING_END))
break;
20253 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20257 pm_node_t *
string = (pm_node_t *) pm_string_node_create_current_string(parser, &opening, &parser->
current, &closing);
20258 pm_array_node_elements_append(array,
string);
20261 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_LOWER_ELEMENT);
20265 if (match1(parser, PM_TOKEN_EOF)) {
20266 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_LOWER_TERM);
20269 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_LOWER_TERM);
20272 pm_array_node_close_set(array, &closing);
20273 return (pm_node_t *) array;
20275 case PM_TOKEN_PERCENT_UPPER_W: {
20276 parser_lex(parser);
20278 pm_array_node_t *array = pm_array_node_create(parser, &opening);
20282 pm_node_t *current = NULL;
20284 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20285 switch (parser->
current.type) {
20286 case PM_TOKEN_WORDS_SEP: {
20291 if (current == NULL) {
20298 pm_array_node_elements_append(array, current);
20302 parser_lex(parser);
20305 case PM_TOKEN_STRING_CONTENT: {
20309 pm_node_t *
string = (pm_node_t *) pm_string_node_create_current_string(parser, &opening, &parser->
current, &closing);
20310 pm_node_flag_set(
string, parse_unescaped_encoding(parser));
20311 parser_lex(parser);
20313 if (current == NULL) {
20319 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
20323 pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current,
string);
20324 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20329 pm_interpolated_string_node_t *interpolated = pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
20330 pm_interpolated_string_node_append(interpolated, current);
20331 pm_interpolated_string_node_append(interpolated,
string);
20332 current = (pm_node_t *) interpolated;
20334 assert(
false &&
"unreachable");
20339 case PM_TOKEN_EMBVAR: {
20340 if (current == NULL) {
20347 current = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
20348 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20355 pm_interpolated_string_node_t *interpolated = pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
20356 pm_interpolated_string_node_append(interpolated, current);
20357 current = (pm_node_t *) interpolated;
20364 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20365 pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current, part);
20368 case PM_TOKEN_EMBEXPR_BEGIN: {
20369 if (current == NULL) {
20376 current = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
20377 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20384 pm_interpolated_string_node_t *interpolated = pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
20385 pm_interpolated_string_node_append(interpolated, current);
20386 current = (pm_node_t *) interpolated;
20387 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
20392 assert(
false &&
"unreachable");
20395 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20396 pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current, part);
20400 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_UPPER_ELEMENT);
20401 parser_lex(parser);
20408 pm_array_node_elements_append(array, current);
20412 if (match1(parser, PM_TOKEN_EOF)) {
20413 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_UPPER_TERM);
20416 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_UPPER_TERM);
20419 pm_array_node_close_set(array, &closing);
20420 return (pm_node_t *) array;
20422 case PM_TOKEN_REGEXP_BEGIN: {
20424 parser_lex(parser);
20426 if (match1(parser, PM_TOKEN_REGEXP_END)) {
20431 .type = PM_TOKEN_STRING_CONTENT,
20436 parser_lex(parser);
20438 pm_node_t *node = (pm_node_t *) pm_regular_expression_node_create(parser, &opening, &content, &parser->
previous);
20439 pm_node_flag_set(node, PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING);
20444 pm_interpolated_regular_expression_node_t *interpolated;
20446 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20454 parser_lex(parser);
20459 if (accept1(parser, PM_TOKEN_REGEXP_END)) {
20460 pm_regular_expression_node_t *node = (pm_regular_expression_node_t *) pm_regular_expression_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped);
20466 if (!match1(parser, PM_TOKEN_EQUAL_TILDE)) {
20467 parse_regular_expression_errors(parser, node);
20470 pm_node_flag_set((pm_node_t *) node, parse_and_validate_regular_expression_encoding(parser, &unescaped, ascii_only, node->base.
flags));
20471 return (pm_node_t *) node;
20476 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20480 pm_node_t *part = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &parser->
previous, &closing, &unescaped);
20486 pm_node_flag_set(part, PM_STRING_FLAGS_FORCED_BINARY_ENCODING);
20489 pm_interpolated_regular_expression_node_append(interpolated, part);
20494 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20500 while (!match2(parser, PM_TOKEN_REGEXP_END, PM_TOKEN_EOF)) {
20501 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20502 pm_interpolated_regular_expression_node_append(interpolated, part);
20507 if (match1(parser, PM_TOKEN_EOF)) {
20508 pm_parser_err_token(parser, &opening, PM_ERR_REGEXP_TERM);
20511 expect1(parser, PM_TOKEN_REGEXP_END, PM_ERR_REGEXP_TERM);
20514 pm_interpolated_regular_expression_node_closing_set(parser, interpolated, &closing);
20515 return (pm_node_t *) interpolated;
20517 case PM_TOKEN_BACKTICK:
20518 case PM_TOKEN_PERCENT_LOWER_X: {
20519 parser_lex(parser);
20526 if (match1(parser, PM_TOKEN_STRING_END)) {
20531 .type = PM_TOKEN_STRING_CONTENT,
20536 parser_lex(parser);
20537 return (pm_node_t *) pm_xstring_node_create(parser, &opening, &content, &parser->
previous);
20540 pm_interpolated_x_string_node_t *node;
20542 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20549 parser_lex(parser);
20551 if (match1(parser, PM_TOKEN_STRING_END)) {
20552 pm_node_t *node = (pm_node_t *) pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
20553 pm_node_flag_set(node, parse_unescaped_encoding(parser));
20554 parser_lex(parser);
20560 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20565 pm_node_t *part = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &parser->
previous, &closing, &unescaped);
20566 pm_node_flag_set(part, parse_unescaped_encoding(parser));
20568 pm_interpolated_xstring_node_append(node, part);
20573 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20577 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20578 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20579 pm_interpolated_xstring_node_append(node, part);
20584 if (match1(parser, PM_TOKEN_EOF)) {
20585 pm_parser_err_token(parser, &opening, PM_ERR_XSTRING_TERM);
20588 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_XSTRING_TERM);
20590 pm_interpolated_xstring_node_closing_set(node, &closing);
20592 return (pm_node_t *) node;
20594 case PM_TOKEN_USTAR: {
20595 parser_lex(parser);
20600 if (binding_power != PM_BINDING_POWER_STATEMENT) {
20601 pm_parser_err_prefix(parser, diag_id);
20606 pm_node_t *name = NULL;
20608 if (token_begins_expression_p(parser->
current.type)) {
20609 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
20612 pm_node_t *splat = (pm_node_t *) pm_splat_node_create(parser, &
operator, name);
20614 if (match1(parser, PM_TOKEN_COMMA)) {
20615 return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
20617 return parse_target_validate(parser, splat,
true);
20620 case PM_TOKEN_BANG: {
20621 if (binding_power > PM_BINDING_POWER_UNARY) {
20622 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20625 parser_lex(parser);
20628 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));
20629 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"!");
20631 pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
20632 return (pm_node_t *) node;
20634 case PM_TOKEN_TILDE: {
20635 if (binding_power > PM_BINDING_POWER_UNARY) {
20636 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20638 parser_lex(parser);
20641 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20642 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"~");
20644 return (pm_node_t *) node;
20646 case PM_TOKEN_UMINUS: {
20647 if (binding_power > PM_BINDING_POWER_UNARY) {
20648 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20650 parser_lex(parser);
20653 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20654 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"-@");
20656 return (pm_node_t *) node;
20658 case PM_TOKEN_UMINUS_NUM: {
20659 parser_lex(parser);
20662 pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20664 if (accept1(parser, PM_TOKEN_STAR_STAR)) {
20666 pm_node_t *exponent = parse_expression(parser, pm_binding_powers[exponent_operator.
type].right,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
20667 node = (pm_node_t *) pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0);
20668 node = (pm_node_t *) pm_call_node_unary_create(parser, &
operator, node,
"-@");
20670 switch (PM_NODE_TYPE(node)) {
20671 case PM_INTEGER_NODE:
20672 case PM_FLOAT_NODE:
20673 case PM_RATIONAL_NODE:
20674 case PM_IMAGINARY_NODE:
20675 parse_negative_numeric(node);
20678 node = (pm_node_t *) pm_call_node_unary_create(parser, &
operator, node,
"-@");
20685 case PM_TOKEN_MINUS_GREATER: {
20689 size_t opening_newline_index = token_newline_index(parser);
20690 pm_accepts_block_stack_push(parser,
true);
20691 parser_lex(parser);
20694 pm_parser_scope_push(parser,
false);
20696 pm_block_parameters_node_t *block_parameters;
20698 switch (parser->
current.type) {
20699 case PM_TOKEN_PARENTHESIS_LEFT: {
20701 parser_lex(parser);
20703 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
20704 block_parameters = pm_block_parameters_node_create(parser, NULL, &opening);
20706 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
true, (uint16_t) (depth + 1));
20709 accept1(parser, PM_TOKEN_NEWLINE);
20710 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
20712 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
20715 case PM_CASE_PARAMETER: {
20716 pm_accepts_block_stack_push(parser,
false);
20718 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
false, (uint16_t) (depth + 1));
20719 pm_accepts_block_stack_pop(parser);
20723 block_parameters = NULL;
20729 pm_node_t *body = NULL;
20732 if (accept1(parser, PM_TOKEN_LAMBDA_BEGIN)) {
20735 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
20739 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20740 expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE);
20742 expect1(parser, PM_TOKEN_KEYWORD_DO, PM_ERR_LAMBDA_OPEN);
20745 if (!match3(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20746 pm_accepts_block_stack_push(parser,
true);
20748 pm_accepts_block_stack_pop(parser);
20751 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20752 assert(body == NULL || PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE));
20753 body = (pm_node_t *) parse_rescues_implicit_begin(parser, opening_newline_index, &
operator, opening.
start, (pm_statements_node_t *) body, PM_RESCUES_LAMBDA, (uint16_t) (depth + 1));
20755 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20758 expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END);
20762 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
20763 pm_node_t *parameters = parse_blocklike_parameters(parser, (pm_node_t *) block_parameters, &
operator, &parser->
previous);
20765 pm_parser_scope_pop(parser);
20766 pm_accepts_block_stack_pop(parser);
20768 return (pm_node_t *) pm_lambda_node_create(parser, &locals, &
operator, &opening, &parser->
previous, parameters, body);
20770 case PM_TOKEN_UPLUS: {
20771 if (binding_power > PM_BINDING_POWER_UNARY) {
20772 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20774 parser_lex(parser);
20777 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20778 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"+@");
20780 return (pm_node_t *) node;
20782 case PM_TOKEN_STRING_BEGIN:
20783 return parse_strings(parser, NULL, accepts_label, (uint16_t) (depth + 1));
20784 case PM_TOKEN_SYMBOL_BEGIN: {
20786 parser_lex(parser);
20788 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_END, (uint16_t) (depth + 1));
20799 if (diag_id != PM_ERR_CANNOT_PARSE_EXPRESSION) {
20800 pm_parser_err_prefix(parser, diag_id);
20806 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT,
pm_token_type_human(parser->
current.type), context_human(recoverable));
20807 }
else if (diag_id == PM_ERR_CANNOT_PARSE_EXPRESSION) {
20813 pm_parser_err_prefix(parser, diag_id);
20831parse_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) {
20832 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));
20836 if (match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
20840 parser_lex(parser);
20842 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));
20843 context_pop(parser);
20845 return (pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
20856parse_assignment_value_local(
pm_parser_t *parser,
const pm_node_t *node) {
20857 switch (PM_NODE_TYPE(node)) {
20858 case PM_BEGIN_NODE: {
20859 const pm_begin_node_t *cast = (
const pm_begin_node_t *) node;
20860 if (cast->
statements != NULL) parse_assignment_value_local(parser, (
const pm_node_t *) cast->
statements);
20863 case PM_LOCAL_VARIABLE_WRITE_NODE: {
20864 const pm_local_variable_write_node_t *cast = (
const pm_local_variable_write_node_t *) node;
20865 pm_locals_read(&pm_parser_scope_find(parser, cast->
depth)->locals, cast->
name);
20868 case PM_PARENTHESES_NODE: {
20869 const pm_parentheses_node_t *cast = (
const pm_parentheses_node_t *) node;
20870 if (cast->
body != NULL) parse_assignment_value_local(parser, cast->
body);
20873 case PM_STATEMENTS_NODE: {
20874 const pm_statements_node_t *cast = (
const pm_statements_node_t *) node;
20875 const pm_node_t *statement;
20878 parse_assignment_value_local(parser, statement);
20900parse_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) {
20901 bool permitted =
true;
20902 if (previous_binding_power != PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_USTAR)) permitted =
false;
20904 pm_node_t *value = parse_starred_expression(parser, binding_power, previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? accepts_command_call : previous_binding_power < PM_BINDING_POWER_MATCH, diag_id, (uint16_t) (depth + 1));
20905 if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE);
20907 parse_assignment_value_local(parser, value);
20908 bool single_value =
true;
20910 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && (PM_NODE_TYPE_P(value, PM_SPLAT_NODE) || match1(parser, PM_TOKEN_COMMA))) {
20911 single_value =
false;
20914 pm_array_node_t *array = pm_array_node_create(parser, &opening);
20916 pm_array_node_elements_append(array, value);
20917 value = (pm_node_t *) array;
20919 while (accept1(parser, PM_TOKEN_COMMA)) {
20920 pm_node_t *element = parse_starred_expression(parser, binding_power,
false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1));
20922 pm_array_node_elements_append(array, element);
20923 if (PM_NODE_TYPE_P(element, PM_MISSING_NODE))
break;
20925 parse_assignment_value_local(parser, element);
20931 if ((single_value || (binding_power == (PM_BINDING_POWER_MULTI_ASSIGNMENT + 1))) && match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
20935 parser_lex(parser);
20937 bool accepts_command_call_inner =
false;
20941 if (PM_NODE_TYPE_P(value, PM_CALL_NODE)) {
20942 pm_call_node_t *call_node = (pm_call_node_t *) value;
20944 accepts_command_call_inner =
true;
20948 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));
20949 context_pop(parser);
20951 return (pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
20965parse_call_operator_write(
pm_parser_t *parser, pm_call_node_t *call_node,
const pm_token_t *
operator) {
20967 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_ARGUMENTS);
20968 pm_node_destroy(parser, (pm_node_t *) call_node->
arguments);
20972 if (call_node->
block != NULL) {
20973 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_BLOCK);
20974 pm_node_destroy(parser, (pm_node_t *) call_node->
block);
20975 call_node->
block = NULL;
21004static inline const uint8_t *
21005pm_named_capture_escape_hex(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
21008 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
21009 uint8_t value = escape_hexadecimal_digit(*cursor);
21012 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
21013 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(*cursor));
21017 pm_buffer_append_byte(unescaped, value);
21019 pm_buffer_append_string(unescaped,
"\\x", 2);
21025static inline const uint8_t *
21026pm_named_capture_escape_octal(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
21027 uint8_t value = (uint8_t) (*cursor -
'0');
21030 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
21031 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
21034 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
21035 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
21040 pm_buffer_append_byte(unescaped, value);
21044static inline const uint8_t *
21045pm_named_capture_escape_unicode(
pm_parser_t *parser,
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
21046 const uint8_t *start = cursor - 1;
21049 if (cursor >= end) {
21050 pm_buffer_append_string(unescaped,
"\\u", 2);
21054 if (*cursor !=
'{') {
21055 size_t length = pm_strspn_hexadecimal_digit(cursor, MIN(end - cursor, 4));
21056 uint32_t value = escape_unicode(parser, cursor, length);
21058 if (!pm_buffer_append_unicode_codepoint(unescaped, value)) {
21059 pm_buffer_append_string(unescaped, (
const char *) start, (
size_t) ((cursor + length) - start));
21062 return cursor + length;
21067 while (cursor < end && *cursor ==
' ') cursor++;
21069 if (cursor >= end)
break;
21070 if (*cursor ==
'}') {
21075 size_t length = pm_strspn_hexadecimal_digit(cursor, end - cursor);
21076 uint32_t value = escape_unicode(parser, cursor, length);
21078 (void) pm_buffer_append_unicode_codepoint(unescaped, value);
21086pm_named_capture_escape(
pm_parser_t *parser,
pm_buffer_t *unescaped,
const uint8_t *source,
const size_t length,
const uint8_t *cursor) {
21087 const uint8_t *end = source + length;
21088 pm_buffer_append_string(unescaped, (
const char *) source, (
size_t) (cursor - source));
21091 if (++cursor >= end) {
21092 pm_buffer_append_byte(unescaped,
'\\');
21098 cursor = pm_named_capture_escape_hex(unescaped, cursor, end);
21100 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
21101 cursor = pm_named_capture_escape_octal(unescaped, cursor, end);
21104 cursor = pm_named_capture_escape_unicode(parser, unescaped, cursor, end);
21107 pm_buffer_append_byte(unescaped,
'\\');
21111 const uint8_t *next_cursor = pm_memchr(cursor,
'\\', (
size_t) (end - cursor), parser->
encoding_changed, parser->
encoding);
21112 if (next_cursor == NULL)
break;
21114 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (next_cursor - cursor));
21115 cursor = next_cursor;
21118 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (end - cursor));
21126parse_regular_expression_named_capture(
const pm_string_t *capture,
void *data) {
21130 pm_call_node_t *call = callback_data->
call;
21133 const uint8_t *source = pm_string_source(capture);
21134 size_t length = pm_string_length(capture);
21147 pm_named_capture_escape(parser, &unescaped, source, length, cursor);
21148 source = (
const uint8_t *) pm_buffer_value(&unescaped);
21149 length = pm_buffer_length(&unescaped);
21157 if (!pm_slice_is_valid_local(parser, source, source + length)) {
21158 pm_buffer_free(&unescaped);
21162 if (callback_data->
shared) {
21165 location = (
pm_location_t) { .start = source, .end = source + length };
21166 name = pm_parser_constant_id_location(parser, location.
start, location.
end);
21172 void *memory =
xmalloc(length);
21173 if (memory == NULL) abort();
21175 memcpy(memory, source, length);
21176 name = pm_parser_constant_id_owned(parser, (uint8_t *) memory, length);
21181 if (name != 0 && !pm_constant_id_list_includes(names, name)) {
21182 pm_constant_id_list_append(names, name);
21185 if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
21188 if (pm_local_is_keyword((
const char *) source, length)) {
21189 pm_buffer_free(&unescaped);
21195 pm_parser_local_add(parser, name, location.
start, location.
end, 0);
21200 if (callback_data->
match == NULL) {
21201 callback_data->
match = pm_match_write_node_create(parser, call);
21206 pm_node_t *target = (pm_node_t *) pm_local_variable_target_node_create(parser, &location, name, depth == -1 ? 0 : (uint32_t) depth);
21207 pm_node_list_append(&callback_data->
match->
targets, target);
21210 pm_buffer_free(&unescaped);
21218parse_regular_expression_named_captures(
pm_parser_t *parser,
const pm_string_t *content, pm_call_node_t *call,
bool extended_mode) {
21223 .shared = content->
type == PM_STRING_SHARED
21230 .shared = content->
type == PM_STRING_SHARED
21233 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);
21234 pm_constant_id_list_free(&callback_data.
names);
21236 if (callback_data.
match != NULL) {
21237 return (pm_node_t *) callback_data.
match;
21239 return (pm_node_t *) call;
21243static inline pm_node_t *
21244parse_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) {
21247 switch (token.type) {
21248 case PM_TOKEN_EQUAL: {
21249 switch (PM_NODE_TYPE(node)) {
21250 case PM_CALL_NODE: {
21255 pm_call_node_t *call_node = (pm_call_node_t *) node;
21256 if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21261 case PM_CASE_WRITABLE: {
21265 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
21269 parser_lex(parser);
21270 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));
21272 if (PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) && previous_binding_power != PM_BINDING_POWER_STATEMENT) {
21273 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_MULTI_WRITE);
21276 return parse_write(parser, node, &token, value);
21278 case PM_SPLAT_NODE: {
21279 pm_multi_target_node_t *multi_target = pm_multi_target_node_create(parser);
21280 pm_multi_target_node_targets_append(parser, multi_target, node);
21282 parser_lex(parser);
21283 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));
21284 return parse_write(parser, (pm_node_t *) multi_target, &token, value);
21286 case PM_SOURCE_ENCODING_NODE:
21287 case PM_FALSE_NODE:
21288 case PM_SOURCE_FILE_NODE:
21289 case PM_SOURCE_LINE_NODE:
21292 case PM_TRUE_NODE: {
21295 parser_lex(parser);
21296 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));
21297 return parse_unwriteable_write(parser, node, &token, value);
21303 parser_lex(parser);
21304 pm_parser_err_token(parser, &token, PM_ERR_EXPRESSION_NOT_WRITABLE);
21308 case PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL: {
21309 switch (PM_NODE_TYPE(node)) {
21310 case PM_BACK_REFERENCE_READ_NODE:
21311 case PM_NUMBERED_REFERENCE_READ_NODE:
21312 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21314 case PM_GLOBAL_VARIABLE_READ_NODE: {
21315 parser_lex(parser);
21317 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));
21318 pm_node_t *result = (pm_node_t *) pm_global_variable_and_write_node_create(parser, node, &token, value);
21320 pm_node_destroy(parser, node);
21323 case PM_CLASS_VARIABLE_READ_NODE: {
21324 parser_lex(parser);
21326 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));
21327 pm_node_t *result = (pm_node_t *) pm_class_variable_and_write_node_create(parser, (pm_class_variable_read_node_t *) node, &token, value);
21329 pm_node_destroy(parser, node);
21332 case PM_CONSTANT_PATH_NODE: {
21333 parser_lex(parser);
21335 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));
21336 pm_node_t *write = (pm_node_t *) pm_constant_path_and_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value);
21338 return parse_shareable_constant_write(parser, write);
21340 case PM_CONSTANT_READ_NODE: {
21341 parser_lex(parser);
21343 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));
21344 pm_node_t *write = (pm_node_t *) pm_constant_and_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value);
21346 pm_node_destroy(parser, node);
21347 return parse_shareable_constant_write(parser, write);
21349 case PM_INSTANCE_VARIABLE_READ_NODE: {
21350 parser_lex(parser);
21352 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));
21353 pm_node_t *result = (pm_node_t *) pm_instance_variable_and_write_node_create(parser, (pm_instance_variable_read_node_t *) node, &token, value);
21355 pm_node_destroy(parser, node);
21358 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21360 parser_lex(parser);
21362 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));
21363 pm_node_t *result = (pm_node_t *) pm_local_variable_and_write_node_create(parser, node, &token, value, name, 0);
21365 parse_target_implicit_parameter(parser, node);
21366 pm_node_destroy(parser, node);
21369 case PM_LOCAL_VARIABLE_READ_NODE: {
21372 parse_target_implicit_parameter(parser, node);
21375 pm_local_variable_read_node_t *cast = (pm_local_variable_read_node_t *) node;
21376 parser_lex(parser);
21378 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));
21379 pm_node_t *result = (pm_node_t *) pm_local_variable_and_write_node_create(parser, node, &token, value, cast->
name, cast->
depth);
21381 pm_node_destroy(parser, node);
21384 case PM_CALL_NODE: {
21385 pm_call_node_t *cast = (pm_call_node_t *) node;
21390 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21392 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21395 parser_lex(parser);
21397 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));
21398 pm_node_t *result = (pm_node_t *) pm_local_variable_and_write_node_create(parser, (pm_node_t *) cast, &token, value, constant_id, 0);
21400 pm_node_destroy(parser, (pm_node_t *) cast);
21406 parser_lex(parser);
21411 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21412 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21413 return (pm_node_t *) pm_index_and_write_node_create(parser, cast, &token, value);
21417 if (pm_call_node_writable_p(parser, cast)) {
21418 parse_write_name(parser, &cast->name);
21420 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21423 parse_call_operator_write(parser, cast, &token);
21424 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));
21425 return (pm_node_t *) pm_call_and_write_node_create(parser, cast, &token, value);
21427 case PM_MULTI_WRITE_NODE: {
21428 parser_lex(parser);
21429 pm_parser_err_token(parser, &token, PM_ERR_AMPAMPEQ_MULTI_ASSIGN);
21433 parser_lex(parser);
21438 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
21442 case PM_TOKEN_PIPE_PIPE_EQUAL: {
21443 switch (PM_NODE_TYPE(node)) {
21444 case PM_BACK_REFERENCE_READ_NODE:
21445 case PM_NUMBERED_REFERENCE_READ_NODE:
21446 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21448 case PM_GLOBAL_VARIABLE_READ_NODE: {
21449 parser_lex(parser);
21451 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));
21452 pm_node_t *result = (pm_node_t *) pm_global_variable_or_write_node_create(parser, node, &token, value);
21454 pm_node_destroy(parser, node);
21457 case PM_CLASS_VARIABLE_READ_NODE: {
21458 parser_lex(parser);
21460 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));
21461 pm_node_t *result = (pm_node_t *) pm_class_variable_or_write_node_create(parser, (pm_class_variable_read_node_t *) node, &token, value);
21463 pm_node_destroy(parser, node);
21466 case PM_CONSTANT_PATH_NODE: {
21467 parser_lex(parser);
21469 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));
21470 pm_node_t *write = (pm_node_t *) pm_constant_path_or_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value);
21472 return parse_shareable_constant_write(parser, write);
21474 case PM_CONSTANT_READ_NODE: {
21475 parser_lex(parser);
21477 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));
21478 pm_node_t *write = (pm_node_t *) pm_constant_or_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value);
21480 pm_node_destroy(parser, node);
21481 return parse_shareable_constant_write(parser, write);
21483 case PM_INSTANCE_VARIABLE_READ_NODE: {
21484 parser_lex(parser);
21486 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));
21487 pm_node_t *result = (pm_node_t *) pm_instance_variable_or_write_node_create(parser, (pm_instance_variable_read_node_t *) node, &token, value);
21489 pm_node_destroy(parser, node);
21492 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21494 parser_lex(parser);
21496 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));
21497 pm_node_t *result = (pm_node_t *) pm_local_variable_or_write_node_create(parser, node, &token, value, name, 0);
21499 parse_target_implicit_parameter(parser, node);
21500 pm_node_destroy(parser, node);
21503 case PM_LOCAL_VARIABLE_READ_NODE: {
21506 parse_target_implicit_parameter(parser, node);
21509 pm_local_variable_read_node_t *cast = (pm_local_variable_read_node_t *) node;
21510 parser_lex(parser);
21512 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));
21513 pm_node_t *result = (pm_node_t *) pm_local_variable_or_write_node_create(parser, node, &token, value, cast->
name, cast->
depth);
21515 pm_node_destroy(parser, node);
21518 case PM_CALL_NODE: {
21519 pm_call_node_t *cast = (pm_call_node_t *) node;
21524 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21526 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21529 parser_lex(parser);
21531 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));
21532 pm_node_t *result = (pm_node_t *) pm_local_variable_or_write_node_create(parser, (pm_node_t *) cast, &token, value, constant_id, 0);
21534 pm_node_destroy(parser, (pm_node_t *) cast);
21540 parser_lex(parser);
21545 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21546 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21547 return (pm_node_t *) pm_index_or_write_node_create(parser, cast, &token, value);
21551 if (pm_call_node_writable_p(parser, cast)) {
21552 parse_write_name(parser, &cast->name);
21554 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21557 parse_call_operator_write(parser, cast, &token);
21558 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));
21559 return (pm_node_t *) pm_call_or_write_node_create(parser, cast, &token, value);
21561 case PM_MULTI_WRITE_NODE: {
21562 parser_lex(parser);
21563 pm_parser_err_token(parser, &token, PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN);
21567 parser_lex(parser);
21572 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
21576 case PM_TOKEN_AMPERSAND_EQUAL:
21577 case PM_TOKEN_CARET_EQUAL:
21578 case PM_TOKEN_GREATER_GREATER_EQUAL:
21579 case PM_TOKEN_LESS_LESS_EQUAL:
21580 case PM_TOKEN_MINUS_EQUAL:
21581 case PM_TOKEN_PERCENT_EQUAL:
21582 case PM_TOKEN_PIPE_EQUAL:
21583 case PM_TOKEN_PLUS_EQUAL:
21584 case PM_TOKEN_SLASH_EQUAL:
21585 case PM_TOKEN_STAR_EQUAL:
21586 case PM_TOKEN_STAR_STAR_EQUAL: {
21587 switch (PM_NODE_TYPE(node)) {
21588 case PM_BACK_REFERENCE_READ_NODE:
21589 case PM_NUMBERED_REFERENCE_READ_NODE:
21590 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21592 case PM_GLOBAL_VARIABLE_READ_NODE: {
21593 parser_lex(parser);
21595 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));
21596 pm_node_t *result = (pm_node_t *) pm_global_variable_operator_write_node_create(parser, node, &token, value);
21598 pm_node_destroy(parser, node);
21601 case PM_CLASS_VARIABLE_READ_NODE: {
21602 parser_lex(parser);
21604 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));
21605 pm_node_t *result = (pm_node_t *) pm_class_variable_operator_write_node_create(parser, (pm_class_variable_read_node_t *) node, &token, value);
21607 pm_node_destroy(parser, node);
21610 case PM_CONSTANT_PATH_NODE: {
21611 parser_lex(parser);
21613 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));
21614 pm_node_t *write = (pm_node_t *) pm_constant_path_operator_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value);
21616 return parse_shareable_constant_write(parser, write);
21618 case PM_CONSTANT_READ_NODE: {
21619 parser_lex(parser);
21621 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21622 pm_node_t *write = (pm_node_t *) pm_constant_operator_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value);
21624 pm_node_destroy(parser, node);
21625 return parse_shareable_constant_write(parser, write);
21627 case PM_INSTANCE_VARIABLE_READ_NODE: {
21628 parser_lex(parser);
21630 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));
21631 pm_node_t *result = (pm_node_t *) pm_instance_variable_operator_write_node_create(parser, (pm_instance_variable_read_node_t *) node, &token, value);
21633 pm_node_destroy(parser, node);
21636 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21638 parser_lex(parser);
21640 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));
21641 pm_node_t *result = (pm_node_t *) pm_local_variable_operator_write_node_create(parser, node, &token, value, name, 0);
21643 parse_target_implicit_parameter(parser, node);
21644 pm_node_destroy(parser, node);
21647 case PM_LOCAL_VARIABLE_READ_NODE: {
21650 parse_target_implicit_parameter(parser, node);
21653 pm_local_variable_read_node_t *cast = (pm_local_variable_read_node_t *) node;
21654 parser_lex(parser);
21656 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));
21657 pm_node_t *result = (pm_node_t *) pm_local_variable_operator_write_node_create(parser, node, &token, value, cast->
name, cast->
depth);
21659 pm_node_destroy(parser, node);
21662 case PM_CALL_NODE: {
21663 parser_lex(parser);
21664 pm_call_node_t *cast = (pm_call_node_t *) node;
21669 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21671 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21674 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));
21675 pm_node_t *result = (pm_node_t *) pm_local_variable_operator_write_node_create(parser, (pm_node_t *) cast, &token, value, constant_id, 0);
21677 pm_node_destroy(parser, (pm_node_t *) cast);
21684 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21685 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));
21686 return (pm_node_t *) pm_index_operator_write_node_create(parser, cast, &token, value);
21690 if (pm_call_node_writable_p(parser, cast)) {
21691 parse_write_name(parser, &cast->name);
21693 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21696 parse_call_operator_write(parser, cast, &token);
21697 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21698 return (pm_node_t *) pm_call_operator_write_node_create(parser, cast, &token, value);
21700 case PM_MULTI_WRITE_NODE: {
21701 parser_lex(parser);
21702 pm_parser_err_token(parser, &token, PM_ERR_OPERATOR_MULTI_ASSIGN);
21706 parser_lex(parser);
21715 case PM_TOKEN_AMPERSAND_AMPERSAND:
21716 case PM_TOKEN_KEYWORD_AND: {
21717 parser_lex(parser);
21719 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));
21720 return (pm_node_t *) pm_and_node_create(parser, node, &token, right);
21722 case PM_TOKEN_KEYWORD_OR:
21723 case PM_TOKEN_PIPE_PIPE: {
21724 parser_lex(parser);
21726 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));
21727 return (pm_node_t *) pm_or_node_create(parser, node, &token, right);
21729 case PM_TOKEN_EQUAL_TILDE: {
21737 parser_lex(parser);
21738 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21741 pm_call_node_t *call = pm_call_node_binary_create(parser, node, &token, argument, 0);
21742 pm_node_t *result = (pm_node_t *) call;
21747 if (PM_NODE_TYPE_P(node, PM_INTERPOLATED_REGULAR_EXPRESSION_NODE)) {
21752 pm_node_list_t *parts = &((pm_interpolated_regular_expression_node_t *) node)->parts;
21754 bool interpolated =
false;
21755 size_t total_length = 0;
21759 if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
21760 total_length += pm_string_length(&((pm_string_node_t *) part)->unescaped);
21762 interpolated =
true;
21767 if (!interpolated && total_length > 0) {
21768 void *memory =
xmalloc(total_length);
21769 if (!memory) abort();
21771 uint8_t *cursor = memory;
21773 pm_string_t *unescaped = &((pm_string_node_t *) part)->unescaped;
21774 size_t length = pm_string_length(unescaped);
21776 memcpy(cursor, pm_string_source(unescaped), length);
21781 pm_string_owned_init(&owned, (uint8_t *) memory, total_length);
21783 result = parse_regular_expression_named_captures(parser, &owned, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
21784 pm_string_free(&owned);
21786 }
else if (PM_NODE_TYPE_P(node, PM_REGULAR_EXPRESSION_NODE)) {
21789 const pm_string_t *content = &((pm_regular_expression_node_t *) node)->unescaped;
21790 result = parse_regular_expression_named_captures(parser, content, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
21795 case PM_TOKEN_UAMPERSAND:
21796 case PM_TOKEN_USTAR:
21797 case PM_TOKEN_USTAR_STAR:
21800 case PM_TOKEN_BANG_EQUAL:
21801 case PM_TOKEN_BANG_TILDE:
21802 case PM_TOKEN_EQUAL_EQUAL:
21803 case PM_TOKEN_EQUAL_EQUAL_EQUAL:
21804 case PM_TOKEN_LESS_EQUAL_GREATER:
21805 case PM_TOKEN_CARET:
21806 case PM_TOKEN_PIPE:
21807 case PM_TOKEN_AMPERSAND:
21808 case PM_TOKEN_GREATER_GREATER:
21809 case PM_TOKEN_LESS_LESS:
21810 case PM_TOKEN_MINUS:
21811 case PM_TOKEN_PLUS:
21812 case PM_TOKEN_PERCENT:
21813 case PM_TOKEN_SLASH:
21814 case PM_TOKEN_STAR:
21815 case PM_TOKEN_STAR_STAR: {
21816 parser_lex(parser);
21818 switch (PM_NODE_TYPE(node)) {
21819 case PM_RESCUE_MODIFIER_NODE: {
21820 pm_rescue_modifier_node_t *cast = (pm_rescue_modifier_node_t *) node;
21822 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21826 case PM_AND_NODE: {
21827 pm_and_node_t *cast = (pm_and_node_t *) node;
21828 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21829 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21834 pm_or_node_t *cast = (pm_or_node_t *) node;
21835 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21836 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21844 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21845 return (pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument, 0);
21847 case PM_TOKEN_GREATER:
21848 case PM_TOKEN_GREATER_EQUAL:
21849 case PM_TOKEN_LESS:
21850 case PM_TOKEN_LESS_EQUAL: {
21851 if (PM_NODE_TYPE_P(node, PM_CALL_NODE) && PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_COMPARISON)) {
21852 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_COMPARISON_AFTER_COMPARISON);
21855 parser_lex(parser);
21856 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21857 return (pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON);
21859 case PM_TOKEN_AMPERSAND_DOT:
21860 case PM_TOKEN_DOT: {
21861 parser_lex(parser);
21866 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
21867 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21868 return (pm_node_t *) pm_call_node_shorthand_create(parser, node, &
operator, &arguments);
21871 switch (PM_NODE_TYPE(node)) {
21872 case PM_RESCUE_MODIFIER_NODE: {
21873 pm_rescue_modifier_node_t *cast = (pm_rescue_modifier_node_t *) node;
21875 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21879 case PM_AND_NODE: {
21880 pm_and_node_t *cast = (pm_and_node_t *) node;
21881 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21882 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21887 pm_or_node_t *cast = (pm_or_node_t *) node;
21888 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21889 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21899 switch (parser->
current.type) {
21900 case PM_CASE_OPERATOR:
21901 case PM_CASE_KEYWORD:
21902 case PM_TOKEN_CONSTANT:
21903 case PM_TOKEN_IDENTIFIER:
21904 case PM_TOKEN_METHOD_NAME: {
21905 parser_lex(parser);
21915 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21916 pm_call_node_t *call = pm_call_node_call_create(parser, node, &
operator, &message, &arguments);
21919 (previous_binding_power == PM_BINDING_POWER_STATEMENT) &&
21922 match1(parser, PM_TOKEN_COMMA)
21924 return parse_targets_validate(parser, (pm_node_t *) call, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21926 return (pm_node_t *) call;
21929 case PM_TOKEN_DOT_DOT:
21930 case PM_TOKEN_DOT_DOT_DOT: {
21931 parser_lex(parser);
21933 pm_node_t *right = NULL;
21934 if (token_begins_expression_p(parser->
current.type)) {
21935 right = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21938 return (pm_node_t *) pm_range_node_create(parser, node, &token, right);
21940 case PM_TOKEN_KEYWORD_IF_MODIFIER: {
21942 parser_lex(parser);
21944 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
21945 return (pm_node_t *) pm_if_node_modifier_create(parser, node, &keyword, predicate);
21947 case PM_TOKEN_KEYWORD_UNLESS_MODIFIER: {
21949 parser_lex(parser);
21951 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
21952 return (pm_node_t *) pm_unless_node_modifier_create(parser, node, &keyword, predicate);
21954 case PM_TOKEN_KEYWORD_UNTIL_MODIFIER: {
21955 parser_lex(parser);
21956 pm_statements_node_t *statements = pm_statements_node_create(parser);
21957 pm_statements_node_body_append(parser, statements, node,
true);
21959 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
21960 return (pm_node_t *) pm_until_node_modifier_create(parser, &token, predicate, statements, PM_NODE_TYPE_P(node, PM_BEGIN_NODE) ? PM_LOOP_FLAGS_BEGIN_MODIFIER : 0);
21962 case PM_TOKEN_KEYWORD_WHILE_MODIFIER: {
21963 parser_lex(parser);
21964 pm_statements_node_t *statements = pm_statements_node_create(parser);
21965 pm_statements_node_body_append(parser, statements, node,
true);
21967 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
21968 return (pm_node_t *) pm_while_node_modifier_create(parser, &token, predicate, statements, PM_NODE_TYPE_P(node, PM_BEGIN_NODE) ? PM_LOOP_FLAGS_BEGIN_MODIFIER : 0);
21970 case PM_TOKEN_QUESTION_MARK: {
21972 pm_node_list_t current_block_exits = { 0 };
21973 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
21976 parser_lex(parser);
21978 pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_TRUE, (uint16_t) (depth + 1));
21988 pm_node_t *false_expression = (pm_node_t *) pm_missing_node_create(parser, colon.
start, colon.
end);
21990 context_pop(parser);
21991 pop_block_exits(parser, previous_block_exits);
21992 pm_node_list_free(¤t_block_exits);
21994 return (pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
21997 accept1(parser, PM_TOKEN_NEWLINE);
21998 expect1(parser, PM_TOKEN_COLON, PM_ERR_TERNARY_COLON);
22001 pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_FALSE, (uint16_t) (depth + 1));
22003 context_pop(parser);
22004 pop_block_exits(parser, previous_block_exits);
22005 pm_node_list_free(¤t_block_exits);
22007 return (pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
22009 case PM_TOKEN_COLON_COLON: {
22010 parser_lex(parser);
22013 switch (parser->
current.type) {
22014 case PM_TOKEN_CONSTANT: {
22015 parser_lex(parser);
22019 (parser->
current.type == PM_TOKEN_PARENTHESIS_LEFT) ||
22020 (accepts_command_call && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)))
22031 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
22032 path = (pm_node_t *) pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
22035 path = (pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
22039 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
22040 return parse_targets_validate(parser, path, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22045 case PM_CASE_OPERATOR:
22046 case PM_CASE_KEYWORD:
22047 case PM_TOKEN_IDENTIFIER:
22048 case PM_TOKEN_METHOD_NAME: {
22049 parser_lex(parser);
22055 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
22056 pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
22059 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
22060 return parse_targets_validate(parser, (pm_node_t *) call, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22063 return (pm_node_t *) call;
22065 case PM_TOKEN_PARENTHESIS_LEFT: {
22069 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
22071 return (pm_node_t *) pm_call_node_shorthand_create(parser, node, &delimiter, &arguments);
22074 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
22075 return (pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
22079 case PM_TOKEN_KEYWORD_RESCUE_MODIFIER: {
22081 parser_lex(parser);
22082 accept1(parser, PM_TOKEN_NEWLINE);
22084 pm_node_t *value = parse_expression(parser, binding_power,
true,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
22085 context_pop(parser);
22087 return (pm_node_t *) pm_rescue_modifier_node_create(parser, node, &token, value);
22089 case PM_TOKEN_BRACKET_LEFT: {
22090 parser_lex(parser);
22095 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
22096 pm_accepts_block_stack_push(parser,
true);
22097 parse_arguments(parser, &arguments,
false, PM_TOKEN_BRACKET_RIGHT, (uint16_t) (depth + 1));
22098 pm_accepts_block_stack_pop(parser);
22099 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_EXPECT_RBRACKET);
22106 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
22107 pm_call_node_t *aref = pm_call_node_aref_create(parser, node, &arguments);
22108 return parse_targets_validate(parser, (pm_node_t *) aref, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22114 pm_block_node_t *block = NULL;
22115 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
22116 block = parse_block(parser, (uint16_t) (depth + 1));
22117 pm_arguments_validate_block(parser, &arguments, block);
22118 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
22119 block = parse_block(parser, (uint16_t) (depth + 1));
22122 if (block != NULL) {
22123 if (arguments.
block != NULL) {
22124 pm_parser_err_node(parser, (pm_node_t *) block, PM_ERR_ARGUMENT_AFTER_BLOCK);
22126 arguments.
arguments = pm_arguments_node_create(parser);
22128 pm_arguments_node_arguments_append(arguments.
arguments, arguments.
block);
22131 arguments.
block = (pm_node_t *) block;
22134 return (pm_node_t *) pm_call_node_aref_create(parser, node, &arguments);
22136 case PM_TOKEN_KEYWORD_IN: {
22142 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
22143 parser_lex(parser);
22146 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));
22149 pm_constant_id_list_free(&captures);
22151 return (pm_node_t *) pm_match_predicate_node_create(parser, node, pattern, &
operator);
22153 case PM_TOKEN_EQUAL_GREATER: {
22159 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
22160 parser_lex(parser);
22163 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));
22166 pm_constant_id_list_free(&captures);
22168 return (pm_node_t *) pm_match_required_node_create(parser, node, pattern, &
operator);
22171 assert(
false &&
"unreachable");
22176#undef PM_PARSE_PATTERN_SINGLE
22177#undef PM_PARSE_PATTERN_TOP
22178#undef PM_PARSE_PATTERN_MULTI
22185pm_call_node_command_p(
const pm_call_node_t *node) {
22188 (node->
block == NULL || PM_NODE_TYPE_P(node->
block, PM_BLOCK_ARGUMENT_NODE)) &&
22202parse_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) {
22204 pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
22205 return (pm_node_t *) pm_missing_node_create(parser, parser->
current.start, parser->
current.end);
22208 pm_node_t *node = parse_expression_prefix(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
22210 switch (PM_NODE_TYPE(node)) {
22211 case PM_MISSING_NODE:
22215 case PM_PRE_EXECUTION_NODE:
22216 case PM_POST_EXECUTION_NODE:
22217 case PM_ALIAS_GLOBAL_VARIABLE_NODE:
22218 case PM_ALIAS_METHOD_NODE:
22219 case PM_MULTI_WRITE_NODE:
22220 case PM_UNDEF_NODE:
22223 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
22233 if ((pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_COMPOSITION) && pm_call_node_command_p((pm_call_node_t *) node)) {
22237 case PM_SYMBOL_NODE:
22241 if (pm_symbol_node_label_p(node)) {
22252 pm_token_type_t current_token_type;
22255 current_token_type = parser->
current.type,
22256 current_binding_powers = pm_binding_powers[current_token_type],
22257 binding_power <= current_binding_powers.
left &&
22258 current_binding_powers.
binary
22260 node = parse_expression_infix(parser, node, binding_power, current_binding_powers.
right, accepts_command_call, (uint16_t) (depth + 1));
22268 switch (PM_NODE_TYPE(node)) {
22269 case PM_MULTI_WRITE_NODE:
22272 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
22276 case PM_CLASS_VARIABLE_WRITE_NODE:
22277 case PM_CONSTANT_PATH_WRITE_NODE:
22278 case PM_CONSTANT_WRITE_NODE:
22279 case PM_GLOBAL_VARIABLE_WRITE_NODE:
22280 case PM_INSTANCE_VARIABLE_WRITE_NODE:
22281 case PM_LOCAL_VARIABLE_WRITE_NODE:
22284 if (PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
22292 if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
22302 if (current_binding_powers.
nonassoc) {
22305 if (match1(parser, current_token_type)) {
22317 if (PM_NODE_TYPE_P(node, PM_RANGE_NODE) && ((pm_range_node_t *) node)->right == NULL) {
22318 if (match4(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_DOT, PM_TOKEN_AMPERSAND_DOT)) {
22323 if (PM_BINDING_POWER_TERM <= pm_binding_powers[parser->
current.type].left) {
22326 }
else if (current_binding_powers.
left <= pm_binding_powers[parser->
current.type].left) {
22331 if (accepts_command_call) {
22340 switch (node->
type) {
22341 case PM_CALL_NODE: {
22342 pm_call_node_t *cast = (pm_call_node_t *)node;
22355 cast->
block == NULL &&
22365 cast->
block != NULL && PM_NODE_TYPE_P(cast->
block, PM_BLOCK_NODE)
22368 accepts_command_call =
false;
22373 case PM_CONSTANT_PATH_NODE:
22376 accepts_command_call =
false;
22389static pm_statements_node_t *
22390wrap_statements(
pm_parser_t *parser, pm_statements_node_t *statements) {
22391 if (PM_PARSER_COMMAND_LINE_OPTION_P(parser)) {
22392 if (statements == NULL) {
22393 statements = pm_statements_node_create(parser);
22396 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
22397 pm_arguments_node_arguments_append(
22399 (pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2))
22402 pm_statements_node_body_append(parser, statements, (pm_node_t *) pm_call_node_fcall_synthesized_create(
22405 pm_parser_constant_id_constant(parser,
"print", 5)
22409 if (PM_PARSER_COMMAND_LINE_OPTION_N(parser)) {
22410 if (PM_PARSER_COMMAND_LINE_OPTION_A(parser)) {
22411 if (statements == NULL) {
22412 statements = pm_statements_node_create(parser);
22415 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
22416 pm_arguments_node_arguments_append(
22418 (pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$;", 2))
22421 pm_global_variable_read_node_t *receiver = pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2));
22422 pm_call_node_t *call = pm_call_node_call_synthesized_create(parser, (pm_node_t *) receiver,
"split", arguments);
22424 pm_global_variable_write_node_t *write = pm_global_variable_write_node_synthesized_create(
22426 pm_parser_constant_id_constant(parser,
"$F", 2),
22430 pm_statements_node_body_prepend(statements, (pm_node_t *) write);
22433 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
22434 pm_arguments_node_arguments_append(
22436 (pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$/", 2))
22439 if (PM_PARSER_COMMAND_LINE_OPTION_L(parser)) {
22440 pm_keyword_hash_node_t *keywords = pm_keyword_hash_node_create(parser);
22441 pm_keyword_hash_node_elements_append(keywords, (pm_node_t *) pm_assoc_node_create(
22443 (pm_node_t *) pm_symbol_node_synthesized_create(parser,
"chomp"),
22444 &(
pm_token_t) { .type = PM_TOKEN_NOT_PROVIDED, .start = parser->
start, .end = parser->
start },
22445 (pm_node_t *) pm_true_node_synthesized_create(parser)
22448 pm_arguments_node_arguments_append(arguments, (pm_node_t *) keywords);
22449 pm_node_flag_set((pm_node_t *) arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS);
22452 pm_statements_node_t *wrapped_statements = pm_statements_node_create(parser);
22453 pm_statements_node_body_append(parser, wrapped_statements, (pm_node_t *) pm_while_node_synthesized_create(
22455 (pm_node_t *) pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser,
"gets", 4)),
22459 statements = wrapped_statements;
22474 pm_parser_scope_push(parser,
true);
22477 pm_node_list_t current_block_exits = { 0 };
22478 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
22480 parser_lex(parser);
22481 pm_statements_node_t *statements = parse_statements(parser,
PM_CONTEXT_MAIN, 0);
22487 assert(statements->
body.
size > 0);
22488 pm_void_statement_check(parser, statements->
body.
nodes[statements->
body.
size - 1]);
22493 pm_parser_scope_pop(parser);
22498 statements = wrap_statements(parser, statements);
22500 flush_block_exits(parser, previous_block_exits);
22501 pm_node_list_free(¤t_block_exits);
22507 if (statements == NULL) {
22508 statements = pm_statements_node_create(parser);
22509 pm_statements_node_location_set(statements, parser->
start, parser->
start);
22512 return (pm_node_t *) pm_program_node_create(parser, &locals, statements);
22529pm_strnstr(
const char *big,
const char *little,
size_t big_length) {
22530 size_t little_length = strlen(little);
22532 for (
const char *big_end = big + big_length; big < big_end; big++) {
22533 if (*big == *little && memcmp(big, little, little_length) == 0)
return big;
22540#define pm_parser_warn_shebang_carriage_return(parser, start, length) ((void) 0)
22548pm_parser_warn_shebang_carriage_return(
pm_parser_t *parser,
const uint8_t *start,
size_t length) {
22549 if (length > 2 && start[length - 2] ==
'\r' && start[length - 1] ==
'\n') {
22550 pm_parser_warn(parser, start, start + length, PM_WARN_SHEBANG_CARRIAGE_RETURN);
22561 const char *switches = pm_strnstr(engine,
" -", length);
22562 if (switches == NULL)
return;
22567 (
const uint8_t *) (switches + 1),
22568 length - ((
size_t) (switches - engine)) - 1,
22572 size_t encoding_length;
22573 if ((encoding_length = pm_string_length(&next_options.
encoding)) > 0) {
22574 const uint8_t *encoding_source = pm_string_source(&next_options.
encoding);
22575 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22587 assert(source != NULL);
22591 .lex_state = PM_LEX_STATE_BEG,
22592 .enclosure_nesting = 0,
22593 .lambda_enclosure_nesting = -1,
22594 .brace_nesting = 0,
22595 .do_loop_stack = 0,
22596 .accepts_block_stack = 0,
22599 .stack = {{ .mode = PM_LEX_DEFAULT }},
22603 .end = source + size,
22604 .previous = { .type = PM_TOKEN_EOF, .start = source, .end = source },
22605 .current = { .type = PM_TOKEN_EOF, .start = source, .end = source },
22606 .next_start = NULL,
22607 .heredoc_end = NULL,
22608 .data_loc = { .start = NULL, .end = NULL },
22609 .comment_list = { 0 },
22610 .magic_comment_list = { 0 },
22611 .warning_list = { 0 },
22612 .error_list = { 0 },
22613 .current_scope = NULL,
22614 .current_context = NULL,
22616 .encoding_changed_callback = NULL,
22617 .encoding_comment_start = source,
22618 .lex_callback = NULL,
22620 .constant_pool = { 0 },
22621 .newline_list = { 0 },
22625 .explicit_encoding = NULL,
22627 .parsing_eval =
false,
22628 .partial_script =
false,
22629 .command_start =
true,
22630 .recovering =
false,
22631 .encoding_locked =
false,
22632 .encoding_changed =
false,
22633 .pattern_matching_newlines =
false,
22634 .in_keyword_arg =
false,
22635 .current_block_exits = NULL,
22636 .semantic_token_seen =
false,
22638 .current_regular_expression_ascii_only =
false,
22639 .warn_mismatched_indentation =
true
22656 uint32_t constant_size = ((uint32_t) size) / 95;
22657 pm_constant_pool_init(&parser->
constant_pool, constant_size < 4 ? 4 : constant_size);
22662 size_t newline_size = size / 22;
22663 pm_newline_list_init(&parser->
newline_list, source, newline_size < 4 ? 4 : newline_size);
22666 if (options != NULL) {
22674 size_t encoding_length = pm_string_length(&options->
encoding);
22675 if (encoding_length > 0) {
22676 const uint8_t *encoding_source = pm_string_source(&options->
encoding);
22677 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22699 for (
size_t scope_index = 0; scope_index < options->
scopes_count; scope_index++) {
22701 pm_parser_scope_push(parser, scope_index == 0);
22707 for (
size_t local_index = 0; local_index < scope->
locals_count; local_index++) {
22708 const pm_string_t *local = pm_options_scope_local_get(scope, local_index);
22710 const uint8_t *source = pm_string_source(local);
22711 size_t length = pm_string_length(local);
22713 void *allocated =
xmalloc(length);
22714 if (allocated == NULL)
continue;
22716 memcpy(allocated, source, length);
22717 pm_parser_local_add_owned(parser, (uint8_t *) allocated, length);
22728 pm_accepts_block_stack_push(parser,
true);
22731 if (size >= 3 && source[0] == 0xef && source[1] == 0xbb && source[2] == 0xbf) {
22744 bool search_shebang = PM_PARSER_COMMAND_LINE_OPTION_X(parser);
22761 const uint8_t *newline = next_newline(parser->
start, parser->
end - parser->
start);
22762 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - parser->
start);
22764 if (length > 2 && parser->
current.end[0] ==
'#' && parser->
current.end[1] ==
'!') {
22765 const char *engine;
22767 if ((engine = pm_strnstr((
const char *) parser->
start,
"ruby", length)) != NULL) {
22768 if (newline != NULL) {
22772 pm_parser_warn_shebang_carriage_return(parser, parser->
start, length + 1);
22777 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) parser->
start)));
22780 search_shebang =
false;
22782 search_shebang =
true;
22788 if (search_shebang) {
22791 bool found_shebang =
false;
22795 const uint8_t *cursor = parser->
start;
22799 const uint8_t *newline = next_newline(cursor, parser->
end - cursor);
22801 while (newline != NULL) {
22802 pm_newline_list_append(&parser->
newline_list, newline);
22804 cursor = newline + 1;
22805 newline = next_newline(cursor, parser->
end - cursor);
22807 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - cursor);
22808 if (length > 2 && cursor[0] ==
'#' && cursor[1] ==
'!') {
22809 const char *engine;
22810 if ((engine = pm_strnstr((
const char *) cursor,
"ruby", length)) != NULL) {
22811 found_shebang =
true;
22813 if (newline != NULL) {
22814 pm_parser_warn_shebang_carriage_return(parser, cursor, length + 1);
22819 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) cursor)));
22827 if (found_shebang) {
22828 parser->
previous = (
pm_token_t) { .type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
22829 parser->
current = (
pm_token_t) { .type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
22831 pm_parser_err(parser, parser->
start, parser->
start, PM_ERR_SCRIPT_NOT_FOUND);
22858 for (node = list->
head; node != NULL; node = next) {
22870pm_magic_comment_list_free(
pm_list_t *list) {
22873 for (node = list->
head; node != NULL; node = next) {
22886 pm_string_free(&parser->
filepath);
22887 pm_diagnostic_list_free(&parser->
error_list);
22899 pm_parser_scope_pop(parser);
22903 lex_mode_pop(parser);
22912 return parse_program(parser);
22922#define LINE_SIZE 4096
22923 char line[LINE_SIZE];
22925 while (memset(line,
'\n', LINE_SIZE), stream_fgets(line, LINE_SIZE, stream) != NULL) {
22926 size_t length = LINE_SIZE;
22927 while (length > 0 && line[length - 1] ==
'\n') length--;
22929 if (length == LINE_SIZE) {
22934 pm_buffer_append_string(buffer, line, length);
22940 pm_buffer_append_string(buffer, line, length);
22948 if (strncmp(line,
"__END__", 7) == 0)
return false;
22951 if (strncmp(line,
"__END__\n", 8) == 0)
return false;
22954 if (strncmp(line,
"__END__\r\n", 9) == 0)
return false;
22960 if (stream_feof(stream)) {
22979pm_parse_stream_unterminated_heredoc_p(
pm_parser_t *parser) {
22982 for (; diagnostic != NULL; diagnostic = (
pm_diagnostic_t *) diagnostic->node.next) {
22983 if (diagnostic->diag_id == PM_ERR_HEREDOC_TERM) {
22999 pm_buffer_init(buffer);
23001 bool eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof);
23003 pm_parser_init(parser, (
const uint8_t *) pm_buffer_value(buffer), pm_buffer_length(buffer), options);
23004 pm_node_t *node =
pm_parse(parser);
23007 pm_node_destroy(parser, node);
23008 eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof);
23011 pm_parser_init(parser, (
const uint8_t *) pm_buffer_value(buffer), pm_buffer_length(buffer), options);
23022pm_parse_success_p(
const uint8_t *source,
size_t size,
const char *data) {
23024 pm_options_read(&options, data);
23027 pm_parser_init(&parser, source, size, &options);
23029 pm_node_t *node = pm_parse(&parser);
23030 pm_node_destroy(&parser, node);
23033 pm_parser_free(&parser);
23034 pm_options_free(&options);
23039#undef PM_CASE_KEYWORD
23040#undef PM_CASE_OPERATOR
23041#undef PM_CASE_WRITABLE
23042#undef PM_STRING_EMPTY
23043#undef PM_LOCATION_NODE_BASE_VALUE
23044#undef PM_LOCATION_NODE_VALUE
23045#undef PM_LOCATION_NULL_VALUE
23046#undef PM_LOCATION_TOKEN_VALUE
23051#ifndef PRISM_EXCLUDE_SERIALIZATION
23055 pm_buffer_append_string(buffer,
"PRISM", 5);
23059 pm_buffer_append_byte(buffer, PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS ? 1 : 0);
23067 pm_serialize_header(buffer);
23069 pm_buffer_append_byte(buffer,
'\0');
23077pm_serialize_parse(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
23079 pm_options_read(&options, data);
23082 pm_parser_init(&parser, source, size, &options);
23084 pm_node_t *node = pm_parse(&parser);
23086 pm_serialize_header(buffer);
23088 pm_buffer_append_byte(buffer,
'\0');
23090 pm_node_destroy(&parser, node);
23091 pm_parser_free(&parser);
23092 pm_options_free(&options);
23103 pm_options_read(&options, data);
23106 pm_node_t *node = pm_parse_stream(&parser, &parser_buffer, stream, stream_fgets, stream_feof, &options);
23107 pm_serialize_header(buffer);
23109 pm_buffer_append_byte(buffer,
'\0');
23111 pm_node_destroy(&parser, node);
23112 pm_buffer_free(&parser_buffer);
23113 pm_parser_free(&parser);
23114 pm_options_free(&options);
23121pm_serialize_parse_comments(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
23123 pm_options_read(&options, data);
23126 pm_parser_init(&parser, source, size, &options);
23128 pm_node_t *node = pm_parse(&parser);
23129 pm_serialize_header(buffer);
23131 pm_buffer_append_varsint(buffer, parser.
start_line);
23134 pm_node_destroy(&parser, node);
23135 pm_parser_free(&parser);
23136 pm_options_free(&options);
23148 PM_SLICE_TYPE_ERROR = -1,
23151 PM_SLICE_TYPE_NONE,
23154 PM_SLICE_TYPE_LOCAL,
23157 PM_SLICE_TYPE_CONSTANT,
23160 PM_SLICE_TYPE_METHOD_NAME
23167pm_slice_type(
const uint8_t *source,
size_t length,
const char *encoding_name) {
23169 const pm_encoding_t *encoding = pm_encoding_find((
const uint8_t *) encoding_name, (
const uint8_t *) (encoding_name + strlen(encoding_name)));
23170 if (encoding == NULL)
return PM_SLICE_TYPE_ERROR;
23173 if (length == 0)
return PM_SLICE_TYPE_NONE;
23176 if ((width = encoding->
alpha_char(source, (ptrdiff_t) length)) != 0) {
23178 }
else if (*source ==
'_') {
23181 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, (ptrdiff_t) length)) > 0)) {
23185 return PM_SLICE_TYPE_NONE;
23189 const uint8_t *end = source + length;
23190 pm_slice_type_t result = encoding->
isupper_char(source, end - source) ? PM_SLICE_TYPE_CONSTANT : PM_SLICE_TYPE_LOCAL;
23196 while (source < end) {
23197 if ((width = encoding->
alnum_char(source, end - source)) != 0) {
23200 }
else if (*source ==
'_') {
23203 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, end - source)) > 0)) {
23213 if (*source ==
'!' || *source ==
'?' || *source ==
'=') {
23215 result = PM_SLICE_TYPE_METHOD_NAME;
23219 return source == end ? result : PM_SLICE_TYPE_NONE;
23226pm_string_query_local(
const uint8_t *source,
size_t length,
const char *encoding_name) {
23227 switch (pm_slice_type(source, length, encoding_name)) {
23228 case PM_SLICE_TYPE_ERROR:
23230 case PM_SLICE_TYPE_NONE:
23231 case PM_SLICE_TYPE_CONSTANT:
23232 case PM_SLICE_TYPE_METHOD_NAME:
23234 case PM_SLICE_TYPE_LOCAL:
23238 assert(
false &&
"unreachable");
23246pm_string_query_constant(
const uint8_t *source,
size_t length,
const char *encoding_name) {
23247 switch (pm_slice_type(source, length, encoding_name)) {
23248 case PM_SLICE_TYPE_ERROR:
23250 case PM_SLICE_TYPE_NONE:
23251 case PM_SLICE_TYPE_LOCAL:
23252 case PM_SLICE_TYPE_METHOD_NAME:
23254 case PM_SLICE_TYPE_CONSTANT:
23258 assert(
false &&
"unreachable");
23266pm_string_query_method_name(
const uint8_t *source,
size_t length,
const char *encoding_name) {
23267#define B(p) ((p) ? PM_STRING_QUERY_TRUE : PM_STRING_QUERY_FALSE)
23268#define C1(c) (*source == c)
23269#define C2(s) (memcmp(source, s, 2) == 0)
23270#define C3(s) (memcmp(source, s, 3) == 0)
23272 switch (pm_slice_type(source, length, encoding_name)) {
23273 case PM_SLICE_TYPE_ERROR:
23275 case PM_SLICE_TYPE_NONE:
23277 case PM_SLICE_TYPE_LOCAL:
23279 return B((length != 2) || (source[0] !=
'_') || (source[1] ==
'0') || !pm_char_is_decimal_digit(source[1]));
23280 case PM_SLICE_TYPE_CONSTANT:
23282 case PM_SLICE_TYPE_METHOD_NAME:
23289 return B(C1(
'&') || C1(
'`') || C1(
'!') || C1(
'^') || C1(
'>') || C1(
'<') || C1(
'-') || C1(
'%') || C1(
'|') || C1(
'+') || C1(
'/') || C1(
'*') || C1(
'~'));
23291 return B(C2(
"!=") || C2(
"!~") || C2(
"[]") || C2(
"==") || C2(
"=~") || C2(
">=") || C2(
">>") || C2(
"<=") || C2(
"<<") || C2(
"**"));
23293 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.
struct pm_options_scope pm_options_scope_t
A scope of locals surrounding the code that is being parsed.
struct pm_options pm_options_t
The options that can be passed to the parser.
static const uint8_t PM_OPTIONS_COMMAND_LINE_N
A bit representing whether or not the command line -n option was set.
#define PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED
String literals should be made frozen.
#define PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED
String literals should be made mutable.
#define PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET
String literals may be frozen or mutable depending on the implementation default.
static const uint8_t PM_OPTIONS_COMMAND_LINE_P
A bit representing whether or not the command line -p option was set.
@ PM_OPTIONS_VERSION_CRUBY_3_3
The vendored version of prism in CRuby 3.3.x.
@ PM_OPTIONS_VERSION_LATEST
The current version of prism.
@ PM_OPTIONS_VERSION_UNSET
If an explicit version is not provided, the current version of prism will be used.
@ PM_OPTIONS_VERSION_CRUBY_3_4
The vendored version of prism in CRuby 3.4.x.
@ PM_OPTIONS_VERSION_CRUBY_3_5
The vendored version of prism in CRuby 3.5.x.
struct pm_locals pm_locals_t
This is a set of local variables in a certain lexical context (method, class, module,...
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_lex_mode pm_lex_mode_t
When lexing Ruby source, the lexer has a small amount of state to tell which kind of token it is curr...
struct pm_comment pm_comment_t
This is a node in the linked list of comments that we've found while parsing.
pm_lex_state_t
This enum combines the various bits from the above enum into individual values that represent the var...
struct pm_scope pm_scope_t
This struct represents a node in a linked list of scopes.
pm_heredoc_quote_t
The type of quote that a heredoc uses.
void(* pm_encoding_changed_callback_t)(pm_parser_t *parser)
When the encoding that is being used to parse the source is changed by prism, we provide the ability ...
pm_context_t
While parsing, we keep track of a stack of contexts.
@ PM_CONTEXT_CLASS_RESCUE
a rescue statement within a class statement
@ PM_CONTEXT_ELSIF
an elsif clause
@ PM_CONTEXT_DEF_RESCUE
a rescue statement within a method definition
@ PM_CONTEXT_ELSE
an else clause
@ PM_CONTEXT_FOR_INDEX
a for loop's index
@ PM_CONTEXT_CASE_WHEN
a case when statements
@ PM_CONTEXT_BLOCK_RESCUE
a rescue statement within a do..end block
@ PM_CONTEXT_MODULE
a module declaration
@ PM_CONTEXT_DEF_PARAMS
a method definition's parameters
@ PM_CONTEXT_CASE_IN
a case in statements
@ PM_CONTEXT_BLOCK_ELSE
a rescue else statement within a do..end block
@ PM_CONTEXT_LOOP_PREDICATE
the predicate clause of a loop statement
@ PM_CONTEXT_SCLASS
a singleton class definition
@ PM_CONTEXT_UNLESS
an unless statement
@ PM_CONTEXT_POSTEXE
an END block
@ PM_CONTEXT_IF
an if statement
@ PM_CONTEXT_MULTI_TARGET
a multiple target expression
@ PM_CONTEXT_LAMBDA_RESCUE
a rescue statement within a lambda expression
@ PM_CONTEXT_BEGIN_ELSE
a rescue else statement with an explicit begin
@ PM_CONTEXT_NONE
a null context, used for returning a value from a function
@ PM_CONTEXT_CLASS_ELSE
a rescue else statement within a class statement
@ PM_CONTEXT_LAMBDA_ENSURE
an ensure statement within a lambda expression
@ PM_CONTEXT_BLOCK_ENSURE
an ensure statement within a do..end block
@ PM_CONTEXT_CLASS_ENSURE
an ensure statement within a class statement
@ PM_CONTEXT_LAMBDA_BRACES
a lambda expression with braces
@ PM_CONTEXT_MODULE_ELSE
a rescue else statement within a module statement
@ PM_CONTEXT_PARENS
a parenthesized expression
@ PM_CONTEXT_BLOCK_BRACES
expressions in block arguments using braces
@ PM_CONTEXT_DEF_ENSURE
an ensure statement within a method definition
@ PM_CONTEXT_SCLASS_RESCUE
a rescue statement with a singleton class
@ PM_CONTEXT_PREEXE
a BEGIN block
@ PM_CONTEXT_DEFINED
a defined?
@ PM_CONTEXT_MODULE_ENSURE
an ensure statement within a module statement
@ PM_CONTEXT_BEGIN_RESCUE
a rescue statement with an explicit begin
@ PM_CONTEXT_UNTIL
an until statement
@ PM_CONTEXT_DEF_ELSE
a rescue else statement within a method definition
@ PM_CONTEXT_FOR
a for loop
@ PM_CONTEXT_PREDICATE
a predicate inside an if/elsif/unless statement
@ PM_CONTEXT_BEGIN_ENSURE
an ensure statement with an explicit begin
@ PM_CONTEXT_SCLASS_ENSURE
an ensure statement with a singleton class
@ PM_CONTEXT_DEFAULT_PARAMS
a method definition's default parameter
@ PM_CONTEXT_LAMBDA_ELSE
a rescue else statement within a lambda expression
@ PM_CONTEXT_CLASS
a class declaration
@ PM_CONTEXT_MAIN
the top level context
@ PM_CONTEXT_LAMBDA_DO_END
a lambda expression with do..end
@ PM_CONTEXT_BEGIN
a begin statement
@ PM_CONTEXT_RESCUE_MODIFIER
a modifier rescue clause
@ PM_CONTEXT_EMBEXPR
an interpolated expression
@ PM_CONTEXT_TERNARY
a ternary expression
@ PM_CONTEXT_DEF
a method definition
@ PM_CONTEXT_SCLASS_ELSE
a rescue else statement with a singleton class
@ PM_CONTEXT_MODULE_RESCUE
a rescue statement within a module statement
@ PM_CONTEXT_BLOCK_KEYWORDS
expressions in block arguments using do..end
@ PM_CONTEXT_WHILE
a while statement
uint8_t pm_scope_parameters_t
The flags about scope parameters that can be set.
uint8_t pm_shareable_constant_value_t
The type of shareable constant value that can be set.
pm_comment_type_t
This is the type of a comment that we've found while parsing.
#define PM_CONSTANT_ID_UNSET
When we allocate constants into the pool, we reserve 0 to mean that the slot is not yet filled.
uint32_t pm_constant_id_t
A constant id is a unique identifier for a constant in the constant pool.
struct pm_list_node pm_list_node_t
This struct represents an abstract linked list that provides common functionality.
#define PM_STRING_EMPTY
Defines an empty string.
#define PRISM_FALLTHROUGH
We use -Wimplicit-fallthrough to guard potentially unintended fall-through between cases of a switch.
#define PRISM_UNLIKELY(x)
The compiler should predicate that this branch will not be taken.
#define PRISM_ATTRIBUTE_UNUSED
GCC will warn if you specify a function or parameter that is unused at runtime.
#define PRISM_DEPTH_MAXIMUM
When we are parsing using recursive descent, we want to protect against malicious payloads that could...
#define PM_STATIC_ASSERT(line, condition, message)
We want to be able to use static assertions, but they weren't standardized until C11.
#define PRISM_EXPORTED_FUNCTION
By default, we compile with -fvisibility=hidden.
#define PM_ENCODING_US_ASCII_ENTRY
This is the US-ASCII encoding.
#define PM_ENCODING_UTF_8_ENTRY
This is the default UTF-8 encoding.
#define PRISM_ENCODING_ALPHABETIC_BIT
All of the lookup tables use the first bit of each embedded byte to indicate whether the codepoint is...
#define PRISM_ENCODING_ALPHANUMERIC_BIT
All of the lookup tables use the second bit of each embedded byte to indicate whether the codepoint i...
#define PM_NODE_LIST_FOREACH(list, index, node)
Loop through each node in the node list, writing each node to the given pm_node_t pointer.
#define PRISM_VERSION
The version of the Prism library as a constant string.
#define PRISM_VERSION_PATCH
The patch version of the Prism library as an int.
#define PRISM_VERSION_MINOR
The minor version of the Prism library as an int.
#define PRISM_VERSION_MAJOR
The major version of the Prism library as an int.
The main header file for the prism parser.
pm_string_query_t
Represents the results of a slice query.
@ PM_STRING_QUERY_TRUE
Returned if the result of the slice query is true.
@ PM_STRING_QUERY_ERROR
Returned if the encoding given to a slice query was invalid.
@ PM_STRING_QUERY_FALSE
Returned if the result of the slice query is false.
void pm_serialize_content(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer)
Serialize the encoding, metadata, nodes, and constant pool.
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_encoding(const pm_encoding_t *encoding, pm_buffer_t *buffer)
Serialize the name of the encoding to the buffer.
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_comment_list(pm_parser_t *parser, pm_list_t *list, pm_buffer_t *buffer)
Serialize the given list of comments to the given buffer.
PRISM_EXPORTED_FUNCTION const char * pm_version(void)
The prism version and the serialization format.
const char * pm_token_type_human(pm_token_type_t token_type)
Returns the human name of the given token type.
This struct is used to pass information between the regular expression parser and the error callback.
pm_parser_t * parser
The parser that we are parsing the regular expression for.
const uint8_t * start
The start of the regular expression.
bool shared
Whether or not the source of the regular expression is shared.
const uint8_t * end
The end of the regular expression.
This struct is used to pass information between the regular expression parser and the named capture c...
pm_constant_id_list_t names
The list of names that have been parsed.
pm_parser_t * parser
The parser that is parsing the regular expression.
pm_match_write_node_t * match
The match write node that is being created.
pm_call_node_t * call
The call node wrapping the regular expression node.
bool shared
Whether the content of the regular expression is shared.
struct pm_node * left
AndNode::left.
struct pm_node * right
AndNode::right.
pm_node_t base
The embedded base node.
struct pm_node_list arguments
ArgumentsNode::arguments.
This is a special out parameter to the parse_arguments_list function that includes opening and closin...
pm_node_t * block
The optional block attached to the call.
bool has_forwarding
The flag indicating whether this arguments list has forwarding argument.
pm_location_t opening_loc
The optional location of the opening parenthesis or bracket.
pm_arguments_node_t * arguments
The lazily-allocated optional arguments node.
pm_location_t closing_loc
The optional location of the closing parenthesis or bracket.
struct pm_node_list elements
ArrayNode::elements.
struct pm_node * constant
ArrayPatternNode::constant.
pm_location_t opening_loc
ArrayPatternNode::opening_loc.
pm_node_t base
The embedded base node.
pm_location_t closing_loc
ArrayPatternNode::closing_loc.
struct pm_node * value
AssocNode::value.
struct pm_node * key
AssocNode::key.
struct pm_ensure_node * ensure_clause
BeginNode::ensure_clause.
struct pm_rescue_node * rescue_clause
BeginNode::rescue_clause.
struct pm_statements_node * statements
BeginNode::statements.
pm_node_t base
The embedded base node.
struct pm_else_node * else_clause
BeginNode::else_clause.
This struct represents a set of binding powers used for a given token.
bool binary
Whether or not this token can be used as a binary operator.
pm_binding_power_t left
The left binding power.
bool nonassoc
Whether or not this token can be used as non-associative binary operator.
pm_binding_power_t right
The right binding power.
A pm_buffer_t is a simple memory buffer that stores data in a contiguous block of memory.
size_t length
The length of the buffer in bytes.
char * value
A pointer to the start of the buffer.
pm_location_t opening_loc
CallNode::opening_loc.
pm_location_t closing_loc
CallNode::closing_loc.
struct pm_node * receiver
CallNode::receiver.
pm_constant_id_t name
CallNode::name.
pm_node_t base
The embedded base node.
pm_location_t call_operator_loc
CallNode::call_operator_loc.
pm_location_t message_loc
CallNode::message_loc.
struct pm_arguments_node * arguments
CallNode::arguments.
struct pm_node * block
CallNode::block.
struct pm_node_list conditions
CaseMatchNode::conditions.
struct pm_node_list conditions
CaseNode::conditions.
A constant in the pool which effectively stores a string.
size_t length
The length of the string.
const uint8_t * start
A pointer to the start of the string.
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.
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.
pm_integer_t value
IntegerNode::value.
pm_node_t base
The embedded base node.
bool negative
Whether or not the integer is negative.
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...
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.
struct pm_lex_mode * prev
The previous lex state so that it knows how to pop.
union pm_lex_mode::@303336126360075302344075121136356113360170030306 as
The data associated with this type of lex mode.
bool label_allowed
Whether or not at the end of the string we should allow a :, which would indicate this was a dynamic ...
const uint8_t * next_start
This is the pointer to the character where lexing should resume once the heredoc has been completely ...
size_t * common_whitespace
This is used to track the amount of common whitespace on each line so that we know how much to dedent...
enum pm_lex_mode::@204051102252353332352362146052355003264223055126 mode
The type of this lex mode.
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.
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.
size_t size
The number of nodes in the list.
struct pm_node ** nodes
The nodes in the list.
pm_node_type_t type
This represents the type of the node.
pm_node_flags_t flags
This represents any flags on the node.
pm_location_t location
This is the location of the node in the source.
size_t locals_count
The number of locals in the scope.
uint8_t forwarding
Flags for the set of forwarding parameters in this scope.
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.
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.
PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse(pm_parser_t *parser)
Initiate the parser with the given parser.
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...
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...
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.
PRISM_EXPORTED_FUNCTION void pm_parser_free(pm_parser_t *parser)
Free any memory associated with the given parser.
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.
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.
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.
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.
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.
struct pm_parser::@236040131255244317313236162207277265316171136011 lex_modes
A stack of lex modes.
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...
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.
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::@346265266332060241255337121126133217326336224105 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.