15#define PM_TAB_WHITESPACE_SIZE 8
18#define MIN(a,b) (((a)<(b))?(a):(b))
19#define MAX(a,b) (((a)>(b))?(a):(b))
25#define FL PM_NODE_FLAGS
26#define UP PM_NODE_UPCAST
28#define PM_TOKEN_START(token_) ((token_)->start)
29#define PM_TOKEN_END(token_) ((token_)->end)
31#define PM_NODE_START(node_) (UP(node_)->location.start)
32#define PM_NODE_END(node_) (UP(node_)->location.end)
34#define PM_LOCATION_NULL_VALUE(parser_) ((pm_location_t) { .start = (parser_)->start, .end = (parser_)->start })
35#define PM_LOCATION_TOKEN_VALUE(token_) ((pm_location_t) { .start = PM_TOKEN_START(token_), .end = PM_TOKEN_END(token_) })
36#define PM_LOCATION_NODE_VALUE(node_) ((pm_location_t) { .start = PM_NODE_START(node_), .end = PM_NODE_END(node_) })
37#define PM_OPTIONAL_LOCATION_TOKEN_VALUE(token) ((token)->type == PM_TOKEN_NOT_PROVIDED ? ((pm_location_t) { 0 }) : PM_LOCATION_TOKEN_VALUE(token))
48lex_mode_incrementor(
const uint8_t start) {
65lex_mode_terminator(
const uint8_t start) {
107lex_mode_push_list(
pm_parser_t *parser,
bool interpolation, uint8_t delimiter) {
108 uint8_t incrementor = lex_mode_incrementor(delimiter);
109 uint8_t terminator = lex_mode_terminator(delimiter);
115 .interpolation = interpolation,
116 .incrementor = incrementor,
117 .terminator = terminator
124 memcpy(breakpoints,
"\\ \t\f\r\v\n\0\0\0",
sizeof(lex_mode.
as.list.
breakpoints));
129 if (terminator !=
'\0') {
130 breakpoints[index++] = terminator;
136 breakpoints[index++] =
'#';
140 if (incrementor !=
'\0') {
141 breakpoints[index++] = incrementor;
145 return lex_mode_push(parser, lex_mode);
155 return lex_mode_push_list(parser,
false,
'\0');
162lex_mode_push_regexp(
pm_parser_t *parser, uint8_t incrementor, uint8_t terminator) {
164 .mode = PM_LEX_REGEXP,
167 .incrementor = incrementor,
168 .terminator = terminator
176 memcpy(breakpoints,
"\r\n\\#\0\0",
sizeof(lex_mode.
as.regexp.
breakpoints));
180 if (terminator !=
'\0') {
181 breakpoints[index++] = terminator;
185 if (incrementor !=
'\0') {
186 breakpoints[index++] = incrementor;
190 return lex_mode_push(parser, lex_mode);
197lex_mode_push_string(
pm_parser_t *parser,
bool interpolation,
bool label_allowed, uint8_t incrementor, uint8_t terminator) {
199 .mode = PM_LEX_STRING,
202 .interpolation = interpolation,
203 .label_allowed = label_allowed,
204 .incrementor = incrementor,
205 .terminator = terminator
212 memcpy(breakpoints,
"\r\n\\\0\0\0",
sizeof(lex_mode.
as.string.
breakpoints));
217 if (terminator !=
'\0') {
218 breakpoints[index++] = terminator;
224 breakpoints[index++] =
'#';
229 if (incrementor !=
'\0') {
230 breakpoints[index++] = incrementor;
234 return lex_mode_push(parser, lex_mode);
244 return lex_mode_push_string(parser,
false,
false,
'\0',
'\0');
276 PM_IGNORED_NEWLINE_NONE = 0,
277 PM_IGNORED_NEWLINE_ALL,
278 PM_IGNORED_NEWLINE_PATTERN
279} pm_ignored_newline_type_t;
281static inline pm_ignored_newline_type_t
283 bool ignored = lex_state_p(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_CLASS | PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT) && !lex_state_p(parser, PM_LEX_STATE_LABELED);
286 return PM_IGNORED_NEWLINE_ALL;
287 }
else if ((parser->
lex_state & ~((
unsigned int) PM_LEX_STATE_LABEL)) == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)) {
288 return PM_IGNORED_NEWLINE_PATTERN;
290 return PM_IGNORED_NEWLINE_NONE;
296 return lex_state_p(parser, PM_LEX_STATE_BEG_ANY) || ((parser->
lex_state & (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)) == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED));
301 return lex_state_p(parser, PM_LEX_STATE_ARG_ANY);
305lex_state_spcarg_p(
pm_parser_t *parser,
bool space_seen) {
309 return lex_state_arg_p(parser) && space_seen && !pm_char_is_whitespace(*parser->
current.end);
314 return lex_state_p(parser, PM_LEX_STATE_END_ANY);
322 return lex_state_p(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT);
334#ifndef PM_DEBUG_LOGGING
339#define PM_DEBUG_LOGGING 0
345 fprintf(stderr,
"STATE: ");
348 if (parser->
lex_state == PM_LEX_STATE_NONE) {
349 fprintf(stderr,
"NONE\n");
353#define CHECK_STATE(state) \
354 if (parser->lex_state & state) { \
355 if (!first) fprintf(stderr, "|"); \
356 fprintf(stderr, "%s", #state); \
360 CHECK_STATE(PM_LEX_STATE_BEG)
361 CHECK_STATE(PM_LEX_STATE_END)
362 CHECK_STATE(PM_LEX_STATE_ENDARG)
363 CHECK_STATE(PM_LEX_STATE_ENDFN)
364 CHECK_STATE(PM_LEX_STATE_ARG)
365 CHECK_STATE(PM_LEX_STATE_CMDARG)
366 CHECK_STATE(PM_LEX_STATE_MID)
367 CHECK_STATE(PM_LEX_STATE_FNAME)
368 CHECK_STATE(PM_LEX_STATE_DOT)
369 CHECK_STATE(PM_LEX_STATE_CLASS)
370 CHECK_STATE(PM_LEX_STATE_LABEL)
371 CHECK_STATE(PM_LEX_STATE_LABELED)
372 CHECK_STATE(PM_LEX_STATE_FITEM)
376 fprintf(stderr,
"\n");
381 fprintf(stderr,
"Caller: %s:%d\nPrevious: ", caller_name, line_number);
383 lex_state_set(parser, state);
384 fprintf(stderr,
"Now: ");
386 fprintf(stderr,
"\n");
389#define lex_state_set(parser, state) debug_lex_state_set(parser, state, __func__, __LINE__)
397#define PM_PARSER_COMMAND_LINE_OPTION(parser, option) ((parser)->command_line & (option))
400#define PM_PARSER_COMMAND_LINE_OPTION_A(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_A)
403#define PM_PARSER_COMMAND_LINE_OPTION_E(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_E)
406#define PM_PARSER_COMMAND_LINE_OPTION_L(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_L)
409#define PM_PARSER_COMMAND_LINE_OPTION_N(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_N)
412#define PM_PARSER_COMMAND_LINE_OPTION_P(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_P)
415#define PM_PARSER_COMMAND_LINE_OPTION_X(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_X)
426 pm_diagnostic_list_append(&parser->
error_list, start, end, diag_id);
432#define PM_PARSER_ERR_FORMAT(parser, start, end, diag_id, ...) \
433 pm_diagnostic_list_append_format(&parser->error_list, start, end, diag_id, __VA_ARGS__)
441 pm_parser_err(parser, parser->
current.start, parser->
current.end, diag_id);
448#define PM_PARSER_ERR_LOCATION_FORMAT(parser, location, diag_id, ...) \
449 PM_PARSER_ERR_FORMAT(parser, (location)->start, (location)->end, diag_id, __VA_ARGS__)
464#define PM_PARSER_ERR_NODE_FORMAT(parser, node, diag_id, ...) \
465 PM_PARSER_ERR_FORMAT(parser, (node)->location.start, (node)->location.end, diag_id, __VA_ARGS__)
471#define PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, diag_id) \
472 PM_PARSER_ERR_NODE_FORMAT(parser, node, diag_id, (int) ((node)->location.end - (node)->location.start), (const char *) (node)->location.start)
489 pm_parser_err(parser, token->start, token->end, diag_id);
496#define PM_PARSER_ERR_TOKEN_FORMAT(parser, token, diag_id, ...) \
497 PM_PARSER_ERR_FORMAT(parser, (token).start, (token).end, diag_id, __VA_ARGS__)
503#define PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, token, diag_id) \
504 PM_PARSER_ERR_TOKEN_FORMAT(parser, token, diag_id, (int) ((token).end - (token).start), (const char *) (token).start)
511 pm_diagnostic_list_append(&parser->
warning_list, start, end, diag_id);
520 pm_parser_warn(parser, token->start, token->end, diag_id);
535#define PM_PARSER_WARN_FORMAT(parser, start, end, diag_id, ...) \
536 pm_diagnostic_list_append_format(&parser->warning_list, start, end, diag_id, __VA_ARGS__)
542#define PM_PARSER_WARN_TOKEN_FORMAT(parser, token, diag_id, ...) \
543 PM_PARSER_WARN_FORMAT(parser, (token).start, (token).end, diag_id, __VA_ARGS__)
549#define PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, token, diag_id) \
550 PM_PARSER_WARN_TOKEN_FORMAT(parser, token, diag_id, (int) ((token).end - (token).start), (const char *) (token).start)
556#define PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, ...) \
557 PM_PARSER_WARN_FORMAT(parser, (node)->location.start, (node)->location.end, diag_id, __VA_ARGS__)
565pm_parser_err_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
566 PM_PARSER_ERR_FORMAT(
569 ident_start + ident_length,
572 (
const char *) ident_start
584pm_parser_scope_push(
pm_parser_t *parser,
bool closed) {
586 if (scope == NULL)
return false;
591 .parameters = PM_SCOPE_PARAMETERS_NONE,
592 .implicit_parameters = { 0 },
610 if (scope->
previous == NULL)
return true;
611 if (scope->
closed)
return false;
612 }
while ((scope = scope->
previous) != NULL);
614 assert(
false &&
"unreachable");
622pm_parser_scope_find(
pm_parser_t *parser, uint32_t depth) {
625 while (depth-- > 0) {
626 assert(scope != NULL);
634 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS,
635 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT,
636 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL
637} pm_scope_forwarding_param_check_result_t;
639static pm_scope_forwarding_param_check_result_t
640pm_parser_scope_forwarding_param_check(
pm_parser_t *parser,
const uint8_t mask) {
642 bool conflict =
false;
644 while (scope != NULL) {
648 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT;
650 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS;
661 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL;
666 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_BLOCK)) {
667 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
670 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
671 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_AMPERSAND);
673 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
674 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_AMPERSAND);
681 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS)) {
682 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
685 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
686 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR);
688 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
689 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR);
696 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_ALL)) {
697 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
700 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
705 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
706 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
713 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS)) {
714 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
717 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
718 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR_STAR);
720 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
721 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR_STAR);
730pm_parser_scope_shareable_constant_get(
pm_parser_t *parser) {
754#define PM_LOCALS_HASH_THRESHOLD 9
769 name = ((name >> 16) ^ name) * 0x45d9f3b;
770 name = ((name >> 16) ^ name) * 0x45d9f3b;
771 name = (name >> 16) ^ name;
781 uint32_t next_capacity = locals->
capacity == 0 ? 4 : (locals->
capacity * 2);
782 assert(next_capacity > locals->
capacity);
785 if (next_locals == NULL) abort();
787 if (next_capacity < PM_LOCALS_HASH_THRESHOLD) {
788 if (locals->
size > 0) {
794 bool hash_needed = (locals->
capacity <= PM_LOCALS_HASH_THRESHOLD);
795 uint32_t mask = next_capacity - 1;
797 for (uint32_t index = 0; index < locals->
capacity; index++) {
801 if (hash_needed) local->
hash = pm_locals_hash(local->
name);
803 uint32_t hash = local->
hash;
805 next_locals[hash & mask] = *local;
810 pm_locals_free(locals);
811 locals->
locals = next_locals;
833 pm_locals_resize(locals);
836 if (locals->
capacity < PM_LOCALS_HASH_THRESHOLD) {
837 for (uint32_t index = 0; index < locals->
capacity; index++) {
843 .location = { .start = start, .end = end },
844 .index = locals->
size++,
849 }
else if (local->
name == name) {
854 uint32_t mask = locals->
capacity - 1;
855 uint32_t hash = pm_locals_hash(name);
856 uint32_t initial_hash = hash;
864 .location = { .start = start, .end = end },
865 .index = locals->
size++,
870 }
else if (local->
name == name) {
875 }
while ((hash & mask) != initial_hash);
878 assert(
false &&
"unreachable");
888 if (locals->
capacity < PM_LOCALS_HASH_THRESHOLD) {
889 for (uint32_t index = 0; index < locals->
size; index++) {
891 if (local->
name == name)
return index;
894 uint32_t mask = locals->
capacity - 1;
895 uint32_t hash = pm_locals_hash(name);
896 uint32_t initial_hash = hash & mask;
903 }
else if (local->
name == name) {
908 }
while ((hash & mask) != initial_hash);
920 uint32_t index = pm_locals_find(locals, name);
921 assert(index != UINT32_MAX);
924 assert(local->
reads < UINT32_MAX);
935 uint32_t index = pm_locals_find(locals, name);
936 assert(index != UINT32_MAX);
939 assert(local->
reads > 0);
949 uint32_t index = pm_locals_find(locals, name);
950 assert(index != UINT32_MAX);
965 pm_constant_id_list_init_capacity(list, locals->
size);
970 uint32_t capacity = locals->
capacity < PM_LOCALS_HASH_THRESHOLD ? locals->
size : locals->
capacity;
974 bool warn_unused = !toplevel || (!parser->parsing_eval && !PM_PARSER_COMMAND_LINE_OPTION_E(parser));
976 for (uint32_t index = 0; index < capacity; index++) {
980 pm_constant_id_list_insert(list, (
size_t) local->
index, local->
name);
982 if (warn_unused && local->
reads == 0 && ((parser->start_line >= 0) || (pm_newline_list_line(&parser->newline_list, local->
location.
start, parser->start_line) >= 0))) {
983 pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, local->
name);
985 if (constant->
length >= 1 && *constant->
start !=
'_') {
986 PM_PARSER_WARN_FORMAT(
990 PM_WARN_UNUSED_LOCAL_VARIABLE,
992 (
const char *) constant->
start
1008pm_parser_constant_id_location(
pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
1009 return pm_constant_pool_insert_shared(&parser->
constant_pool, start, (
size_t) (end - start));
1016pm_parser_constant_id_owned(
pm_parser_t *parser, uint8_t *start,
size_t length) {
1017 return pm_constant_pool_insert_owned(&parser->
constant_pool, start, length);
1024pm_parser_constant_id_constant(
pm_parser_t *parser,
const char *start,
size_t length) {
1025 return pm_constant_pool_insert_constant(&parser->
constant_pool, (
const uint8_t *) start, length);
1033 return pm_parser_constant_id_location(parser, token->start, token->end);
1042 return token->type == PM_TOKEN_NOT_PROVIDED ? 0 : pm_parser_constant_id_token(parser, token);
1051pm_check_value_expression(
pm_parser_t *parser, pm_node_t *node) {
1052 pm_node_t *void_node = NULL;
1054 while (node != NULL) {
1055 switch (PM_NODE_TYPE(node)) {
1056 case PM_RETURN_NODE:
1061 case PM_MATCH_REQUIRED_NODE:
1062 return void_node != NULL ? void_node : node;
1063 case PM_MATCH_PREDICATE_NODE:
1065 case PM_BEGIN_NODE: {
1066 pm_begin_node_t *cast = (pm_begin_node_t *) node;
1070 pm_node_t *vn = pm_check_value_expression(parser, UP(cast->
rescue_clause));
1071 if (vn != NULL)
return vn;
1075 pm_node_t *vn = pm_check_value_expression(parser, UP(cast->
statements));
1076 if (vn != NULL)
return vn;
1083 pm_node_t *vn = pm_check_value_expression(parser, UP(cast->
statements));
1084 if (vn == NULL)
return NULL;
1085 if (void_node == NULL) void_node = vn;
1087 for (pm_rescue_node_t *rescue_clause = cast->
rescue_clause; rescue_clause != NULL; rescue_clause = rescue_clause->
subsequent) {
1088 pm_node_t *vn = pm_check_value_expression(parser, UP(rescue_clause->statements));
1093 if (void_node == NULL) {
1109 case PM_ENSURE_NODE: {
1110 pm_ensure_node_t *cast = (pm_ensure_node_t *) node;
1114 case PM_PARENTHESES_NODE: {
1115 pm_parentheses_node_t *cast = (pm_parentheses_node_t *) node;
1116 node = UP(cast->
body);
1119 case PM_STATEMENTS_NODE: {
1120 pm_statements_node_t *cast = (pm_statements_node_t *) node;
1125 pm_if_node_t *cast = (pm_if_node_t *) node;
1129 pm_node_t *vn = pm_check_value_expression(parser, UP(cast->
statements));
1133 if (void_node == NULL) {
1139 case PM_UNLESS_NODE: {
1140 pm_unless_node_t *cast = (pm_unless_node_t *) node;
1144 pm_node_t *vn = pm_check_value_expression(parser, UP(cast->
statements));
1148 if (void_node == NULL) {
1154 case PM_ELSE_NODE: {
1155 pm_else_node_t *cast = (pm_else_node_t *) node;
1160 pm_and_node_t *cast = (pm_and_node_t *) node;
1165 pm_or_node_t *cast = (pm_or_node_t *) node;
1169 case PM_LOCAL_VARIABLE_WRITE_NODE: {
1170 pm_local_variable_write_node_t *cast = (pm_local_variable_write_node_t *) node;
1173 for (uint32_t depth = 0; depth < cast->
depth; depth++) scope = scope->
previous;
1187pm_assert_value_expression(
pm_parser_t *parser, pm_node_t *node) {
1188 pm_node_t *void_node = pm_check_value_expression(parser, node);
1189 if (void_node != NULL) {
1190 pm_parser_err_node(parser, void_node, PM_ERR_VOID_EXPRESSION);
1198pm_void_statement_check(
pm_parser_t *parser,
const pm_node_t *node) {
1199 const char *
type = NULL;
1202 switch (PM_NODE_TYPE(node)) {
1203 case PM_BACK_REFERENCE_READ_NODE:
1204 case PM_CLASS_VARIABLE_READ_NODE:
1205 case PM_GLOBAL_VARIABLE_READ_NODE:
1206 case PM_INSTANCE_VARIABLE_READ_NODE:
1207 case PM_LOCAL_VARIABLE_READ_NODE:
1208 case PM_NUMBERED_REFERENCE_READ_NODE:
1209 type =
"a variable";
1212 case PM_CALL_NODE: {
1213 const pm_call_node_t *cast = (
const pm_call_node_t *) node;
1217 switch (message->
length) {
1219 switch (message->
start[0]) {
1236 switch (message->
start[1]) {
1238 if (message->
start[0] ==
'<' || message->
start[0] ==
'>' || message->
start[0] ==
'!' || message->
start[0] ==
'=') {
1244 if (message->
start[0] ==
'+' || message->
start[0] ==
'-') {
1250 if (message->
start[0] ==
'*') {
1258 if (memcmp(message->
start,
"<=>", 3) == 0) {
1267 case PM_CONSTANT_PATH_NODE:
1271 case PM_CONSTANT_READ_NODE:
1272 type =
"a constant";
1275 case PM_DEFINED_NODE:
1284 case PM_IMAGINARY_NODE:
1285 case PM_INTEGER_NODE:
1286 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
1287 case PM_INTERPOLATED_STRING_NODE:
1288 case PM_RATIONAL_NODE:
1289 case PM_REGULAR_EXPRESSION_NODE:
1290 case PM_SOURCE_ENCODING_NODE:
1291 case PM_SOURCE_FILE_NODE:
1292 case PM_SOURCE_LINE_NODE:
1293 case PM_STRING_NODE:
1294 case PM_SYMBOL_NODE:
1302 case PM_RANGE_NODE: {
1303 const pm_range_node_t *cast = (
const pm_range_node_t *) node;
1305 if (PM_NODE_FLAG_P(cast, PM_RANGE_FLAGS_EXCLUDE_END)) {
1328 PM_PARSER_WARN_NODE_FORMAT(parser, node, PM_WARN_VOID_STATEMENT, length,
type);
1337pm_void_statements_check(
pm_parser_t *parser,
const pm_statements_node_t *node,
bool last_value) {
1339 const size_t size = node->
body.
size - (last_value ? 1 : 0);
1340 for (
size_t index = 0; index < size; index++) {
1341 pm_void_statement_check(parser, node->
body.
nodes[index]);
1351 PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL,
1352 PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP,
1353 PM_CONDITIONAL_PREDICATE_TYPE_NOT
1354} pm_conditional_predicate_type_t;
1360pm_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) {
1362 case PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL:
1363 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"condition");
1365 case PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP:
1366 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"flip-flop");
1368 case PM_CONDITIONAL_PREDICATE_TYPE_NOT:
1378pm_conditional_predicate_warn_write_literal_p(
const pm_node_t *node) {
1379 switch (PM_NODE_TYPE(node)) {
1380 case PM_ARRAY_NODE: {
1381 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1383 const pm_array_node_t *cast = (
const pm_array_node_t *) node;
1384 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1385 if (!pm_conditional_predicate_warn_write_literal_p(cast->
elements.
nodes[index]))
return false;
1390 case PM_HASH_NODE: {
1391 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1393 const pm_hash_node_t *cast = (
const pm_hash_node_t *) node;
1394 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1396 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE))
return false;
1398 const pm_assoc_node_t *assoc = (
const pm_assoc_node_t *) element;
1399 if (!pm_conditional_predicate_warn_write_literal_p(assoc->
key) || !pm_conditional_predicate_warn_write_literal_p(assoc->
value))
return false;
1406 case PM_IMAGINARY_NODE:
1407 case PM_INTEGER_NODE:
1409 case PM_RATIONAL_NODE:
1410 case PM_REGULAR_EXPRESSION_NODE:
1411 case PM_SOURCE_ENCODING_NODE:
1412 case PM_SOURCE_FILE_NODE:
1413 case PM_SOURCE_LINE_NODE:
1414 case PM_STRING_NODE:
1415 case PM_SYMBOL_NODE:
1428pm_conditional_predicate_warn_write_literal(
pm_parser_t *parser,
const pm_node_t *node) {
1429 if (pm_conditional_predicate_warn_write_literal_p(node)) {
1447pm_conditional_predicate(
pm_parser_t *parser, pm_node_t *node, pm_conditional_predicate_type_t
type) {
1448 switch (PM_NODE_TYPE(node)) {
1450 pm_and_node_t *cast = (pm_and_node_t *) node;
1451 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1452 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1456 pm_or_node_t *cast = (pm_or_node_t *) node;
1457 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1458 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1461 case PM_PARENTHESES_NODE: {
1462 pm_parentheses_node_t *cast = (pm_parentheses_node_t *) node;
1464 if ((cast->
body != NULL) && PM_NODE_TYPE_P(cast->
body, PM_STATEMENTS_NODE)) {
1465 pm_statements_node_t *statements = (pm_statements_node_t *) cast->
body;
1466 if (statements->body.size == 1) pm_conditional_predicate(parser, statements->body.nodes[0],
type);
1471 case PM_BEGIN_NODE: {
1472 pm_begin_node_t *cast = (pm_begin_node_t *) node;
1474 pm_statements_node_t *statements = cast->
statements;
1479 case PM_RANGE_NODE: {
1480 pm_range_node_t *cast = (pm_range_node_t *) node;
1482 if (cast->
left != NULL) pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1483 if (cast->
right != NULL) pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1490 assert(
sizeof(pm_range_node_t) ==
sizeof(pm_flip_flop_node_t));
1491 node->
type = PM_FLIP_FLOP_NODE;
1495 case PM_REGULAR_EXPRESSION_NODE:
1499 assert(
sizeof(pm_regular_expression_node_t) ==
sizeof(pm_match_last_line_node_t));
1500 node->
type = PM_MATCH_LAST_LINE_NODE;
1502 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1503 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"regex ");
1507 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
1511 assert(
sizeof(pm_interpolated_regular_expression_node_t) ==
sizeof(pm_interpolated_match_last_line_node_t));
1512 node->
type = PM_INTERPOLATED_MATCH_LAST_LINE_NODE;
1514 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1515 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"regex ");
1519 case PM_INTEGER_NODE:
1520 if (
type == PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP) {
1521 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1522 pm_parser_warn_node(parser, node, PM_WARN_INTEGER_IN_FLIP_FLOP);
1525 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1528 case PM_STRING_NODE:
1529 case PM_SOURCE_FILE_NODE:
1530 case PM_INTERPOLATED_STRING_NODE:
1531 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"string ");
1533 case PM_SYMBOL_NODE:
1534 case PM_INTERPOLATED_SYMBOL_NODE:
1535 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"symbol ");
1537 case PM_SOURCE_LINE_NODE:
1538 case PM_SOURCE_ENCODING_NODE:
1540 case PM_RATIONAL_NODE:
1541 case PM_IMAGINARY_NODE:
1542 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1544 case PM_CLASS_VARIABLE_WRITE_NODE:
1545 pm_conditional_predicate_warn_write_literal(parser, ((pm_class_variable_write_node_t *) node)->value);
1547 case PM_CONSTANT_WRITE_NODE:
1548 pm_conditional_predicate_warn_write_literal(parser, ((pm_constant_write_node_t *) node)->value);
1550 case PM_GLOBAL_VARIABLE_WRITE_NODE:
1551 pm_conditional_predicate_warn_write_literal(parser, ((pm_global_variable_write_node_t *) node)->value);
1553 case PM_INSTANCE_VARIABLE_WRITE_NODE:
1554 pm_conditional_predicate_warn_write_literal(parser, ((pm_instance_variable_write_node_t *) node)->value);
1556 case PM_LOCAL_VARIABLE_WRITE_NODE:
1557 pm_conditional_predicate_warn_write_literal(parser, ((pm_local_variable_write_node_t *) node)->value);
1559 case PM_MULTI_WRITE_NODE:
1560 pm_conditional_predicate_warn_write_literal(parser, ((pm_multi_write_node_t *) node)->value);
1577 return (
pm_token_t) { .type = PM_TOKEN_NOT_PROVIDED, .start = parser->
start, .end = parser->
start };
1606static inline const uint8_t *
1608 if (arguments->
block != NULL) {
1649 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_UNEXPECTED_BLOCK);
1663char_is_identifier_start(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
1664 if (n <= 0)
return 0;
1671 }
else if (*b ==
'_') {
1673 }
else if (*b >= 0x80) {
1678 }
else if (*b < 0x80) {
1681 return pm_encoding_utf_8_char_width(b, n);
1690char_is_identifier_utf8(
const uint8_t *b, ptrdiff_t n) {
1693 }
else if (*b < 0x80) {
1696 return pm_encoding_utf_8_char_width(b, n);
1706char_is_identifier(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
1714 }
else if (*b ==
'_') {
1716 }
else if (*b >= 0x80) {
1722 return char_is_identifier_utf8(b, n);
1729#define BIT(c, idx) (((c) / 32 - 1 == idx) ? (1U << ((c) % 32)) : 0)
1730#define PUNCT(idx) ( \
1731 BIT('~', idx) | BIT('*', idx) | BIT('$', idx) | BIT('?', idx) | \
1732 BIT('!', idx) | BIT('@', idx) | BIT('/', idx) | BIT('\\', idx) | \
1733 BIT(';', idx) | BIT(',', idx) | BIT('.', idx) | BIT('=', idx) | \
1734 BIT(':', idx) | BIT('<', idx) | BIT('>', idx) | BIT('\"', idx) | \
1735 BIT('&', idx) | BIT('`', idx) | BIT('\'', idx) | BIT('+', idx) | \
1738const unsigned int pm_global_name_punctuation_hash[(0x7e - 0x20 + 31) / 32] = { PUNCT(0), PUNCT(1), PUNCT(2) };
1744char_is_global_name_punctuation(const uint8_t b) {
1745 const unsigned int i = (const unsigned int) b;
1746 if (i <= 0x20 || 0x7e < i) return false;
1748 return (pm_global_name_punctuation_hash[(i - 0x20) / 32] >> (i % 32)) & 1;
1752token_is_setter_name(pm_token_t *token) {
1754 (token->type == PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL) ||
1755 ((token->type == PM_TOKEN_IDENTIFIER) &&
1756 (token->end - token->start >= 2) &&
1757 (token->end[-1] == '='))
1765pm_local_is_keyword(const char *source, size_t length) {
1766#define KEYWORD(name) if (memcmp(source, name, length) == 0) return true
1770 switch (source[0]) {
1771 case 'd': KEYWORD("do"); return false;
1772 case 'i': KEYWORD("if"); KEYWORD("in"); return false;
1773 case 'o': KEYWORD("or"); return false;
1774 default: return false;
1777 switch (source[0]) {
1778 case 'a': KEYWORD("and"); return false;
1779 case 'd': KEYWORD("def"); return false;
1780 case 'e': KEYWORD("end"); return false;
1781 case 'f': KEYWORD("for"); return false;
1782 case 'n': KEYWORD("nil"); KEYWORD("not"); return false;
1783 default: return false;
1786 switch (source[0]) {
1787 case 'c': KEYWORD("case"); return false;
1788 case 'e': KEYWORD("else"); return false;
1789 case 'n': KEYWORD("next"); return false;
1790 case 'r': KEYWORD("redo"); return false;
1791 case 's': KEYWORD("self"); return false;
1792 case 't': KEYWORD("then"); KEYWORD("true"); return false;
1793 case 'w': KEYWORD("when"); return false;
1794 default: return false;
1797 switch (source[0]) {
1798 case 'a': KEYWORD("alias"); return false;
1799 case 'b': KEYWORD("begin"); KEYWORD("break"); return false;
1800 case 'c': KEYWORD("class"); return false;
1801 case 'e': KEYWORD("elsif"); return false;
1802 case 'f': KEYWORD("false"); return false;
1803 case 'r': KEYWORD("retry"); return false;
1804 case 's': KEYWORD("super"); return false;
1805 case 'u': KEYWORD("undef"); KEYWORD("until"); return false;
1806 case 'w': KEYWORD("while"); return false;
1807 case 'y': KEYWORD("yield"); return false;
1808 default: return false;
1811 switch (source[0]) {
1812 case 'e': KEYWORD("ensure"); return false;
1813 case 'm': KEYWORD("module"); return false;
1814 case 'r': KEYWORD("rescue"); KEYWORD("return"); return false;
1815 case 'u': KEYWORD("unless"); return false;
1816 default: return false;
1819 KEYWORD("__LINE__");
1820 KEYWORD("__FILE__");
1823 KEYWORD("__ENCODING__");
1832/******************************************************************************/
1833/* Node flag handling functions */
1834/******************************************************************************/
1840pm_node_flag_set(pm_node_t *node, pm_node_flags_t flag) {
1841 node->flags |= flag;
1848pm_node_flag_unset(pm_node_t *node, pm_node_flags_t flag) {
1849 node->flags &= (pm_node_flags_t) ~flag;
1856pm_node_flag_set_repeated_parameter(pm_node_t *node) {
1857 assert(PM_NODE_TYPE(node) == PM_BLOCK_LOCAL_VARIABLE_NODE ||
1858 PM_NODE_TYPE(node) == PM_BLOCK_PARAMETER_NODE ||
1859 PM_NODE_TYPE(node) == PM_KEYWORD_REST_PARAMETER_NODE ||
1860 PM_NODE_TYPE(node) == PM_OPTIONAL_KEYWORD_PARAMETER_NODE ||
1861 PM_NODE_TYPE(node) == PM_OPTIONAL_PARAMETER_NODE ||
1862 PM_NODE_TYPE(node) == PM_REQUIRED_KEYWORD_PARAMETER_NODE ||
1863 PM_NODE_TYPE(node) == PM_REQUIRED_PARAMETER_NODE ||
1864 PM_NODE_TYPE(node) == PM_REST_PARAMETER_NODE);
1866 pm_node_flag_set(node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER);
1869/******************************************************************************/
1870/* Node creation functions */
1871/******************************************************************************/
1878#define PM_REGULAR_EXPRESSION_ENCODING_MASK ~(PM_REGULAR_EXPRESSION_FLAGS_EUC_JP | PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J | PM_REGULAR_EXPRESSION_FLAGS_UTF_8)
1883static inline pm_node_flags_t
1884pm_regular_expression_flags_create(pm_parser_t *parser, const pm_token_t *closing) {
1885 pm_node_flags_t flags = 0;
1887 if (closing->type == PM_TOKEN_REGEXP_END) {
1888 pm_buffer_t unknown_flags = { 0 };
1890 for (const uint8_t *flag = closing->start + 1; flag < closing->end; flag++) {
1892 case 'i': flags |= PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE; break;
1893 case 'm': flags |= PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE; break;
1894 case 'x': flags |= PM_REGULAR_EXPRESSION_FLAGS_EXTENDED; break;
1895 case 'o': flags |= PM_REGULAR_EXPRESSION_FLAGS_ONCE; break;
1897 case 'e': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_EUC_JP); break;
1898 case 'n': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT); break;
1899 case 's': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J); break;
1900 case 'u': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_UTF_8); break;
1902 default: pm_buffer_append_byte(&unknown_flags, *flag);
1906 size_t unknown_flags_length = pm_buffer_length(&unknown_flags);
1907 if (unknown_flags_length != 0) {
1908 const char *word = unknown_flags_length >= 2 ? "options" : "option";
1909 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, PM_ERR_REGEXP_UNKNOWN_OPTIONS, word, unknown_flags_length, pm_buffer_value(&unknown_flags));
1911 pm_buffer_free(&unknown_flags);
1917#undef PM_REGULAR_EXPRESSION_ENCODING_MASK
1919static pm_statements_node_t *
1920pm_statements_node_create(pm_parser_t *parser);
1923pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline);
1926pm_statements_node_body_length(pm_statements_node_t *node);
1933pm_node_alloc(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, size_t size) {
1934 void *memory = xcalloc(1, size);
1935 if (memory == NULL) {
1936 fprintf(stderr, "Failed to allocate %d bytes\n", (int) size);
1942#define PM_NODE_ALLOC(parser_, type_) (type_ *) pm_node_alloc(parser_, sizeof(type_))
1943#define PM_NODE_INIT(parser_, type_, flags_, start_, end_) (pm_node_t) { \
1945 .flags = (flags_), \
1946 .node_id = ++(parser_)->node_id, \
1947 .location = { .start = (start_), .end = (end_) } \
1950#define PM_NODE_INIT_UNSET(parser_, type_, flags_) PM_NODE_INIT(parser_, type_, flags_, NULL, NULL)
1951#define PM_NODE_INIT_BASE(parser_, type_, flags_) PM_NODE_INIT(parser_, type_, flags_, (parser_)->start, (parser_)->start)
1952#define PM_NODE_INIT_TOKEN(parser_, type_, flags_, token_) PM_NODE_INIT(parser_, type_, flags_, PM_TOKEN_START(token_), PM_TOKEN_END(token_))
1953#define PM_NODE_INIT_NODE(parser_, type_, flags_, node_) PM_NODE_INIT(parser_, type_, flags_, PM_NODE_START(node_), PM_NODE_END(node_))
1955#define PM_NODE_INIT_TOKENS(parser_, type_, flags_, left_, right_) PM_NODE_INIT(parser_, type_, flags_, PM_TOKEN_START(left_), PM_TOKEN_END(right_))
1956#define PM_NODE_INIT_NODES(parser_, type_, flags_, left_, right_) PM_NODE_INIT(parser_, type_, flags_, PM_NODE_START(left_), PM_NODE_END(right_))
1957#define PM_NODE_INIT_TOKEN_NODE(parser_, type_, flags_, token_, node_) PM_NODE_INIT(parser_, type_, flags_, PM_TOKEN_START(token_), PM_NODE_END(node_))
1958#define PM_NODE_INIT_NODE_TOKEN(parser_, type_, flags_, node_, token_) PM_NODE_INIT(parser_, type_, flags_, PM_NODE_START(node_), PM_TOKEN_END(token_))
1963static pm_missing_node_t *
1964pm_missing_node_create(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
1965 pm_missing_node_t *node = PM_NODE_ALLOC(parser, pm_missing_node_t);
1967 *node = (pm_missing_node_t) {
1968 .base = PM_NODE_INIT(parser, PM_MISSING_NODE, 0, start, end)
1977static pm_alias_global_variable_node_t *
1978pm_alias_global_variable_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
1979 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
1980 pm_alias_global_variable_node_t *node = PM_NODE_ALLOC(parser, pm_alias_global_variable_node_t);
1982 *node = (pm_alias_global_variable_node_t) {
1983 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_ALIAS_GLOBAL_VARIABLE_NODE, 0, keyword, old_name),
1984 .new_name = new_name,
1985 .old_name = old_name,
1986 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
1995static pm_alias_method_node_t *
1996pm_alias_method_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
1997 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
1998 pm_alias_method_node_t *node = PM_NODE_ALLOC(parser, pm_alias_method_node_t);
2000 *node = (pm_alias_method_node_t) {
2001 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_ALIAS_METHOD_NODE, 0, keyword, old_name),
2002 .new_name = new_name,
2003 .old_name = old_name,
2004 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
2013static pm_alternation_pattern_node_t *
2014pm_alternation_pattern_node_create(pm_parser_t *parser, pm_node_t *left, pm_node_t *right, const pm_token_t *operator) {
2015 pm_alternation_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_alternation_pattern_node_t);
2017 *node = (pm_alternation_pattern_node_t) {
2018 .base = PM_NODE_INIT_NODES(parser, PM_ALTERNATION_PATTERN_NODE, 0, left, right),
2021 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2030static pm_and_node_t *
2031pm_and_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
2032 pm_assert_value_expression(parser, left);
2034 pm_and_node_t *node = PM_NODE_ALLOC(parser, pm_and_node_t);
2036 *node = (pm_and_node_t) {
2037 .base = PM_NODE_INIT_NODES(parser, PM_AND_NODE, 0, left, right),
2039 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2049static pm_arguments_node_t *
2050pm_arguments_node_create(pm_parser_t *parser) {
2051 pm_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_arguments_node_t);
2053 *node = (pm_arguments_node_t) {
2054 .base = PM_NODE_INIT_BASE(parser, PM_ARGUMENTS_NODE, 0),
2065pm_arguments_node_size(pm_arguments_node_t *node) {
2066 return node->arguments.size;
2073pm_arguments_node_arguments_append(pm_arguments_node_t *node, pm_node_t *argument) {
2074 if (pm_arguments_node_size(node) == 0) {
2075 node->base.location.start = argument->location.start;
2078 if (node->base.location.end < argument->location.end) {
2079 node->base.location.end = argument->location.end;
2082 pm_node_list_append(&node->arguments, argument);
2084 if (PM_NODE_TYPE_P(argument, PM_SPLAT_NODE)) {
2085 if (PM_NODE_FLAG_P(node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
2086 pm_node_flag_set(UP(node), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS);
2088 pm_node_flag_set(UP(node), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT);
2096static pm_array_node_t *
2097pm_array_node_create(pm_parser_t *parser, const pm_token_t *opening) {
2098 pm_array_node_t *node = PM_NODE_ALLOC(parser, pm_array_node_t);
2100 *node = (pm_array_node_t) {
2101 .base = PM_NODE_INIT_TOKEN(parser, PM_ARRAY_NODE, PM_NODE_FLAG_STATIC_LITERAL, opening),
2102 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2103 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2114pm_array_node_elements_append(pm_array_node_t *node, pm_node_t *element) {
2115 if (!node->elements.size && !node->opening_loc.start) {
2116 node->base.location.start = element->location.start;
2119 pm_node_list_append(&node->elements, element);
2120 node->base.location.end = element->location.end;
2122 // If the element is not a static literal, then the array is not a static
2123 // literal. Turn that flag off.
2124 if (PM_NODE_TYPE_P(element, PM_ARRAY_NODE) || PM_NODE_TYPE_P(element, PM_HASH_NODE) || PM_NODE_TYPE_P(element, PM_RANGE_NODE) || !PM_NODE_FLAG_P(element, PM_NODE_FLAG_STATIC_LITERAL)) {
2125 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
2128 if (PM_NODE_TYPE_P(element, PM_SPLAT_NODE)) {
2129 pm_node_flag_set(UP(node), PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT);
2137pm_array_node_close_set(pm_array_node_t *node, const pm_token_t *closing) {
2138 assert(closing->type == PM_TOKEN_BRACKET_RIGHT || closing->type == PM_TOKEN_STRING_END || closing->type == PM_TOKEN_MISSING || closing->type == PM_TOKEN_NOT_PROVIDED);
2139 node->base.location.end = closing->end;
2140 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
2147static pm_array_pattern_node_t *
2148pm_array_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *nodes) {
2149 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2151 *node = (pm_array_pattern_node_t) {
2152 .base = PM_NODE_INIT_NODES(parser, PM_ARRAY_PATTERN_NODE, 0, nodes->nodes[0], nodes->nodes[nodes->size - 1]),
2157 .opening_loc = { 0 },
2158 .closing_loc = { 0 }
2161 // For now we're going to just copy over each pointer manually. This could be
2162 // much more efficient, as we could instead resize the node list.
2163 bool found_rest = false;
2166 PM_NODE_LIST_FOREACH(nodes, index, child) {
2167 if (!found_rest && (PM_NODE_TYPE_P(child, PM_SPLAT_NODE) || PM_NODE_TYPE_P(child, PM_IMPLICIT_REST_NODE))) {
2170 } else if (found_rest) {
2171 pm_node_list_append(&node->posts, child);
2173 pm_node_list_append(&node->requireds, child);
2183static pm_array_pattern_node_t *
2184pm_array_pattern_node_rest_create(pm_parser_t *parser, pm_node_t *rest) {
2185 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2187 *node = (pm_array_pattern_node_t) {
2188 .base = PM_NODE_INIT_NODE(parser, PM_ARRAY_PATTERN_NODE, 0, rest),
2193 .opening_loc = { 0 },
2194 .closing_loc = { 0 }
2204static pm_array_pattern_node_t *
2205pm_array_pattern_node_constant_create(pm_parser_t *parser, pm_node_t *constant, const pm_token_t *opening, const pm_token_t *closing) {
2206 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2208 *node = (pm_array_pattern_node_t) {
2209 .base = PM_NODE_INIT_NODE_TOKEN(parser, PM_ARRAY_PATTERN_NODE, 0, constant, closing),
2210 .constant = constant,
2212 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2213 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
2225static pm_array_pattern_node_t *
2226pm_array_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
2227 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2229 *node = (pm_array_pattern_node_t) {
2230 .base = PM_NODE_INIT_TOKENS(parser, PM_ARRAY_PATTERN_NODE, 0, opening, closing),
2233 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2234 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
2243pm_array_pattern_node_requireds_append(pm_array_pattern_node_t *node, pm_node_t *inner) {
2244 pm_node_list_append(&node->requireds, inner);
2250static pm_assoc_node_t *
2251pm_assoc_node_create(pm_parser_t *parser, pm_node_t *key, const pm_token_t *operator, pm_node_t *value) {
2252 pm_assoc_node_t *node = PM_NODE_ALLOC(parser, pm_assoc_node_t);
2255 if (value != NULL && value->location.end > key->location.end) {
2256 end = value->location.end;
2257 } else if (operator->type != PM_TOKEN_NOT_PROVIDED) {
2258 end = operator->end;
2260 end = key->location.end;
2263 // Hash string keys will be frozen, so we can mark them as frozen here so
2264 // that the compiler picks them up and also when we check for static literal
2265 // on the keys it gets factored in.
2266 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
2267 key->flags |= PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL;
2270 // If the key and value of this assoc node are both static literals, then
2271 // we can mark this node as a static literal.
2272 pm_node_flags_t flags = 0;
2274 !PM_NODE_TYPE_P(key, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(key, PM_HASH_NODE) && !PM_NODE_TYPE_P(key, PM_RANGE_NODE) &&
2275 value && !PM_NODE_TYPE_P(value, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(value, PM_HASH_NODE) && !PM_NODE_TYPE_P(value, PM_RANGE_NODE)
2277 flags = key->flags & value->flags & PM_NODE_FLAG_STATIC_LITERAL;
2280 *node = (pm_assoc_node_t) {
2281 .base = PM_NODE_INIT(parser, PM_ASSOC_NODE, flags, key->location.start, end),
2283 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
2293static pm_assoc_splat_node_t *
2294pm_assoc_splat_node_create(pm_parser_t *parser, pm_node_t *value, const pm_token_t *operator) {
2295 assert(operator->type == PM_TOKEN_USTAR_STAR);
2296 pm_assoc_splat_node_t *node = PM_NODE_ALLOC(parser, pm_assoc_splat_node_t);
2298 *node = (pm_assoc_splat_node_t) {
2301 ? PM_NODE_INIT_TOKEN(parser, PM_ASSOC_SPLAT_NODE, 0, operator)
2302 : PM_NODE_INIT_TOKEN_NODE(parser, PM_ASSOC_SPLAT_NODE, 0, operator, value)
2305 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2314static pm_back_reference_read_node_t *
2315pm_back_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
2316 assert(name->type == PM_TOKEN_BACK_REFERENCE);
2317 pm_back_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_back_reference_read_node_t);
2319 *node = (pm_back_reference_read_node_t) {
2320 .base = PM_NODE_INIT_TOKEN(parser, PM_BACK_REFERENCE_READ_NODE, 0, name),
2321 .name = pm_parser_constant_id_token(parser, name)
2330static pm_begin_node_t *
2331pm_begin_node_create(pm_parser_t *parser, const pm_token_t *begin_keyword, pm_statements_node_t *statements) {
2332 pm_begin_node_t *node = PM_NODE_ALLOC(parser, pm_begin_node_t);
2334 *node = (pm_begin_node_t) {
2336 (statements == NULL)
2337 ? PM_NODE_INIT_TOKEN(parser, PM_BEGIN_NODE, 0, begin_keyword)
2338 : PM_NODE_INIT_TOKEN_NODE(parser, PM_BEGIN_NODE, 0, begin_keyword, statements)
2340 .begin_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(begin_keyword),
2341 .statements = statements,
2342 .end_keyword_loc = { 0 }
2352pm_begin_node_rescue_clause_set(pm_begin_node_t *node, pm_rescue_node_t *rescue_clause) {
2353 // If the begin keyword doesn't exist, we set the start on the begin_node
2354 if (!node->begin_keyword_loc.start) {
2355 node->base.location.start = rescue_clause->base.location.start;
2357 node->base.location.end = rescue_clause->base.location.end;
2358 node->rescue_clause = rescue_clause;
2365pm_begin_node_else_clause_set(pm_begin_node_t *node, pm_else_node_t *else_clause) {
2366 node->base.location.end = else_clause->base.location.end;
2367 node->else_clause = else_clause;
2374pm_begin_node_ensure_clause_set(pm_begin_node_t *node, pm_ensure_node_t *ensure_clause) {
2375 node->base.location.end = ensure_clause->base.location.end;
2376 node->ensure_clause = ensure_clause;
2383pm_begin_node_end_keyword_set(pm_begin_node_t *node, const pm_token_t *end_keyword) {
2384 assert(end_keyword->type == PM_TOKEN_KEYWORD_END || end_keyword->type == PM_TOKEN_MISSING);
2386 node->base.location.end = end_keyword->end;
2387 node->end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword);
2393static pm_block_argument_node_t *
2394pm_block_argument_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
2395 pm_block_argument_node_t *node = PM_NODE_ALLOC(parser, pm_block_argument_node_t);
2397 *node = (pm_block_argument_node_t) {
2399 (expression == NULL)
2400 ? PM_NODE_INIT_TOKEN(parser, PM_BLOCK_ARGUMENT_NODE, 0, operator)
2401 : PM_NODE_INIT_TOKEN_NODE(parser, PM_BLOCK_ARGUMENT_NODE, 0, operator, expression)
2403 .expression = expression,
2404 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2413static pm_block_node_t *
2414pm_block_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const pm_token_t *opening, pm_node_t *parameters, pm_node_t *body, const pm_token_t *closing) {
2415 pm_block_node_t *node = PM_NODE_ALLOC(parser, pm_block_node_t);
2417 *node = (pm_block_node_t) {
2418 .base = PM_NODE_INIT_TOKENS(parser, PM_BLOCK_NODE, 0, opening, closing),
2420 .parameters = parameters,
2422 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2423 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
2432static pm_block_parameter_node_t *
2433pm_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator) {
2434 assert(operator->type == PM_TOKEN_NOT_PROVIDED || operator->type == PM_TOKEN_UAMPERSAND || operator->type == PM_TOKEN_AMPERSAND);
2435 pm_block_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_block_parameter_node_t);
2437 *node = (pm_block_parameter_node_t) {
2439 (name->type == PM_TOKEN_NOT_PROVIDED)
2440 ? PM_NODE_INIT_TOKEN(parser, PM_BLOCK_PARAMETER_NODE, 0, operator)
2441 : PM_NODE_INIT_TOKENS(parser, PM_BLOCK_PARAMETER_NODE, 0, operator, name)
2443 .name = pm_parser_optional_constant_id_token(parser, name),
2444 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
2445 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2454static pm_block_parameters_node_t *
2455pm_block_parameters_node_create(pm_parser_t *parser, pm_parameters_node_t *parameters, const pm_token_t *opening) {
2456 pm_block_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_block_parameters_node_t);
2458 const uint8_t *start;
2459 if (opening->type != PM_TOKEN_NOT_PROVIDED) {
2460 start = opening->start;
2461 } else if (parameters != NULL) {
2462 start = parameters->base.location.start;
2468 if (parameters != NULL) {
2469 end = parameters->base.location.end;
2470 } else if (opening->type != PM_TOKEN_NOT_PROVIDED) {
2476 *node = (pm_block_parameters_node_t) {
2477 .base = PM_NODE_INIT(parser, PM_BLOCK_PARAMETERS_NODE, 0, start, end),
2478 .parameters = parameters,
2479 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2480 .closing_loc = { 0 },
2491pm_block_parameters_node_closing_set(pm_block_parameters_node_t *node, const pm_token_t *closing) {
2492 assert(closing->type == PM_TOKEN_PIPE || closing->type == PM_TOKEN_PARENTHESIS_RIGHT || closing->type == PM_TOKEN_MISSING);
2494 node->base.location.end = closing->end;
2495 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
2501static pm_block_local_variable_node_t *
2502pm_block_local_variable_node_create(pm_parser_t *parser, const pm_token_t *name) {
2503 pm_block_local_variable_node_t *node = PM_NODE_ALLOC(parser, pm_block_local_variable_node_t);
2505 *node = (pm_block_local_variable_node_t) {
2506 .base = PM_NODE_INIT_TOKEN(parser, PM_BLOCK_LOCAL_VARIABLE_NODE, 0, name),
2507 .name = pm_parser_constant_id_token(parser, name)
2517pm_block_parameters_node_append_local(pm_block_parameters_node_t *node, const pm_block_local_variable_node_t *local) {
2518 pm_node_list_append(&node->locals, UP(local));
2520 if (node->base.location.start == NULL) node->base.location.start = local->base.location.start;
2521 node->base.location.end = local->base.location.end;
2527static pm_break_node_t *
2528pm_break_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
2529 assert(keyword->type == PM_TOKEN_KEYWORD_BREAK);
2530 pm_break_node_t *node = PM_NODE_ALLOC(parser, pm_break_node_t);
2532 *node = (pm_break_node_t) {
2535 ? PM_NODE_INIT_TOKEN(parser, PM_BREAK_NODE, 0, keyword)
2536 : PM_NODE_INIT_TOKEN_NODE(parser, PM_BREAK_NODE, 0, keyword, arguments)
2538 .arguments = arguments,
2539 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
2545// There are certain flags that we want to use internally but don't want to
2546// expose because they are not relevant beyond parsing. Therefore we'll define
2547// them here and not define them in config.yml/a header file.
2548static const pm_node_flags_t PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY = (1 << 2);
2550static const pm_node_flags_t PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY = ((PM_CALL_NODE_FLAGS_LAST - 1) << 1);
2551static const pm_node_flags_t PM_CALL_NODE_FLAGS_COMPARISON = ((PM_CALL_NODE_FLAGS_LAST - 1) << 2);
2552static const pm_node_flags_t PM_CALL_NODE_FLAGS_INDEX = ((PM_CALL_NODE_FLAGS_LAST - 1) << 3);
2559static pm_call_node_t *
2560pm_call_node_create(pm_parser_t *parser, pm_node_flags_t flags) {
2561 pm_call_node_t *node = PM_NODE_ALLOC(parser, pm_call_node_t);
2563 *node = (pm_call_node_t) {
2564 .base = PM_NODE_INIT_BASE(parser, PM_CALL_NODE, flags),
2566 .call_operator_loc = { 0 },
2567 .message_loc = { 0 },
2568 .opening_loc = { 0 },
2570 .closing_loc = { 0 },
2583static inline pm_node_flags_t
2584pm_call_node_ignore_visibility_flag(const pm_node_t *receiver) {
2585 return PM_NODE_TYPE_P(receiver, PM_SELF_NODE) ? PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY : 0;
2592static pm_call_node_t *
2593pm_call_node_aref_create(pm_parser_t *parser, pm_node_t *receiver, pm_arguments_t *arguments) {
2594 pm_assert_value_expression(parser, receiver);
2596 pm_node_flags_t flags = pm_call_node_ignore_visibility_flag(receiver);
2597 if (arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_ARGUMENT_NODE)) {
2598 flags |= PM_CALL_NODE_FLAGS_INDEX;
2601 pm_call_node_t *node = pm_call_node_create(parser, flags);
2603 node->base.location.start = receiver->location.start;
2604 node->base.location.end = pm_arguments_end(arguments);
2606 node->receiver = receiver;
2607 node->message_loc.start = arguments->opening_loc.start;
2608 node->message_loc.end = arguments->closing_loc.end;
2610 node->opening_loc = arguments->opening_loc;
2611 node->arguments = arguments->arguments;
2612 node->closing_loc = arguments->closing_loc;
2613 node->block = arguments->block;
2615 node->name = pm_parser_constant_id_constant(parser, "[]", 2);
2622static pm_call_node_t *
2623pm_call_node_binary_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_node_t *argument, pm_node_flags_t flags) {
2624 pm_assert_value_expression(parser, receiver);
2625 pm_assert_value_expression(parser, argument);
2627 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver) | flags);
2629 node->base.location.start = MIN(receiver->location.start, argument->location.start);
2630 node->base.location.end = MAX(receiver->location.end, argument->location.end);
2632 node->receiver = receiver;
2633 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2635 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
2636 pm_arguments_node_arguments_append(arguments, argument);
2637 node->arguments = arguments;
2639 node->name = pm_parser_constant_id_token(parser, operator);
2643static const uint8_t * parse_operator_symbol_name(const pm_token_t *);
2648static pm_call_node_t *
2649pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_token_t *message, pm_arguments_t *arguments) {
2650 pm_assert_value_expression(parser, receiver);
2652 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2654 node->base.location.start = receiver->location.start;
2655 const uint8_t *end = pm_arguments_end(arguments);
2659 node->base.location.end = end;
2661 node->receiver = receiver;
2662 node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2663 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2664 node->opening_loc = arguments->opening_loc;
2665 node->arguments = arguments->arguments;
2666 node->closing_loc = arguments->closing_loc;
2667 node->block = arguments->block;
2669 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2670 pm_node_flag_set(UP(node), PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2677 node->name = pm_parser_constant_id_location(parser, message->start, parse_operator_symbol_name(message));
2684static pm_call_node_t *
2685pm_call_node_call_synthesized_create(pm_parser_t *parser, pm_node_t *receiver, const char *message, pm_arguments_node_t *arguments) {
2686 pm_call_node_t *node = pm_call_node_create(parser, 0);
2687 node->base.location.start = parser->start;
2688 node->base.location.end = parser->end;
2690 node->receiver = receiver;
2691 node->call_operator_loc = (pm_location_t) { .start = NULL, .end = NULL };
2692 node->message_loc = (pm_location_t) { .start = NULL, .end = NULL };
2693 node->arguments = arguments;
2695 node->name = pm_parser_constant_id_constant(parser, message, strlen(message));
2703static pm_call_node_t *
2704pm_call_node_fcall_create(pm_parser_t *parser, pm_token_t *message, pm_arguments_t *arguments) {
2705 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2707 node->base.location.start = message->start;
2708 node->base.location.end = pm_arguments_end(arguments);
2710 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2711 node->opening_loc = arguments->opening_loc;
2712 node->arguments = arguments->arguments;
2713 node->closing_loc = arguments->closing_loc;
2714 node->block = arguments->block;
2716 node->name = pm_parser_constant_id_token(parser, message);
2724static pm_call_node_t *
2725pm_call_node_fcall_synthesized_create(pm_parser_t *parser, pm_arguments_node_t *arguments, pm_constant_id_t name) {
2726 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2728 node->base.location = PM_LOCATION_NULL_VALUE(parser);
2729 node->arguments = arguments;
2738static pm_call_node_t *
2739pm_call_node_not_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *message, pm_arguments_t *arguments) {
2740 pm_assert_value_expression(parser, receiver);
2741 if (receiver != NULL) pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
2743 pm_call_node_t *node = pm_call_node_create(parser, receiver == NULL ? 0 : pm_call_node_ignore_visibility_flag(receiver));
2745 node->base.location.start = message->start;
2746 if (arguments->closing_loc.start != NULL) {
2747 node->base.location.end = arguments->closing_loc.end;
2749 assert(receiver != NULL);
2750 node->base.location.end = receiver->location.end;
2753 node->receiver = receiver;
2754 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2755 node->opening_loc = arguments->opening_loc;
2756 node->arguments = arguments->arguments;
2757 node->closing_loc = arguments->closing_loc;
2759 node->name = pm_parser_constant_id_constant(parser, "!", 1);
2766static pm_call_node_t *
2767pm_call_node_shorthand_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_arguments_t *arguments) {
2768 pm_assert_value_expression(parser, receiver);
2770 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2772 node->base.location.start = receiver->location.start;
2773 node->base.location.end = pm_arguments_end(arguments);
2775 node->receiver = receiver;
2776 node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2777 node->opening_loc = arguments->opening_loc;
2778 node->arguments = arguments->arguments;
2779 node->closing_loc = arguments->closing_loc;
2780 node->block = arguments->block;
2782 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2783 pm_node_flag_set(UP(node), PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2786 node->name = pm_parser_constant_id_constant(parser, "call", 4);
2793static pm_call_node_t *
2794pm_call_node_unary_create(pm_parser_t *parser, pm_token_t *operator, pm_node_t *receiver, const char *name) {
2795 pm_assert_value_expression(parser, receiver);
2797 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2799 node->base.location.start = operator->start;
2800 node->base.location.end = receiver->location.end;
2802 node->receiver = receiver;
2803 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2805 node->name = pm_parser_constant_id_constant(parser, name, strlen(name));
2813static pm_call_node_t *
2814pm_call_node_variable_call_create(pm_parser_t *parser, pm_token_t *message) {
2815 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2817 node->base.location = PM_LOCATION_TOKEN_VALUE(message);
2818 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2820 node->name = pm_parser_constant_id_token(parser, message);
2829pm_call_node_writable_p(const pm_parser_t *parser, const pm_call_node_t *node) {
2831 (node->message_loc.start != NULL) &&
2832 (node->message_loc.end[-1] != '!') &&
2833 (node->message_loc.end[-1] != '?') &&
2834 char_is_identifier_start(parser, node->message_loc.start, parser->end - node->message_loc.start) &&
2835 (node->opening_loc.start == NULL) &&
2836 (node->arguments == NULL) &&
2837 (node->block == NULL)
2845pm_call_write_read_name_init(pm_parser_t *parser, pm_constant_id_t *read_name, pm_constant_id_t *write_name) {
2846 pm_constant_t *write_constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *write_name);
2848 if (write_constant->length > 0) {
2849 size_t length = write_constant->length - 1;
2851 void *memory = xmalloc(length);
2852 memcpy(memory, write_constant->start, length);
2854 *read_name = pm_constant_pool_insert_owned(&parser->constant_pool, (uint8_t *) memory, length);
2856 // We can get here if the message was missing because of a syntax error.
2857 *read_name = pm_parser_constant_id_constant(parser, "", 0);
2864static pm_call_and_write_node_t *
2865pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2866 assert(target->block == NULL);
2867 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
2868 pm_call_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_and_write_node_t);
2870 *node = (pm_call_and_write_node_t) {
2871 .base = PM_NODE_INIT_NODES(parser, PM_CALL_AND_WRITE_NODE, FL(target), target, value),
2872 .receiver = target->receiver,
2873 .call_operator_loc = target->call_operator_loc,
2874 .message_loc = target->message_loc,
2876 .write_name = target->name,
2877 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2881 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
2883 // Here we're going to free the target, since it is no longer necessary.
2884 // However, we don't want to call `pm_node_destroy` because we want to keep
2885 // around all of its children since we just reused them.
2896pm_index_arguments_check(pm_parser_t *parser, const pm_arguments_node_t *arguments, const pm_node_t *block) {
2897 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) {
2898 if (arguments != NULL && PM_NODE_FLAG_P(arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) {
2900 PM_NODE_LIST_FOREACH(&arguments->arguments, index, node) {
2901 if (PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE)) {
2902 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_INDEX_KEYWORDS);
2908 if (block != NULL) {
2909 pm_parser_err_node(parser, block, PM_ERR_UNEXPECTED_INDEX_BLOCK);
2917static pm_index_and_write_node_t *
2918pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2919 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
2920 pm_index_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_and_write_node_t);
2922 pm_index_arguments_check(parser, target->arguments, target->block);
2924 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
2925 *node = (pm_index_and_write_node_t) {
2926 .base = PM_NODE_INIT_NODES(parser, PM_INDEX_AND_WRITE_NODE, FL(target), target, value),
2927 .receiver = target->receiver,
2928 .call_operator_loc = target->call_operator_loc,
2929 .opening_loc = target->opening_loc,
2930 .arguments = target->arguments,
2931 .closing_loc = target->closing_loc,
2932 .block = (pm_block_argument_node_t *) target->block,
2933 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2937 // Here we're going to free the target, since it is no longer necessary.
2938 // However, we don't want to call `pm_node_destroy` because we want to keep
2939 // around all of its children since we just reused them.
2948static pm_call_operator_write_node_t *
2949pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2950 assert(target->block == NULL);
2951 pm_call_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_operator_write_node_t);
2953 *node = (pm_call_operator_write_node_t) {
2954 .base = PM_NODE_INIT_NODES(parser, PM_CALL_OPERATOR_WRITE_NODE, FL(target), target, value),
2955 .receiver = target->receiver,
2956 .call_operator_loc = target->call_operator_loc,
2957 .message_loc = target->message_loc,
2959 .write_name = target->name,
2960 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
2961 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2965 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
2967 // Here we're going to free the target, since it is no longer necessary.
2968 // However, we don't want to call `pm_node_destroy` because we want to keep
2969 // around all of its children since we just reused them.
2978static pm_index_operator_write_node_t *
2979pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2980 pm_index_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_operator_write_node_t);
2982 pm_index_arguments_check(parser, target->arguments, target->block);
2984 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
2985 *node = (pm_index_operator_write_node_t) {
2986 .base = PM_NODE_INIT_NODES(parser, PM_INDEX_OPERATOR_WRITE_NODE, FL(target), target, value),
2987 .receiver = target->receiver,
2988 .call_operator_loc = target->call_operator_loc,
2989 .opening_loc = target->opening_loc,
2990 .arguments = target->arguments,
2991 .closing_loc = target->closing_loc,
2992 .block = (pm_block_argument_node_t *) target->block,
2993 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
2994 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2998 // Here we're going to free the target, since it is no longer necessary.
2999 // However, we don't want to call `pm_node_destroy` because we want to keep
3000 // around all of its children since we just reused them.
3009static pm_call_or_write_node_t *
3010pm_call_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3011 assert(target->block == NULL);
3012 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3013 pm_call_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_or_write_node_t);
3015 *node = (pm_call_or_write_node_t) {
3016 .base = PM_NODE_INIT_NODES(parser, PM_CALL_OR_WRITE_NODE, FL(target), target, value),
3017 .receiver = target->receiver,
3018 .call_operator_loc = target->call_operator_loc,
3019 .message_loc = target->message_loc,
3021 .write_name = target->name,
3022 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3026 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3028 // Here we're going to free the target, since it is no longer necessary.
3029 // However, we don't want to call `pm_node_destroy` because we want to keep
3030 // around all of its children since we just reused them.
3039static pm_index_or_write_node_t *
3040pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3041 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3042 pm_index_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_or_write_node_t);
3044 pm_index_arguments_check(parser, target->arguments, target->block);
3046 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3047 *node = (pm_index_or_write_node_t) {
3048 .base = PM_NODE_INIT_NODES(parser, PM_INDEX_OR_WRITE_NODE, FL(target), target, value),
3049 .receiver = target->receiver,
3050 .call_operator_loc = target->call_operator_loc,
3051 .opening_loc = target->opening_loc,
3052 .arguments = target->arguments,
3053 .closing_loc = target->closing_loc,
3054 .block = (pm_block_argument_node_t *) target->block,
3055 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3059 // Here we're going to free the target, since it is no longer necessary.
3060 // However, we don't want to call `pm_node_destroy` because we want to keep
3061 // around all of its children since we just reused them.
3071static pm_call_target_node_t *
3072pm_call_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3073 pm_call_target_node_t *node = PM_NODE_ALLOC(parser, pm_call_target_node_t);
3075 *node = (pm_call_target_node_t) {
3076 .base = PM_NODE_INIT_NODE(parser, PM_CALL_TARGET_NODE, FL(target), target),
3077 .receiver = target->receiver,
3078 .call_operator_loc = target->call_operator_loc,
3079 .name = target->name,
3080 .message_loc = target->message_loc
3083 /* It is possible to get here where we have parsed an invalid syntax tree
3084 * where the call operator was not present. In that case we will have a
3085 * problem because it is a required location. In this case we need to fill
3086 * it in with a fake location so that the syntax tree remains valid. */
3087 if (node->call_operator_loc.start == NULL) {
3088 node->call_operator_loc = (pm_location_t) {
3089 .start = target->base.location.start,
3090 .end = target->base.location.start
3094 // Here we're going to free the target, since it is no longer necessary.
3095 // However, we don't want to call `pm_node_destroy` because we want to keep
3096 // around all of its children since we just reused them.
3106static pm_index_target_node_t *
3107pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3108 pm_index_target_node_t *node = PM_NODE_ALLOC(parser, pm_index_target_node_t);
3110 pm_index_arguments_check(parser, target->arguments, target->block);
3111 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3113 *node = (pm_index_target_node_t) {
3114 .base = PM_NODE_INIT_NODE(parser, PM_INDEX_TARGET_NODE, FL(target) | PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE, target),
3115 .receiver = target->receiver,
3116 .opening_loc = target->opening_loc,
3117 .arguments = target->arguments,
3118 .closing_loc = target->closing_loc,
3119 .block = (pm_block_argument_node_t *) target->block,
3122 // Here we're going to free the target, since it is no longer necessary.
3123 // However, we don't want to call `pm_node_destroy` because we want to keep
3124 // around all of its children since we just reused them.
3133static pm_capture_pattern_node_t *
3134pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_local_variable_target_node_t *target, const pm_token_t *operator) {
3135 pm_capture_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_capture_pattern_node_t);
3137 *node = (pm_capture_pattern_node_t) {
3138 .base = PM_NODE_INIT_NODES(parser, PM_CAPTURE_PATTERN_NODE, 0, value, target),
3141 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
3150static pm_case_node_t *
3151pm_case_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3152 pm_case_node_t *node = PM_NODE_ALLOC(parser, pm_case_node_t);
3154 *node = (pm_case_node_t) {
3155 .base = PM_NODE_INIT_TOKENS(parser, PM_CASE_NODE, 0, case_keyword, end_keyword),
3156 .predicate = predicate,
3157 .else_clause = NULL,
3158 .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
3159 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3170pm_case_node_condition_append(pm_case_node_t *node, pm_node_t *condition) {
3171 assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
3173 pm_node_list_append(&node->conditions, condition);
3174 node->base.location.end = condition->location.end;
3181pm_case_node_else_clause_set(pm_case_node_t *node, pm_else_node_t *else_clause) {
3182 node->else_clause = else_clause;
3183 node->base.location.end = else_clause->base.location.end;
3190pm_case_node_end_keyword_loc_set(pm_case_node_t *node, const pm_token_t *end_keyword) {
3191 node->base.location.end = end_keyword->end;
3192 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
3198static pm_case_match_node_t *
3199pm_case_match_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3200 pm_case_match_node_t *node = PM_NODE_ALLOC(parser, pm_case_match_node_t);
3202 *node = (pm_case_match_node_t) {
3203 .base = PM_NODE_INIT_TOKENS(parser, PM_CASE_MATCH_NODE, 0, case_keyword, end_keyword),
3204 .predicate = predicate,
3205 .else_clause = NULL,
3206 .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
3207 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3218pm_case_match_node_condition_append(pm_case_match_node_t *node, pm_node_t *condition) {
3219 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
3221 pm_node_list_append(&node->conditions, condition);
3222 node->base.location.end = condition->location.end;
3229pm_case_match_node_else_clause_set(pm_case_match_node_t *node, pm_else_node_t *else_clause) {
3230 node->else_clause = else_clause;
3231 node->base.location.end = else_clause->base.location.end;
3238pm_case_match_node_end_keyword_loc_set(pm_case_match_node_t *node, const pm_token_t *end_keyword) {
3239 node->base.location.end = end_keyword->end;
3240 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
3246static pm_class_node_t *
3247pm_class_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const pm_token_t *class_keyword, pm_node_t *constant_path, const pm_token_t *name, const pm_token_t *inheritance_operator, pm_node_t *superclass, pm_node_t *body, const pm_token_t *end_keyword) {
3248 pm_class_node_t *node = PM_NODE_ALLOC(parser, pm_class_node_t);
3250 *node = (pm_class_node_t) {
3251 .base = PM_NODE_INIT_TOKENS(parser, PM_CLASS_NODE, 0, class_keyword, end_keyword),
3253 .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
3254 .constant_path = constant_path,
3255 .inheritance_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(inheritance_operator),
3256 .superclass = superclass,
3258 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3259 .name = pm_parser_constant_id_token(parser, name)
3268static pm_class_variable_and_write_node_t *
3269pm_class_variable_and_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3270 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3271 pm_class_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_and_write_node_t);
3273 *node = (pm_class_variable_and_write_node_t) {
3274 .base = PM_NODE_INIT_NODES(parser, PM_CLASS_VARIABLE_AND_WRITE_NODE, 0, target, value),
3275 .name = target->name,
3276 .name_loc = target->base.location,
3277 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3287static pm_class_variable_operator_write_node_t *
3288pm_class_variable_operator_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3289 pm_class_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_operator_write_node_t);
3291 *node = (pm_class_variable_operator_write_node_t) {
3292 .base = PM_NODE_INIT_NODES(parser, PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE, 0, target, value),
3293 .name = target->name,
3294 .name_loc = target->base.location,
3295 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3297 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3306static pm_class_variable_or_write_node_t *
3307pm_class_variable_or_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3308 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3309 pm_class_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_or_write_node_t);
3311 *node = (pm_class_variable_or_write_node_t) {
3312 .base = PM_NODE_INIT_NODES(parser, PM_CLASS_VARIABLE_OR_WRITE_NODE, 0, target, value),
3313 .name = target->name,
3314 .name_loc = target->base.location,
3315 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3325static pm_class_variable_read_node_t *
3326pm_class_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
3327 assert(token->type == PM_TOKEN_CLASS_VARIABLE);
3328 pm_class_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_read_node_t);
3330 *node = (pm_class_variable_read_node_t) {
3331 .base = PM_NODE_INIT_TOKEN(parser, PM_CLASS_VARIABLE_READ_NODE, 0, token),
3332 .name = pm_parser_constant_id_token(parser, token)
3344static inline pm_node_flags_t
3345pm_implicit_array_write_flags(const pm_node_t *node, pm_node_flags_t flags) {
3346 if (PM_NODE_TYPE_P(node, PM_ARRAY_NODE) && ((const pm_array_node_t *) node)->opening_loc.start == NULL) {
3355static pm_class_variable_write_node_t *
3356pm_class_variable_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *read_node, pm_token_t *operator, pm_node_t *value) {
3357 pm_class_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_write_node_t);
3358 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
3360 *node = (pm_class_variable_write_node_t) {
3361 .base = PM_NODE_INIT_NODES(parser, PM_CLASS_VARIABLE_WRITE_NODE, flags, read_node, value),
3362 .name = read_node->name,
3363 .name_loc = PM_LOCATION_NODE_VALUE(UP(read_node)),
3364 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3374static pm_constant_path_and_write_node_t *
3375pm_constant_path_and_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3376 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3377 pm_constant_path_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_and_write_node_t);
3379 *node = (pm_constant_path_and_write_node_t) {
3380 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_PATH_AND_WRITE_NODE, 0, target, value),
3382 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3392static pm_constant_path_operator_write_node_t *
3393pm_constant_path_operator_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3394 pm_constant_path_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_operator_write_node_t);
3396 *node = (pm_constant_path_operator_write_node_t) {
3397 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_PATH_OPERATOR_WRITE_NODE, 0, target, value),
3399 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3401 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3410static pm_constant_path_or_write_node_t *
3411pm_constant_path_or_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3412 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3413 pm_constant_path_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_or_write_node_t);
3415 *node = (pm_constant_path_or_write_node_t) {
3416 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_PATH_OR_WRITE_NODE, 0, target, value),
3418 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3428static pm_constant_path_node_t *
3429pm_constant_path_node_create(pm_parser_t *parser, pm_node_t *parent, const pm_token_t *delimiter, const pm_token_t *name_token) {
3430 pm_assert_value_expression(parser, parent);
3431 pm_constant_path_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_node_t);
3433 pm_constant_id_t name = PM_CONSTANT_ID_UNSET;
3434 if (name_token->type == PM_TOKEN_CONSTANT) {
3435 name = pm_parser_constant_id_token(parser, name_token);
3438 if (parent == NULL) {
3439 *node = (pm_constant_path_node_t) {
3440 .base = PM_NODE_INIT_TOKENS(parser, PM_CONSTANT_PATH_NODE, 0, delimiter, name_token),
3443 .delimiter_loc = PM_LOCATION_TOKEN_VALUE(delimiter),
3444 .name_loc = PM_LOCATION_TOKEN_VALUE(name_token)
3447 *node = (pm_constant_path_node_t) {
3448 .base = PM_NODE_INIT_NODE_TOKEN(parser, PM_CONSTANT_PATH_NODE, 0, parent, name_token),
3451 .delimiter_loc = PM_LOCATION_TOKEN_VALUE(delimiter),
3452 .name_loc = PM_LOCATION_TOKEN_VALUE(name_token)
3462static pm_constant_path_write_node_t *
3463pm_constant_path_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3464 pm_constant_path_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_write_node_t);
3465 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
3467 *node = (pm_constant_path_write_node_t) {
3468 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_PATH_WRITE_NODE, flags, target, value),
3470 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3480static pm_constant_and_write_node_t *
3481pm_constant_and_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3482 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3483 pm_constant_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_and_write_node_t);
3485 *node = (pm_constant_and_write_node_t) {
3486 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_AND_WRITE_NODE, 0, target, value),
3487 .name = target->name,
3488 .name_loc = target->base.location,
3489 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3499static pm_constant_operator_write_node_t *
3500pm_constant_operator_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3501 pm_constant_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_operator_write_node_t);
3503 *node = (pm_constant_operator_write_node_t) {
3504 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_OPERATOR_WRITE_NODE, 0, target, value),
3505 .name = target->name,
3506 .name_loc = target->base.location,
3507 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3509 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3518static pm_constant_or_write_node_t *
3519pm_constant_or_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3520 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3521 pm_constant_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_or_write_node_t);
3523 *node = (pm_constant_or_write_node_t) {
3524 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_OR_WRITE_NODE, 0, target, value),
3525 .name = target->name,
3526 .name_loc = target->base.location,
3527 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3537static pm_constant_read_node_t *
3538pm_constant_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
3539 assert(name->type == PM_TOKEN_CONSTANT || name->type == PM_TOKEN_MISSING);
3540 pm_constant_read_node_t *node = PM_NODE_ALLOC(parser, pm_constant_read_node_t);
3542 *node = (pm_constant_read_node_t) {
3543 .base = PM_NODE_INIT_TOKEN(parser, PM_CONSTANT_READ_NODE, 0, name),
3544 .name = pm_parser_constant_id_token(parser, name)
3553static pm_constant_write_node_t *
3554pm_constant_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3555 pm_constant_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_write_node_t);
3556 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
3558 *node = (pm_constant_write_node_t) {
3559 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_WRITE_NODE, flags, target, value),
3560 .name = target->name,
3561 .name_loc = target->base.location,
3562 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3573pm_def_node_receiver_check(pm_parser_t *parser, const pm_node_t *node) {
3574 switch (PM_NODE_TYPE(node)) {
3575 case PM_BEGIN_NODE: {
3576 const pm_begin_node_t *cast = (pm_begin_node_t *) node;
3577 if (cast->statements != NULL) pm_def_node_receiver_check(parser, UP(cast->statements));
3580 case PM_PARENTHESES_NODE: {
3581 const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node;
3582 if (cast->body != NULL) pm_def_node_receiver_check(parser, cast->body);
3585 case PM_STATEMENTS_NODE: {
3586 const pm_statements_node_t *cast = (const pm_statements_node_t *) node;
3587 pm_def_node_receiver_check(parser, cast->body.nodes[cast->body.size - 1]);
3592 case PM_IMAGINARY_NODE:
3593 case PM_INTEGER_NODE:
3594 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
3595 case PM_INTERPOLATED_STRING_NODE:
3596 case PM_INTERPOLATED_SYMBOL_NODE:
3597 case PM_INTERPOLATED_X_STRING_NODE:
3598 case PM_RATIONAL_NODE:
3599 case PM_REGULAR_EXPRESSION_NODE:
3600 case PM_SOURCE_ENCODING_NODE:
3601 case PM_SOURCE_FILE_NODE:
3602 case PM_SOURCE_LINE_NODE:
3603 case PM_STRING_NODE:
3604 case PM_SYMBOL_NODE:
3605 case PM_X_STRING_NODE:
3606 pm_parser_err_node(parser, node, PM_ERR_SINGLETON_FOR_LITERALS);
3616static pm_def_node_t *
3618 pm_parser_t *parser,
3619 pm_constant_id_t name,
3620 const pm_token_t *name_loc,
3621 pm_node_t *receiver,
3622 pm_parameters_node_t *parameters,
3624 pm_constant_id_list_t *locals,
3625 const pm_token_t *def_keyword,
3626 const pm_token_t *operator,
3627 const pm_token_t *lparen,
3628 const pm_token_t *rparen,
3629 const pm_token_t *equal,
3630 const pm_token_t *end_keyword
3632 pm_def_node_t *node = PM_NODE_ALLOC(parser, pm_def_node_t);
3634 if (receiver != NULL) {
3635 pm_def_node_receiver_check(parser, receiver);
3638 *node = (pm_def_node_t) {
3640 (end_keyword->type == PM_TOKEN_NOT_PROVIDED)
3641 ? PM_NODE_INIT_TOKEN_NODE(parser, PM_DEF_NODE, 0, def_keyword, body)
3642 : PM_NODE_INIT_TOKENS(parser, PM_DEF_NODE, 0, def_keyword, end_keyword)
3645 .name_loc = PM_LOCATION_TOKEN_VALUE(name_loc),
3646 .receiver = receiver,
3647 .parameters = parameters,
3650 .def_keyword_loc = PM_LOCATION_TOKEN_VALUE(def_keyword),
3651 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3652 .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
3653 .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
3654 .equal_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(equal),
3655 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
3664static pm_defined_node_t *
3665pm_defined_node_create(pm_parser_t *parser, const pm_token_t *lparen, pm_node_t *value, const pm_token_t *rparen, const pm_token_t *keyword) {
3666 pm_defined_node_t *node = PM_NODE_ALLOC(parser, pm_defined_node_t);
3668 *node = (pm_defined_node_t) {
3670 (rparen->type == PM_TOKEN_NOT_PROVIDED)
3671 ? PM_NODE_INIT_TOKEN_NODE(parser, PM_DEFINED_NODE, 0, keyword, value)
3672 : PM_NODE_INIT_TOKENS(parser, PM_DEFINED_NODE, 0, keyword, rparen)
3674 .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
3676 .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
3677 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
3686static pm_else_node_t *
3687pm_else_node_create(pm_parser_t *parser, const pm_token_t *else_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
3688 pm_else_node_t *node = PM_NODE_ALLOC(parser, pm_else_node_t);
3690 *node = (pm_else_node_t) {
3692 ((end_keyword->type == PM_TOKEN_NOT_PROVIDED) && (statements != NULL))
3693 ? PM_NODE_INIT_TOKEN_NODE(parser, PM_ELSE_NODE, 0, else_keyword, statements)
3694 : PM_NODE_INIT_TOKENS(parser, PM_ELSE_NODE, 0, else_keyword, end_keyword)
3696 .else_keyword_loc = PM_LOCATION_TOKEN_VALUE(else_keyword),
3697 .statements = statements,
3698 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
3707static pm_embedded_statements_node_t *
3708pm_embedded_statements_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
3709 pm_embedded_statements_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_statements_node_t);
3711 *node = (pm_embedded_statements_node_t) {
3712 .base = PM_NODE_INIT_TOKENS(parser, PM_EMBEDDED_STATEMENTS_NODE, 0, opening, closing),
3713 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
3714 .statements = statements,
3715 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
3724static pm_embedded_variable_node_t *
3725pm_embedded_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
3726 pm_embedded_variable_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_variable_node_t);
3728 *node = (pm_embedded_variable_node_t) {
3729 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_EMBEDDED_VARIABLE_NODE, 0, operator, variable),
3730 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3731 .variable = variable
3740static pm_ensure_node_t *
3741pm_ensure_node_create(pm_parser_t *parser, const pm_token_t *ensure_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
3742 pm_ensure_node_t *node = PM_NODE_ALLOC(parser, pm_ensure_node_t);
3744 *node = (pm_ensure_node_t) {
3745 .base = PM_NODE_INIT_TOKENS(parser, PM_ENSURE_NODE, 0, ensure_keyword, end_keyword),
3746 .ensure_keyword_loc = PM_LOCATION_TOKEN_VALUE(ensure_keyword),
3747 .statements = statements,
3748 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
3757static pm_false_node_t *
3758pm_false_node_create(pm_parser_t *parser, const pm_token_t *token) {
3759 assert(token->type == PM_TOKEN_KEYWORD_FALSE);
3760 pm_false_node_t *node = PM_NODE_ALLOC(parser, pm_false_node_t);
3762 *node = (pm_false_node_t) {
3763 .base = PM_NODE_INIT_TOKEN(parser, PM_FALSE_NODE, PM_NODE_FLAG_STATIC_LITERAL, token)
3773static pm_find_pattern_node_t *
3774pm_find_pattern_node_create(pm_parser_t *parser, pm_node_list_t *nodes) {
3775 pm_find_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_find_pattern_node_t);
3777 pm_node_t *left = nodes->nodes[0];
3778 assert(PM_NODE_TYPE_P(left, PM_SPLAT_NODE));
3779 pm_splat_node_t *left_splat_node = (pm_splat_node_t *) left;
3783 if (nodes->size == 1) {
3784 right = UP(pm_missing_node_create(parser, left->location.end, left->location.end));
3786 right = nodes->nodes[nodes->size - 1];
3787 assert(PM_NODE_TYPE_P(right, PM_SPLAT_NODE));
3790#if PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS
3791 // FindPatternNode#right is typed as SplatNode in this case, so replace the potential MissingNode with a SplatNode.
3792 // The resulting AST will anyway be ignored, but this file still needs to compile.
3793 pm_splat_node_t *right_splat_node = PM_NODE_TYPE_P(right, PM_SPLAT_NODE) ? (pm_splat_node_t *) right : left_splat_node;
3795 pm_node_t *right_splat_node = right;
3797 *node = (pm_find_pattern_node_t) {
3798 .base = PM_NODE_INIT_NODES(parser, PM_FIND_PATTERN_NODE, 0, left, right),
3800 .left = left_splat_node,
3801 .right = right_splat_node,
3803 .opening_loc = { 0 },
3804 .closing_loc = { 0 }
3807 // For now we're going to just copy over each pointer manually. This could be
3808 // much more efficient, as we could instead resize the node list to only point
3810 for (size_t index = 1; index < nodes->size - 1; index++) {
3811 pm_node_list_append(&node->requireds, nodes->nodes[index]);
3822pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
3823 ptrdiff_t diff = token->end - token->start;
3824 if (diff <= 0) return 0.0;
3826 // First, get a buffer of the content.
3827 size_t length = (size_t) diff;
3828 char *buffer = xmalloc(sizeof(char) * (length + 1));
3829 memcpy((void *) buffer, token->start, length);
3831 // Next, determine if we need to replace the decimal point because of
3832 // locale-specific options, and then normalize them if we have to.
3833 char decimal_point = *localeconv()->decimal_point;
3834 if (decimal_point != '.') {
3835 for (size_t index = 0; index < length; index++) {
3836 if (buffer[index] == '.') buffer[index] = decimal_point;
3840 // Next, handle underscores by removing them from the buffer.
3841 for (size_t index = 0; index < length; index++) {
3842 if (buffer[index] == '_') {
3843 memmove((void *) (buffer + index), (void *) (buffer + index + 1), length - index);
3848 // Null-terminate the buffer so that strtod cannot read off the end.
3849 buffer[length] = '\0';
3851 // Now, call strtod to parse the value. Note that CRuby has their own
3852 // version of strtod which avoids locales. We're okay using the locale-aware
3853 // version because we've already validated through the parser that the token
3854 // is in a valid format.
3857 double value = strtod(buffer, &eptr);
3859 // This should never happen, because we've already checked that the token
3860 // is in a valid format. However it's good to be safe.
3861 if ((eptr != buffer + length) || (errno != 0 && errno != ERANGE)) {
3862 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, (*token), PM_ERR_FLOAT_PARSE);
3863 xfree((void *) buffer);
3867 // If errno is set, then it should only be ERANGE. At this point we need to
3868 // check if it's infinity (it should be).
3869 if (errno == ERANGE && PRISM_ISINF(value)) {
3871 const char *ellipsis;
3877 warn_width = (int) length;
3881 pm_diagnostic_list_append_format(&parser->warning_list, token->start, token->end, PM_WARN_FLOAT_OUT_OF_RANGE, warn_width, (const char *) token->start, ellipsis);
3882 value = (value < 0.0) ? -HUGE_VAL : HUGE_VAL;
3885 // Finally we can free the buffer and return the value.
3886 xfree((void *) buffer);
3893static pm_float_node_t *
3894pm_float_node_create(pm_parser_t *parser, const pm_token_t *token) {
3895 assert(token->type == PM_TOKEN_FLOAT);
3896 pm_float_node_t *node = PM_NODE_ALLOC(parser, pm_float_node_t);
3898 *node = (pm_float_node_t) {
3899 .base = PM_NODE_INIT_TOKEN(parser, PM_FLOAT_NODE, PM_NODE_FLAG_STATIC_LITERAL, token),
3900 .value = pm_double_parse(parser, token)
3909static pm_imaginary_node_t *
3910pm_float_node_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
3911 assert(token->type == PM_TOKEN_FLOAT_IMAGINARY);
3913 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
3914 *node = (pm_imaginary_node_t) {
3915 .base = PM_NODE_INIT_TOKEN(parser, PM_IMAGINARY_NODE, PM_NODE_FLAG_STATIC_LITERAL, token),
3916 .numeric = UP(pm_float_node_create(parser, &((pm_token_t) {
3917 .type = PM_TOKEN_FLOAT,
3918 .start = token->start,
3919 .end = token->end - 1
3929static pm_rational_node_t *
3930pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
3931 assert(token->type == PM_TOKEN_FLOAT_RATIONAL);
3933 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
3934 *node = (pm_rational_node_t) {
3935 .base = PM_NODE_INIT_TOKEN(parser, PM_RATIONAL_NODE, PM_INTEGER_BASE_FLAGS_DECIMAL | PM_NODE_FLAG_STATIC_LITERAL, token),
3937 .denominator = { 0 }
3940 const uint8_t *start = token->start;
3941 const uint8_t *end = token->end - 1; // r
3943 while (start < end && *start == '0') start++; // 0.1 -> .1
3944 while (end > start && end[-1] == '0') end--; // 1.0 -> 1.
3946 size_t length = (size_t) (end - start);
3948 node->denominator.value = 1;
3952 const uint8_t *point = memchr(start, '.', length);
3953 assert(point && "should have a decimal point");
3955 uint8_t *digits = xmalloc(length);
3956 if (digits == NULL) {
3957 fputs("[pm_float_node_rational_create] Failed to allocate memory", stderr);
3961 memcpy(digits, start, (unsigned long) (point - start));
3962 memcpy(digits + (point - start), point + 1, (unsigned long) (end - point - 1));
3963 pm_integer_parse(&node->numerator, PM_INTEGER_BASE_DEFAULT, digits, digits + length - 1);
3965 size_t fract_length = 0;
3966 for (const uint8_t *fract = point; fract < end; ++fract) {
3967 if (*fract != '_') ++fract_length;
3970 if (fract_length > 1) memset(digits + 1, '0', fract_length - 1);
3971 pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + fract_length);
3974 pm_integers_reduce(&node->numerator, &node->denominator);
3982static pm_imaginary_node_t *
3983pm_float_node_rational_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
3984 assert(token->type == PM_TOKEN_FLOAT_RATIONAL_IMAGINARY);
3986 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
3987 *node = (pm_imaginary_node_t) {
3988 .base = PM_NODE_INIT_TOKEN(parser, PM_IMAGINARY_NODE, PM_NODE_FLAG_STATIC_LITERAL, token),
3989 .numeric = UP(pm_float_node_rational_create(parser, &((pm_token_t) {
3990 .type = PM_TOKEN_FLOAT_RATIONAL,
3991 .start = token->start,
3992 .end = token->end - 1
4002static pm_for_node_t *
4004 pm_parser_t *parser,
4006 pm_node_t *collection,
4007 pm_statements_node_t *statements,
4008 const pm_token_t *for_keyword,
4009 const pm_token_t *in_keyword,
4010 const pm_token_t *do_keyword,
4011 const pm_token_t *end_keyword
4013 pm_for_node_t *node = PM_NODE_ALLOC(parser, pm_for_node_t);
4015 *node = (pm_for_node_t) {
4016 .base = PM_NODE_INIT_TOKENS(parser, PM_FOR_NODE, 0, for_keyword, end_keyword),
4018 .collection = collection,
4019 .statements = statements,
4020 .for_keyword_loc = PM_LOCATION_TOKEN_VALUE(for_keyword),
4021 .in_keyword_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
4022 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
4023 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
4032static pm_forwarding_arguments_node_t *
4033pm_forwarding_arguments_node_create(pm_parser_t *parser, const pm_token_t *token) {
4034 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4035 pm_forwarding_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_arguments_node_t);
4037 *node = (pm_forwarding_arguments_node_t) {
4038 .base = PM_NODE_INIT_TOKEN(parser, PM_FORWARDING_ARGUMENTS_NODE, 0, token)
4047static pm_forwarding_parameter_node_t *
4048pm_forwarding_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
4049 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4050 pm_forwarding_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_parameter_node_t);
4052 *node = (pm_forwarding_parameter_node_t) {
4053 .base = PM_NODE_INIT_TOKEN(parser, PM_FORWARDING_PARAMETER_NODE, 0, token)
4062static pm_forwarding_super_node_t *
4063pm_forwarding_super_node_create(pm_parser_t *parser, const pm_token_t *token, pm_arguments_t *arguments) {
4064 assert(arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_NODE));
4065 assert(token->type == PM_TOKEN_KEYWORD_SUPER);
4066 pm_forwarding_super_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_super_node_t);
4068 pm_block_node_t *block = NULL;
4069 if (arguments->block != NULL) {
4070 block = (pm_block_node_t *) arguments->block;
4073 *node = (pm_forwarding_super_node_t) {
4076 ? PM_NODE_INIT_TOKEN(parser, PM_FORWARDING_SUPER_NODE, 0, token)
4077 : PM_NODE_INIT_TOKEN_NODE(parser, PM_FORWARDING_SUPER_NODE, 0, token, block)
4089static pm_hash_pattern_node_t *
4090pm_hash_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4091 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4093 *node = (pm_hash_pattern_node_t) {
4094 .base = PM_NODE_INIT_TOKENS(parser, PM_HASH_PATTERN_NODE, 0, opening, closing),
4096 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4097 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
4108static pm_hash_pattern_node_t *
4109pm_hash_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *elements, pm_node_t *rest) {
4110 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4112 const uint8_t *start;
4115 if (elements->size > 0) {
4117 start = MIN(rest->location.start, elements->nodes[0]->location.start);
4118 end = MAX(rest->location.end, elements->nodes[elements->size - 1]->location.end);
4120 start = elements->nodes[0]->location.start;
4121 end = elements->nodes[elements->size - 1]->location.end;
4124 assert(rest != NULL);
4125 start = rest->location.start;
4126 end = rest->location.end;
4129 *node = (pm_hash_pattern_node_t) {
4130 .base = PM_NODE_INIT(parser, PM_HASH_PATTERN_NODE, 0, start, end),
4134 .opening_loc = { 0 },
4135 .closing_loc = { 0 }
4138 pm_node_list_concat(&node->elements, elements);
4145static pm_constant_id_t
4146pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
4147 switch (PM_NODE_TYPE(target)) {
4148 case PM_GLOBAL_VARIABLE_READ_NODE:
4149 return ((pm_global_variable_read_node_t *) target)->name;
4150 case PM_BACK_REFERENCE_READ_NODE:
4151 return ((pm_back_reference_read_node_t *) target)->name;
4152 case PM_NUMBERED_REFERENCE_READ_NODE:
4153 // This will only ever happen in the event of a syntax error, but we
4154 // still need to provide something for the node.
4155 return pm_parser_constant_id_location(parser, target->location.start, target->location.end);
4157 assert(false && "unreachable");
4158 return (pm_constant_id_t) -1;
4165static pm_global_variable_and_write_node_t *
4166pm_global_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4167 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4168 pm_global_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_and_write_node_t);
4170 *node = (pm_global_variable_and_write_node_t) {
4171 .base = PM_NODE_INIT_NODES(parser, PM_GLOBAL_VARIABLE_AND_WRITE_NODE, 0, target, value),
4172 .name = pm_global_variable_write_name(parser, target),
4173 .name_loc = target->location,
4174 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4184static pm_global_variable_operator_write_node_t *
4185pm_global_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4186 pm_global_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_operator_write_node_t);
4188 *node = (pm_global_variable_operator_write_node_t) {
4189 .base = PM_NODE_INIT_NODES(parser, PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE, 0, target, value),
4190 .name = pm_global_variable_write_name(parser, target),
4191 .name_loc = target->location,
4192 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4194 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
4203static pm_global_variable_or_write_node_t *
4204pm_global_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4205 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4206 pm_global_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_or_write_node_t);
4208 *node = (pm_global_variable_or_write_node_t) {
4209 .base = PM_NODE_INIT_NODES(parser, PM_GLOBAL_VARIABLE_OR_WRITE_NODE, 0, target, value),
4210 .name = pm_global_variable_write_name(parser, target),
4211 .name_loc = target->location,
4212 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4222static pm_global_variable_read_node_t *
4223pm_global_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
4224 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4226 *node = (pm_global_variable_read_node_t) {
4227 .base = PM_NODE_INIT_TOKEN(parser, PM_GLOBAL_VARIABLE_READ_NODE, 0, name),
4228 .name = pm_parser_constant_id_token(parser, name)
4237static pm_global_variable_read_node_t *
4238pm_global_variable_read_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name) {
4239 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4241 *node = (pm_global_variable_read_node_t) {
4242 .base = PM_NODE_INIT_BASE(parser, PM_GLOBAL_VARIABLE_READ_NODE, 0),
4252static pm_global_variable_write_node_t *
4253pm_global_variable_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4254 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4255 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
4257 *node = (pm_global_variable_write_node_t) {
4258 .base = PM_NODE_INIT_NODES(parser, PM_GLOBAL_VARIABLE_WRITE_NODE, flags, target, value),
4259 .name = pm_global_variable_write_name(parser, target),
4260 .name_loc = PM_LOCATION_NODE_VALUE(target),
4261 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
4271static pm_global_variable_write_node_t *
4272pm_global_variable_write_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name, pm_node_t *value) {
4273 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4275 *node = (pm_global_variable_write_node_t) {
4276 .base = PM_NODE_INIT_BASE(parser, PM_GLOBAL_VARIABLE_WRITE_NODE, 0),
4278 .name_loc = PM_LOCATION_NULL_VALUE(parser),
4279 .operator_loc = PM_LOCATION_NULL_VALUE(parser),
4289static pm_hash_node_t *
4290pm_hash_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4291 assert(opening != NULL);
4292 pm_hash_node_t *node = PM_NODE_ALLOC(parser, pm_hash_node_t);
4294 *node = (pm_hash_node_t) {
4295 .base = PM_NODE_INIT_TOKEN(parser, PM_HASH_NODE, PM_NODE_FLAG_STATIC_LITERAL, opening),
4296 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4297 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
4308pm_hash_node_elements_append(pm_hash_node_t *hash, pm_node_t *element) {
4309 pm_node_list_append(&hash->elements, element);
4311 bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE);
4312 if (static_literal) {
4313 pm_assoc_node_t *assoc = (pm_assoc_node_t *) element;
4314 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);
4315 static_literal = static_literal && PM_NODE_FLAG_P(assoc->key, PM_NODE_FLAG_STATIC_LITERAL);
4316 static_literal = static_literal && PM_NODE_FLAG_P(assoc, PM_NODE_FLAG_STATIC_LITERAL);
4319 if (!static_literal) {
4320 pm_node_flag_unset(UP(hash), PM_NODE_FLAG_STATIC_LITERAL);
4325pm_hash_node_closing_loc_set(pm_hash_node_t *hash, pm_token_t *token) {
4326 hash->base.location.end = token->end;
4327 hash->closing_loc = PM_LOCATION_TOKEN_VALUE(token);
4333static pm_if_node_t *
4334pm_if_node_create(pm_parser_t *parser,
4335 const pm_token_t *if_keyword,
4336 pm_node_t *predicate,
4337 const pm_token_t *then_keyword,
4338 pm_statements_node_t *statements,
4339 pm_node_t *subsequent,
4340 const pm_token_t *end_keyword
4342 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4343 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4346 if (end_keyword->type != PM_TOKEN_NOT_PROVIDED) {
4347 end = end_keyword->end;
4348 } else if (subsequent != NULL) {
4349 end = subsequent->location.end;
4350 } else if (pm_statements_node_body_length(statements) != 0) {
4351 end = statements->base.location.end;
4353 end = predicate->location.end;
4356 *node = (pm_if_node_t) {
4357 .base = PM_NODE_INIT(parser, PM_IF_NODE, PM_NODE_FLAG_NEWLINE, if_keyword->start, end),
4358 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4359 .predicate = predicate,
4360 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
4361 .statements = statements,
4362 .subsequent = subsequent,
4363 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
4372static pm_if_node_t *
4373pm_if_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *if_keyword, pm_node_t *predicate) {
4374 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4375 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4377 pm_statements_node_t *statements = pm_statements_node_create(parser);
4378 pm_statements_node_body_append(parser, statements, statement, true);
4380 *node = (pm_if_node_t) {
4381 .base = PM_NODE_INIT_NODES(parser, PM_IF_NODE, PM_NODE_FLAG_NEWLINE, statement, predicate),
4382 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4383 .predicate = predicate,
4384 .then_keyword_loc = { 0 },
4385 .statements = statements,
4387 .end_keyword_loc = { 0 }
4396static pm_if_node_t *
4397pm_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) {
4398 pm_assert_value_expression(parser, predicate);
4399 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4401 pm_statements_node_t *if_statements = pm_statements_node_create(parser);
4402 pm_statements_node_body_append(parser, if_statements, true_expression, true);
4404 pm_statements_node_t *else_statements = pm_statements_node_create(parser);
4405 pm_statements_node_body_append(parser, else_statements, false_expression, true);
4407 pm_token_t end_keyword = not_provided(parser);
4408 pm_else_node_t *else_node = pm_else_node_create(parser, colon, else_statements, &end_keyword);
4410 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4412 *node = (pm_if_node_t) {
4413 .base = PM_NODE_INIT_NODES(parser, PM_IF_NODE, PM_NODE_FLAG_NEWLINE, predicate, false_expression),
4414 .if_keyword_loc = { 0 },
4415 .predicate = predicate,
4416 .then_keyword_loc = PM_LOCATION_TOKEN_VALUE(qmark),
4417 .statements = if_statements,
4418 .subsequent = UP(else_node),
4419 .end_keyword_loc = { 0 }
4427pm_if_node_end_keyword_loc_set(pm_if_node_t *node, const pm_token_t *keyword) {
4428 node->base.location.end = keyword->end;
4429 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4433pm_else_node_end_keyword_loc_set(pm_else_node_t *node, const pm_token_t *keyword) {
4434 node->base.location.end = keyword->end;
4435 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4441static pm_implicit_node_t *
4442pm_implicit_node_create(pm_parser_t *parser, pm_node_t *value) {
4443 pm_implicit_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_node_t);
4445 *node = (pm_implicit_node_t) {
4446 .base = PM_NODE_INIT_NODE(parser, PM_IMPLICIT_NODE, 0, value),
4456static pm_implicit_rest_node_t *
4457pm_implicit_rest_node_create(pm_parser_t *parser, const pm_token_t *token) {
4458 assert(token->type == PM_TOKEN_COMMA);
4460 pm_implicit_rest_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_rest_node_t);
4462 *node = (pm_implicit_rest_node_t) {
4463 .base = PM_NODE_INIT_TOKEN(parser, PM_IMPLICIT_REST_NODE, 0, token)
4472static pm_integer_node_t *
4473pm_integer_node_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4474 assert(token->type == PM_TOKEN_INTEGER);
4475 pm_integer_node_t *node = PM_NODE_ALLOC(parser, pm_integer_node_t);
4477 *node = (pm_integer_node_t) {
4478 .base = PM_NODE_INIT_TOKEN(parser, PM_INTEGER_NODE, base | PM_NODE_FLAG_STATIC_LITERAL, token),
4482 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4484 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4485 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4486 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4487 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4488 default: assert(false && "unreachable"); break;
4491 pm_integer_parse(&node->value, integer_base, token->start, token->end);
4499static pm_imaginary_node_t *
4500pm_integer_node_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4501 assert(token->type == PM_TOKEN_INTEGER_IMAGINARY);
4503 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4504 *node = (pm_imaginary_node_t) {
4505 .base = PM_NODE_INIT_TOKEN(parser, PM_IMAGINARY_NODE, PM_NODE_FLAG_STATIC_LITERAL, token),
4506 .numeric = UP(pm_integer_node_create(parser, base, &((pm_token_t) {
4507 .type = PM_TOKEN_INTEGER,
4508 .start = token->start,
4509 .end = token->end - 1
4520static pm_rational_node_t *
4521pm_integer_node_rational_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4522 assert(token->type == PM_TOKEN_INTEGER_RATIONAL);
4524 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
4525 *node = (pm_rational_node_t) {
4526 .base = PM_NODE_INIT_TOKEN(parser, PM_RATIONAL_NODE, base | PM_NODE_FLAG_STATIC_LITERAL, token),
4528 .denominator = { .value = 1, 0 }
4531 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4533 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4534 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4535 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4536 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4537 default: assert(false && "unreachable"); break;
4540 pm_integer_parse(&node->numerator, integer_base, token->start, token->end - 1);
4549static pm_imaginary_node_t *
4550pm_integer_node_rational_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4551 assert(token->type == PM_TOKEN_INTEGER_RATIONAL_IMAGINARY);
4553 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4554 *node = (pm_imaginary_node_t) {
4555 .base = PM_NODE_INIT_TOKEN(parser, PM_IMAGINARY_NODE, PM_NODE_FLAG_STATIC_LITERAL, token),
4556 .numeric = UP(pm_integer_node_rational_create(parser, base, &((pm_token_t) {
4557 .type = PM_TOKEN_INTEGER_RATIONAL,
4558 .start = token->start,
4559 .end = token->end - 1
4569static pm_in_node_t *
4570pm_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) {
4571 pm_in_node_t *node = PM_NODE_ALLOC(parser, pm_in_node_t);
4574 if (statements != NULL) {
4575 end = statements->base.location.end;
4576 } else if (then_keyword->type != PM_TOKEN_NOT_PROVIDED) {
4577 end = then_keyword->end;
4579 end = pattern->location.end;
4582 *node = (pm_in_node_t) {
4583 .base = PM_NODE_INIT(parser, PM_IN_NODE, 0, in_keyword->start, end),
4585 .statements = statements,
4586 .in_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
4587 .then_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword)
4596static pm_instance_variable_and_write_node_t *
4597pm_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) {
4598 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4599 pm_instance_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_and_write_node_t);
4601 *node = (pm_instance_variable_and_write_node_t) {
4602 .base = PM_NODE_INIT_NODES(parser, PM_INSTANCE_VARIABLE_AND_WRITE_NODE, 0, target, value),
4603 .name = target->name,
4604 .name_loc = target->base.location,
4605 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4615static pm_instance_variable_operator_write_node_t *
4616pm_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) {
4617 pm_instance_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_operator_write_node_t);
4619 *node = (pm_instance_variable_operator_write_node_t) {
4620 .base = PM_NODE_INIT_NODES(parser, PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE, 0, target, value),
4621 .name = target->name,
4622 .name_loc = target->base.location,
4623 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4625 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
4634static pm_instance_variable_or_write_node_t *
4635pm_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) {
4636 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4637 pm_instance_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_or_write_node_t);
4639 *node = (pm_instance_variable_or_write_node_t) {
4640 .base = PM_NODE_INIT_NODES(parser, PM_INSTANCE_VARIABLE_OR_WRITE_NODE, 0, target, value),
4641 .name = target->name,
4642 .name_loc = target->base.location,
4643 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4653static pm_instance_variable_read_node_t *
4654pm_instance_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
4655 assert(token->type == PM_TOKEN_INSTANCE_VARIABLE);
4656 pm_instance_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_read_node_t);
4658 *node = (pm_instance_variable_read_node_t) {
4659 .base = PM_NODE_INIT_TOKEN(parser, PM_INSTANCE_VARIABLE_READ_NODE, 0, token),
4660 .name = pm_parser_constant_id_token(parser, token)
4670static pm_instance_variable_write_node_t *
4671pm_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) {
4672 pm_instance_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_write_node_t);
4673 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
4675 *node = (pm_instance_variable_write_node_t) {
4676 .base = PM_NODE_INIT_NODES(parser, PM_INSTANCE_VARIABLE_WRITE_NODE, flags, read_node, value),
4677 .name = read_node->name,
4678 .name_loc = PM_LOCATION_NODE_VALUE(read_node),
4679 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
4692pm_interpolated_node_append(pm_node_t *node, pm_node_list_t *parts, pm_node_t *part) {
4693 switch (PM_NODE_TYPE(part)) {
4694 case PM_STRING_NODE:
4695 pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
4697 case PM_EMBEDDED_STATEMENTS_NODE: {
4698 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
4699 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
4701 if (embedded == NULL) {
4702 // If there are no statements or more than one statement, then
4703 // we lose the static literal flag.
4704 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
4705 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
4706 // If the embedded statement is a string, then we can keep the
4707 // static literal flag and mark the string as frozen.
4708 pm_node_flag_set(embedded, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
4709 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
4710 // If the embedded statement is an interpolated string and it's
4711 // a static literal, then we can keep the static literal flag.
4713 // Otherwise we lose the static literal flag.
4714 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
4719 case PM_EMBEDDED_VARIABLE_NODE:
4720 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
4723 assert(false && "unexpected node type");
4727 pm_node_list_append(parts, part);
4733static pm_interpolated_regular_expression_node_t *
4734pm_interpolated_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4735 pm_interpolated_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_regular_expression_node_t);
4737 *node = (pm_interpolated_regular_expression_node_t) {
4738 .base = PM_NODE_INIT_TOKEN(parser, PM_INTERPOLATED_REGULAR_EXPRESSION_NODE, PM_NODE_FLAG_STATIC_LITERAL, opening),
4739 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4740 .closing_loc = PM_LOCATION_TOKEN_VALUE(opening),
4748pm_interpolated_regular_expression_node_append(pm_interpolated_regular_expression_node_t *node, pm_node_t *part) {
4749 if (node->base.location.start > part->location.start) {
4750 node->base.location.start = part->location.start;
4752 if (node->base.location.end < part->location.end) {
4753 node->base.location.end = part->location.end;
4756 pm_interpolated_node_append(UP(node), &node->parts, part);
4760pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_interpolated_regular_expression_node_t *node, const pm_token_t *closing) {
4761 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
4762 node->base.location.end = closing->end;
4763 pm_node_flag_set(UP(node), pm_regular_expression_flags_create(parser, closing));
4790pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_node_t *part) {
4791#define CLEAR_FLAGS(node) \
4792 node->base.flags = (pm_node_flags_t) (FL(node) & ~(PM_NODE_FLAG_STATIC_LITERAL | PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE))
4794#define MUTABLE_FLAGS(node) \
4795 node->base.flags = (pm_node_flags_t) ((FL(node) | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE) & ~PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN);
4797 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
4798 node->base.location.start = part->location.start;
4801 node->base.location.end = MAX(node->base.location.end, part->location.end);
4803 switch (PM_NODE_TYPE(part)) {
4804 case PM_STRING_NODE:
4805 // If inner string is not frozen, it stops being a static literal. We should *not* clear other flags,
4806 // because concatenating two frozen strings (`'foo' 'bar'`) is still frozen. This holds true for
4807 // as long as this interpolation only consists of other string literals.
4808 if (!PM_NODE_FLAG_P(part, PM_STRING_FLAGS_FROZEN)) {
4809 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
4811 part->flags = (pm_node_flags_t) ((part->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
4813 case PM_INTERPOLATED_STRING_NODE:
4814 if (PM_NODE_FLAG_P(part, PM_NODE_FLAG_STATIC_LITERAL)) {
4815 // If the string that we're concatenating is a static literal,
4816 // then we can keep the static literal flag for this string.
4818 // Otherwise, we lose the static literal flag here and we should
4819 // also clear the mutability flags.
4823 case PM_EMBEDDED_STATEMENTS_NODE: {
4824 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
4825 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
4827 if (embedded == NULL) {
4828 // If we're embedding multiple statements or no statements, then
4829 // the string is not longer a static literal.
4831 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
4832 // If the embedded statement is a string, then we can make that
4833 // string as frozen and static literal, and not touch the static
4834 // literal status of this string.
4835 embedded->flags = (pm_node_flags_t) ((embedded->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
4837 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
4838 MUTABLE_FLAGS(node);
4840 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
4841 // If the embedded statement is an interpolated string, but that
4842 // string is marked as static literal, then we can keep our
4843 // static literal status for this string.
4844 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
4845 MUTABLE_FLAGS(node);
4848 // In all other cases, we lose the static literal flag here and
4855 case PM_EMBEDDED_VARIABLE_NODE:
4856 // Embedded variables clear static literal, which means we also
4857 // should clear the mutability flags.
4860 case PM_X_STRING_NODE:
4861 case PM_INTERPOLATED_X_STRING_NODE:
4862 case PM_SYMBOL_NODE:
4863 case PM_INTERPOLATED_SYMBOL_NODE:
4864 // These will only happen in error cases. But we want to handle it
4865 // here so that we don't fail the assertion.
4869 assert(false && "unexpected node type");
4873 pm_node_list_append(&node->parts, part);
4882static pm_interpolated_string_node_t *
4883pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
4884 pm_interpolated_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_string_node_t);
4885 pm_node_flags_t flags = PM_NODE_FLAG_STATIC_LITERAL;
4887 switch (parser->frozen_string_literal) {
4888 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
4889 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE;
4891 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
4892 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN;
4896 *node = (pm_interpolated_string_node_t) {
4897 .base = PM_NODE_INIT_TOKENS(parser, PM_INTERPOLATED_STRING_NODE, flags, opening, closing),
4898 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
4899 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
4903 if (parts != NULL) {
4905 PM_NODE_LIST_FOREACH(parts, index, part) {
4906 pm_interpolated_string_node_append(node, part);
4917pm_interpolated_string_node_closing_set(pm_interpolated_string_node_t *node, const pm_token_t *closing) {
4918 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
4919 node->base.location.end = closing->end;
4923pm_interpolated_symbol_node_append(pm_interpolated_symbol_node_t *node, pm_node_t *part) {
4924 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
4925 node->base.location.start = part->location.start;
4928 pm_interpolated_node_append(UP(node), &node->parts, part);
4929 node->base.location.end = MAX(node->base.location.end, part->location.end);
4933pm_interpolated_symbol_node_closing_loc_set(pm_interpolated_symbol_node_t *node, const pm_token_t *closing) {
4934 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
4935 node->base.location.end = closing->end;
4941static pm_interpolated_symbol_node_t *
4942pm_interpolated_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
4943 pm_interpolated_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_symbol_node_t);
4945 *node = (pm_interpolated_symbol_node_t) {
4946 .base = PM_NODE_INIT_TOKENS(parser, PM_INTERPOLATED_SYMBOL_NODE, PM_NODE_FLAG_STATIC_LITERAL, opening, closing),
4947 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
4948 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
4952 if (parts != NULL) {
4954 PM_NODE_LIST_FOREACH(parts, index, part) {
4955 pm_interpolated_symbol_node_append(node, part);
4965static pm_interpolated_x_string_node_t *
4966pm_interpolated_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4967 pm_interpolated_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_x_string_node_t);
4969 *node = (pm_interpolated_x_string_node_t) {
4970 .base = PM_NODE_INIT_TOKENS(parser, PM_INTERPOLATED_X_STRING_NODE, 0, opening, closing),
4971 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
4972 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
4980pm_interpolated_xstring_node_append(pm_interpolated_x_string_node_t *node, pm_node_t *part) {
4981 pm_interpolated_node_append(UP(node), &node->parts, part);
4982 node->base.location.end = part->location.end;
4986pm_interpolated_xstring_node_closing_set(pm_interpolated_x_string_node_t *node, const pm_token_t *closing) {
4987 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
4988 node->base.location.end = closing->end;
4994static pm_it_local_variable_read_node_t *
4995pm_it_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
4996 pm_it_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_it_local_variable_read_node_t);
4998 *node = (pm_it_local_variable_read_node_t) {
4999 .base = PM_NODE_INIT_TOKEN(parser, PM_IT_LOCAL_VARIABLE_READ_NODE, 0, name),
5008static pm_it_parameters_node_t *
5009pm_it_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5010 pm_it_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_it_parameters_node_t);
5012 *node = (pm_it_parameters_node_t) {
5013 .base = PM_NODE_INIT_TOKENS(parser, PM_IT_PARAMETERS_NODE, 0, opening, closing),
5022static pm_keyword_hash_node_t *
5023pm_keyword_hash_node_create(pm_parser_t *parser) {
5024 pm_keyword_hash_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_hash_node_t);
5026 *node = (pm_keyword_hash_node_t) {
5027 .base = PM_NODE_INIT_UNSET(parser, PM_KEYWORD_HASH_NODE, PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS),
5038pm_keyword_hash_node_elements_append(pm_keyword_hash_node_t *hash, pm_node_t *element) {
5039 // If the element being added is not an AssocNode or does not have a symbol
5040 // key, then we want to turn the SYMBOL_KEYS flag off.
5041 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE) || !PM_NODE_TYPE_P(((pm_assoc_node_t *) element)->key, PM_SYMBOL_NODE)) {
5042 pm_node_flag_unset(UP(hash), PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS);
5045 pm_node_list_append(&hash->elements, element);
5046 if (hash->base.location.start == NULL) {
5047 hash->base.location.start = element->location.start;
5049 hash->base.location.end = element->location.end;
5055static pm_required_keyword_parameter_node_t *
5056pm_required_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name) {
5057 pm_required_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_keyword_parameter_node_t);
5059 *node = (pm_required_keyword_parameter_node_t) {
5060 .base = PM_NODE_INIT_TOKEN(parser, PM_REQUIRED_KEYWORD_PARAMETER_NODE, 0, name),
5061 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5062 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5071static pm_optional_keyword_parameter_node_t *
5072pm_optional_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, pm_node_t *value) {
5073 pm_optional_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_keyword_parameter_node_t);
5075 *node = (pm_optional_keyword_parameter_node_t) {
5076 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_OPTIONAL_KEYWORD_PARAMETER_NODE, 0, name, value),
5077 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5078 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5088static pm_keyword_rest_parameter_node_t *
5089pm_keyword_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
5090 pm_keyword_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_rest_parameter_node_t);
5092 *node = (pm_keyword_rest_parameter_node_t) {
5094 (name->type == PM_TOKEN_NOT_PROVIDED)
5095 ? PM_NODE_INIT_TOKEN(parser, PM_KEYWORD_REST_PARAMETER_NODE, 0, operator)
5096 : PM_NODE_INIT_TOKENS(parser, PM_KEYWORD_REST_PARAMETER_NODE, 0, operator, name)
5098 .name = pm_parser_optional_constant_id_token(parser, name),
5099 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
5100 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5109static pm_lambda_node_t *
5110pm_lambda_node_create(
5111 pm_parser_t *parser,
5112 pm_constant_id_list_t *locals,
5113 const pm_token_t *operator,
5114 const pm_token_t *opening,
5115 const pm_token_t *closing,
5116 pm_node_t *parameters,
5119 pm_lambda_node_t *node = PM_NODE_ALLOC(parser, pm_lambda_node_t);
5121 *node = (pm_lambda_node_t) {
5122 .base = PM_NODE_INIT_TOKENS(parser, PM_LAMBDA_NODE, 0, operator, closing),
5124 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5125 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5126 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
5127 .parameters = parameters,
5137static pm_local_variable_and_write_node_t *
5138pm_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) {
5139 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));
5140 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5141 pm_local_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_and_write_node_t);
5143 *node = (pm_local_variable_and_write_node_t) {
5144 .base = PM_NODE_INIT_NODES(parser, PM_LOCAL_VARIABLE_AND_WRITE_NODE, 0, target, value),
5145 .name_loc = target->location,
5146 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5158static pm_local_variable_operator_write_node_t *
5159pm_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) {
5160 pm_local_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_operator_write_node_t);
5162 *node = (pm_local_variable_operator_write_node_t) {
5163 .base = PM_NODE_INIT_NODES(parser, PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE, 0, target, value),
5164 .name_loc = target->location,
5165 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5168 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
5178static pm_local_variable_or_write_node_t *
5179pm_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) {
5180 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));
5181 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5182 pm_local_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_or_write_node_t);
5184 *node = (pm_local_variable_or_write_node_t) {
5185 .base = PM_NODE_INIT_NODES(parser, PM_LOCAL_VARIABLE_OR_WRITE_NODE, 0, target, value),
5186 .name_loc = target->location,
5187 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5199static pm_local_variable_read_node_t *
5200pm_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) {
5201 if (!missing) pm_locals_read(&pm_parser_scope_find(parser, depth)->locals, name_id);
5203 pm_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_read_node_t);
5205 *node = (pm_local_variable_read_node_t) {
5206 .base = PM_NODE_INIT_TOKEN(parser, PM_LOCAL_VARIABLE_READ_NODE, 0, name),
5217static pm_local_variable_read_node_t *
5218pm_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5219 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5220 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, false);
5227static pm_local_variable_read_node_t *
5228pm_local_variable_read_node_missing_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5229 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5230 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, true);
5236static pm_local_variable_write_node_t *
5237pm_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) {
5238 pm_local_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_write_node_t);
5239 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
5241 *node = (pm_local_variable_write_node_t) {
5242 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_LOCAL_VARIABLE_WRITE_NODE, flags, name_loc, value),
5246 .name_loc = *name_loc,
5247 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator)
5257pm_token_is_it(const uint8_t *start, const uint8_t *end) {
5258 return (end - start == 2) && (start[0] == 'i') && (start[1] == 't');
5266pm_token_is_numbered_parameter(const uint8_t *start, const uint8_t *end) {
5267 return (end - start == 2) && (start[0] == '_') && (start[1] != '0') && (pm_char_is_decimal_digit(start[1]));
5275pm_refute_numbered_parameter(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
5276 if (pm_token_is_numbered_parameter(start, end)) {
5277 PM_PARSER_ERR_FORMAT(parser, start, end, PM_ERR_PARAMETER_NUMBERED_RESERVED, start);
5285static pm_local_variable_target_node_t *
5286pm_local_variable_target_node_create(pm_parser_t *parser, const pm_location_t *location, pm_constant_id_t name, uint32_t depth) {
5287 pm_refute_numbered_parameter(parser, location->start, location->end);
5288 pm_local_variable_target_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_target_node_t);
5290 *node = (pm_local_variable_target_node_t) {
5291 .base = PM_NODE_INIT_TOKEN(parser, PM_LOCAL_VARIABLE_TARGET_NODE, 0, location),
5302static pm_match_predicate_node_t *
5303pm_match_predicate_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5304 pm_assert_value_expression(parser, value);
5306 pm_match_predicate_node_t *node = PM_NODE_ALLOC(parser, pm_match_predicate_node_t);
5308 *node = (pm_match_predicate_node_t) {
5309 .base = PM_NODE_INIT_NODES(parser, PM_MATCH_PREDICATE_NODE, 0, value, pattern),
5312 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5321static pm_match_required_node_t *
5322pm_match_required_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5323 pm_assert_value_expression(parser, value);
5325 pm_match_required_node_t *node = PM_NODE_ALLOC(parser, pm_match_required_node_t);
5327 *node = (pm_match_required_node_t) {
5328 .base = PM_NODE_INIT_NODES(parser, PM_MATCH_REQUIRED_NODE, 0, value, pattern),
5331 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5340static pm_match_write_node_t *
5341pm_match_write_node_create(pm_parser_t *parser, pm_call_node_t *call) {
5342 pm_match_write_node_t *node = PM_NODE_ALLOC(parser, pm_match_write_node_t);
5344 *node = (pm_match_write_node_t) {
5345 .base = PM_NODE_INIT_NODE(parser, PM_MATCH_WRITE_NODE, 0, call),
5356static pm_module_node_t *
5357pm_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) {
5358 pm_module_node_t *node = PM_NODE_ALLOC(parser, pm_module_node_t);
5360 *node = (pm_module_node_t) {
5361 .base = PM_NODE_INIT_TOKENS(parser, PM_MODULE_NODE, 0, module_keyword, end_keyword),
5362 .locals = (locals == NULL ? ((pm_constant_id_list_t) { .ids = NULL, .size = 0, .capacity = 0 }) : *locals),
5363 .module_keyword_loc = PM_LOCATION_TOKEN_VALUE(module_keyword),
5364 .constant_path = constant_path,
5366 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
5367 .name = pm_parser_constant_id_token(parser, name)
5376static pm_multi_target_node_t *
5377pm_multi_target_node_create(pm_parser_t *parser) {
5378 pm_multi_target_node_t *node = PM_NODE_ALLOC(parser, pm_multi_target_node_t);
5380 *node = (pm_multi_target_node_t) {
5381 .base = PM_NODE_INIT_UNSET(parser, PM_MULTI_TARGET_NODE, 0),
5385 .lparen_loc = { 0 },
5396pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t *node, pm_node_t *target) {
5397 if (PM_NODE_TYPE_P(target, PM_SPLAT_NODE)) {
5398 if (node->rest == NULL) {
5399 node->rest = target;
5401 pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
5402 pm_node_list_append(&node->rights, target);
5404 } else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
5405 if (node->rest == NULL) {
5406 node->rest = target;
5408 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
5409 pm_node_list_append(&node->rights, target);
5411 } else if (node->rest == NULL) {
5412 pm_node_list_append(&node->lefts, target);
5414 pm_node_list_append(&node->rights, target);
5417 if (node->base.location.start == NULL || (node->base.location.start > target->location.start)) {
5418 node->base.location.start = target->location.start;
5421 if (node->base.location.end == NULL || (node->base.location.end < target->location.end)) {
5422 node->base.location.end = target->location.end;
5430pm_multi_target_node_opening_set(pm_multi_target_node_t *node, const pm_token_t *lparen) {
5431 node->base.location.start = lparen->start;
5432 node->lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen);
5439pm_multi_target_node_closing_set(pm_multi_target_node_t *node, const pm_token_t *rparen) {
5440 node->base.location.end = rparen->end;
5441 node->rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen);
5447static pm_multi_write_node_t *
5448pm_multi_write_node_create(pm_parser_t *parser, pm_multi_target_node_t *target, const pm_token_t *operator, pm_node_t *value) {
5449 pm_multi_write_node_t *node = PM_NODE_ALLOC(parser, pm_multi_write_node_t);
5450 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
5452 *node = (pm_multi_write_node_t) {
5453 .base = PM_NODE_INIT_NODES(parser, PM_MULTI_WRITE_NODE, flags, target, value),
5454 .lefts = target->lefts,
5455 .rest = target->rest,
5456 .rights = target->rights,
5457 .lparen_loc = target->lparen_loc,
5458 .rparen_loc = target->rparen_loc,
5459 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5463 // Explicitly do not call pm_node_destroy here because we want to keep
5464 // around all of the information within the MultiWriteNode node.
5473static pm_next_node_t *
5474pm_next_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
5475 assert(keyword->type == PM_TOKEN_KEYWORD_NEXT);
5476 pm_next_node_t *node = PM_NODE_ALLOC(parser, pm_next_node_t);
5478 *node = (pm_next_node_t) {
5481 ? PM_NODE_INIT_TOKEN(parser, PM_NEXT_NODE, 0, keyword)
5482 : PM_NODE_INIT_TOKEN_NODE(parser, PM_NEXT_NODE, 0, keyword, arguments)
5484 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
5485 .arguments = arguments
5494static pm_nil_node_t *
5495pm_nil_node_create(pm_parser_t *parser, const pm_token_t *token) {
5496 assert(token->type == PM_TOKEN_KEYWORD_NIL);
5497 pm_nil_node_t *node = PM_NODE_ALLOC(parser, pm_nil_node_t);
5499 *node = (pm_nil_node_t) {
5500 .base = PM_NODE_INIT_TOKEN(parser, PM_NIL_NODE, PM_NODE_FLAG_STATIC_LITERAL, token)
5509static pm_no_keywords_parameter_node_t *
5510pm_no_keywords_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
5511 assert(operator->type == PM_TOKEN_USTAR_STAR || operator->type == PM_TOKEN_STAR_STAR);
5512 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
5513 pm_no_keywords_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_no_keywords_parameter_node_t);
5515 *node = (pm_no_keywords_parameter_node_t) {
5516 .base = PM_NODE_INIT_TOKENS(parser, PM_NO_KEYWORDS_PARAMETER_NODE, 0, operator, keyword),
5517 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5518 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
5527static pm_numbered_parameters_node_t *
5528pm_numbered_parameters_node_create(pm_parser_t *parser, const pm_location_t *location, uint8_t maximum) {
5529 pm_numbered_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_parameters_node_t);
5531 *node = (pm_numbered_parameters_node_t) {
5532 .base = PM_NODE_INIT_TOKEN(parser, PM_NUMBERED_PARAMETERS_NODE, 0, location),
5543#define NTH_REF_MAX ((uint32_t) (INT_MAX >> 1))
5552pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *token) {
5553 const uint8_t *start = token->start + 1;
5554 const uint8_t *end = token->end;
5556 ptrdiff_t diff = end - start;
5558#if PTRDIFF_MAX > SIZE_MAX
5559 assert(diff < (ptrdiff_t) SIZE_MAX);
5561 size_t length = (size_t) diff;
5563 char *digits = xcalloc(length + 1, sizeof(char));
5564 memcpy(digits, start, length);
5565 digits[length] = '\0';
5569 unsigned long value = strtoul(digits, &endptr, 10);
5571 if ((digits == endptr) || (*endptr != '\0')) {
5572 pm_parser_err(parser, start, end, PM_ERR_INVALID_NUMBER_DECIMAL);
5578 if ((errno == ERANGE) || (value > NTH_REF_MAX)) {
5579 PM_PARSER_WARN_FORMAT(parser, start, end, PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start);
5583 return (uint32_t) value;
5591static pm_numbered_reference_read_node_t *
5592pm_numbered_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5593 assert(name->type == PM_TOKEN_NUMBERED_REFERENCE);
5594 pm_numbered_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_reference_read_node_t);
5596 *node = (pm_numbered_reference_read_node_t) {
5597 .base = PM_NODE_INIT_TOKEN(parser, PM_NUMBERED_REFERENCE_READ_NODE, 0, name),
5598 .number = pm_numbered_reference_read_node_number(parser, name)
5607static pm_optional_parameter_node_t *
5608pm_optional_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator, pm_node_t *value) {
5609 pm_optional_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_parameter_node_t);
5611 *node = (pm_optional_parameter_node_t) {
5612 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_OPTIONAL_PARAMETER_NODE, 0, name, value),
5613 .name = pm_parser_constant_id_token(parser, name),
5614 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5615 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5625static pm_or_node_t *
5626pm_or_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
5627 pm_assert_value_expression(parser, left);
5629 pm_or_node_t *node = PM_NODE_ALLOC(parser, pm_or_node_t);
5631 *node = (pm_or_node_t) {
5632 .base = PM_NODE_INIT_NODES(parser, PM_OR_NODE, 0, left, right),
5635 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5644static pm_parameters_node_t *
5645pm_parameters_node_create(pm_parser_t *parser) {
5646 pm_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_parameters_node_t);
5648 *node = (pm_parameters_node_t) {
5649 .base = PM_NODE_INIT_UNSET(parser, PM_PARAMETERS_NODE, 0),
5651 .keyword_rest = NULL,
5666pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param) {
5667 if (params->base.location.start == NULL) {
5668 params->base.location.start = param->location.start;
5670 params->base.location.start = params->base.location.start < param->location.start ? params->base.location.start : param->location.start;
5673 if (params->base.location.end == NULL) {
5674 params->base.location.end = param->location.end;
5676 params->base.location.end = params->base.location.end > param->location.end ? params->base.location.end : param->location.end;
5684pm_parameters_node_requireds_append(pm_parameters_node_t *params, pm_node_t *param) {
5685 pm_parameters_node_location_set(params, param);
5686 pm_node_list_append(¶ms->requireds, param);
5693pm_parameters_node_optionals_append(pm_parameters_node_t *params, pm_optional_parameter_node_t *param) {
5694 pm_parameters_node_location_set(params, UP(param));
5695 pm_node_list_append(¶ms->optionals, UP(param));
5702pm_parameters_node_posts_append(pm_parameters_node_t *params, pm_node_t *param) {
5703 pm_parameters_node_location_set(params, param);
5704 pm_node_list_append(¶ms->posts, param);
5711pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
5712 pm_parameters_node_location_set(params, param);
5713 params->rest = param;
5720pm_parameters_node_keywords_append(pm_parameters_node_t *params, pm_node_t *param) {
5721 pm_parameters_node_location_set(params, param);
5722 pm_node_list_append(¶ms->keywords, param);
5729pm_parameters_node_keyword_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
5730 assert(params->keyword_rest == NULL);
5731 pm_parameters_node_location_set(params, param);
5732 params->keyword_rest = param;
5739pm_parameters_node_block_set(pm_parameters_node_t *params, pm_block_parameter_node_t *param) {
5740 assert(params->block == NULL);
5741 pm_parameters_node_location_set(params, UP(param));
5742 params->block = param;
5748static pm_program_node_t *
5749pm_program_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, pm_statements_node_t *statements) {
5750 pm_program_node_t *node = PM_NODE_ALLOC(parser, pm_program_node_t);
5752 *node = (pm_program_node_t) {
5753 .base = PM_NODE_INIT_NODE(parser, PM_PROGRAM_NODE, 0, statements),
5755 .statements = statements
5764static pm_parentheses_node_t *
5765pm_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) {
5766 pm_parentheses_node_t *node = PM_NODE_ALLOC(parser, pm_parentheses_node_t);
5768 *node = (pm_parentheses_node_t) {
5769 .base = PM_NODE_INIT_TOKENS(parser, PM_PARENTHESES_NODE, flags, opening, closing),
5771 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5772 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
5781static pm_pinned_expression_node_t *
5782pm_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) {
5783 pm_pinned_expression_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_expression_node_t);
5785 *node = (pm_pinned_expression_node_t) {
5786 .base = PM_NODE_INIT_TOKENS(parser, PM_PINNED_EXPRESSION_NODE, 0, operator, rparen),
5787 .expression = expression,
5788 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5789 .lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen),
5790 .rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen)
5799static pm_pinned_variable_node_t *
5800pm_pinned_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
5801 pm_pinned_variable_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_variable_node_t);
5803 *node = (pm_pinned_variable_node_t) {
5804 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_PINNED_VARIABLE_NODE, 0, operator, variable),
5805 .variable = variable,
5806 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5815static pm_post_execution_node_t *
5816pm_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) {
5817 pm_post_execution_node_t *node = PM_NODE_ALLOC(parser, pm_post_execution_node_t);
5819 *node = (pm_post_execution_node_t) {
5820 .base = PM_NODE_INIT_TOKENS(parser, PM_POST_EXECUTION_NODE, 0, keyword, closing),
5821 .statements = statements,
5822 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
5823 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5824 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
5833static pm_pre_execution_node_t *
5834pm_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) {
5835 pm_pre_execution_node_t *node = PM_NODE_ALLOC(parser, pm_pre_execution_node_t);
5837 *node = (pm_pre_execution_node_t) {
5838 .base = PM_NODE_INIT_TOKENS(parser, PM_PRE_EXECUTION_NODE, 0, keyword, closing),
5839 .statements = statements,
5840 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
5841 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5842 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
5851static pm_range_node_t *
5852pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
5853 pm_assert_value_expression(parser, left);
5854 pm_assert_value_expression(parser, right);
5856 pm_range_node_t *node = PM_NODE_ALLOC(parser, pm_range_node_t);
5857 pm_node_flags_t flags = 0;
5859 // Indicate that this node is an exclusive range if the operator is `...`.
5860 if (operator->type == PM_TOKEN_DOT_DOT_DOT || operator->type == PM_TOKEN_UDOT_DOT_DOT) {
5861 flags |= PM_RANGE_FLAGS_EXCLUDE_END;
5864 // Indicate that this node is a static literal (i.e., can be compiled with
5865 // a putobject in CRuby) if the left and right are implicit nil, explicit
5866 // nil, or integers.
5868 (left == NULL || PM_NODE_TYPE_P(left, PM_NIL_NODE) || PM_NODE_TYPE_P(left, PM_INTEGER_NODE)) &&
5869 (right == NULL || PM_NODE_TYPE_P(right, PM_NIL_NODE) || PM_NODE_TYPE_P(right, PM_INTEGER_NODE))
5871 flags |= PM_NODE_FLAG_STATIC_LITERAL;
5874 *node = (pm_range_node_t) {
5875 .base = PM_NODE_INIT(parser, PM_RANGE_NODE, flags, (left == NULL ? operator->start : left->location.start), (right == NULL ? operator->end : right->location.end)),
5878 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5887static pm_redo_node_t *
5888pm_redo_node_create(pm_parser_t *parser, const pm_token_t *token) {
5889 assert(token->type == PM_TOKEN_KEYWORD_REDO);
5890 pm_redo_node_t *node = PM_NODE_ALLOC(parser, pm_redo_node_t);
5892 *node = (pm_redo_node_t) {
5893 .base = PM_NODE_INIT_TOKEN(parser, PM_REDO_NODE, 0, token)
5903static pm_regular_expression_node_t *
5904pm_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) {
5905 pm_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_regular_expression_node_t);
5906 pm_node_flags_t flags = pm_regular_expression_flags_create(parser, closing) | PM_NODE_FLAG_STATIC_LITERAL;
5908 *node = (pm_regular_expression_node_t) {
5909 .base = PM_NODE_INIT_TOKENS(parser, PM_REGULAR_EXPRESSION_NODE, flags, opening, closing),
5910 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5911 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
5912 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
5913 .unescaped = *unescaped
5922static inline pm_regular_expression_node_t *
5923pm_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
5924 return pm_regular_expression_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
5930static pm_required_parameter_node_t *
5931pm_required_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
5932 pm_required_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_parameter_node_t);
5934 *node = (pm_required_parameter_node_t) {
5935 .base = PM_NODE_INIT_TOKEN(parser, PM_REQUIRED_PARAMETER_NODE, 0, token),
5936 .name = pm_parser_constant_id_token(parser, token)
5945static pm_rescue_modifier_node_t *
5946pm_rescue_modifier_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *keyword, pm_node_t *rescue_expression) {
5947 pm_rescue_modifier_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_modifier_node_t);
5949 *node = (pm_rescue_modifier_node_t) {
5950 .base = PM_NODE_INIT_NODES(parser, PM_RESCUE_MODIFIER_NODE, 0, expression, rescue_expression),
5951 .expression = expression,
5952 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
5953 .rescue_expression = rescue_expression
5962static pm_rescue_node_t *
5963pm_rescue_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
5964 pm_rescue_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_node_t);
5966 *node = (pm_rescue_node_t) {
5967 .base = PM_NODE_INIT_TOKEN(parser, PM_RESCUE_NODE, 0, keyword),
5968 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
5969 .operator_loc = { 0 },
5970 .then_keyword_loc = { 0 },
5981pm_rescue_node_operator_set(pm_rescue_node_t *node, const pm_token_t *operator) {
5982 node->operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
5989pm_rescue_node_reference_set(pm_rescue_node_t *node, pm_node_t *reference) {
5990 node->reference = reference;
5991 node->base.location.end = reference->location.end;
5998pm_rescue_node_statements_set(pm_rescue_node_t *node, pm_statements_node_t *statements) {
5999 node->statements = statements;
6000 if (pm_statements_node_body_length(statements) > 0) {
6001 node->base.location.end = statements->base.location.end;
6009pm_rescue_node_subsequent_set(pm_rescue_node_t *node, pm_rescue_node_t *subsequent) {
6010 node->subsequent = subsequent;
6011 node->base.location.end = subsequent->base.location.end;
6018pm_rescue_node_exceptions_append(pm_rescue_node_t *node, pm_node_t *exception) {
6019 pm_node_list_append(&node->exceptions, exception);
6020 node->base.location.end = exception->location.end;
6026static pm_rest_parameter_node_t *
6027pm_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
6028 pm_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_rest_parameter_node_t);
6030 *node = (pm_rest_parameter_node_t) {
6032 (name->type == PM_TOKEN_NOT_PROVIDED)
6033 ? PM_NODE_INIT_TOKEN(parser, PM_REST_PARAMETER_NODE, 0, operator)
6034 : PM_NODE_INIT_TOKENS(parser, PM_REST_PARAMETER_NODE, 0, operator, name)
6036 .name = pm_parser_optional_constant_id_token(parser, name),
6037 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
6038 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6047static pm_retry_node_t *
6048pm_retry_node_create(pm_parser_t *parser, const pm_token_t *token) {
6049 assert(token->type == PM_TOKEN_KEYWORD_RETRY);
6050 pm_retry_node_t *node = PM_NODE_ALLOC(parser, pm_retry_node_t);
6052 *node = (pm_retry_node_t) {
6053 .base = PM_NODE_INIT_TOKEN(parser, PM_RETRY_NODE, 0, token)
6062static pm_return_node_t *
6063pm_return_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6064 pm_return_node_t *node = PM_NODE_ALLOC(parser, pm_return_node_t);
6066 *node = (pm_return_node_t) {
6069 ? PM_NODE_INIT_TOKEN(parser, PM_RETURN_NODE, 0, keyword)
6070 : PM_NODE_INIT_TOKEN_NODE(parser, PM_RETURN_NODE, 0, keyword, arguments)
6072 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6073 .arguments = arguments
6082static pm_self_node_t *
6083pm_self_node_create(pm_parser_t *parser, const pm_token_t *token) {
6084 assert(token->type == PM_TOKEN_KEYWORD_SELF);
6085 pm_self_node_t *node = PM_NODE_ALLOC(parser, pm_self_node_t);
6087 *node = (pm_self_node_t) {
6088 .base = PM_NODE_INIT_TOKEN(parser, PM_SELF_NODE, 0, token)
6097static pm_shareable_constant_node_t *
6098pm_shareable_constant_node_create(pm_parser_t *parser, pm_node_t *write, pm_shareable_constant_value_t value) {
6099 pm_shareable_constant_node_t *node = PM_NODE_ALLOC(parser, pm_shareable_constant_node_t);
6101 *node = (pm_shareable_constant_node_t) {
6102 .base = PM_NODE_INIT_NODE(parser, PM_SHAREABLE_CONSTANT_NODE, (pm_node_flags_t) value, write),
6112static pm_singleton_class_node_t *
6113pm_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) {
6114 pm_singleton_class_node_t *node = PM_NODE_ALLOC(parser, pm_singleton_class_node_t);
6116 *node = (pm_singleton_class_node_t) {
6117 .base = PM_NODE_INIT_TOKENS(parser, PM_SINGLETON_CLASS_NODE, 0, class_keyword, end_keyword),
6119 .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
6120 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6121 .expression = expression,
6123 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
6132static pm_source_encoding_node_t *
6133pm_source_encoding_node_create(pm_parser_t *parser, const pm_token_t *token) {
6134 assert(token->type == PM_TOKEN_KEYWORD___ENCODING__);
6135 pm_source_encoding_node_t *node = PM_NODE_ALLOC(parser, pm_source_encoding_node_t);
6137 *node = (pm_source_encoding_node_t) {
6138 .base = PM_NODE_INIT_TOKEN(parser, PM_SOURCE_ENCODING_NODE, PM_NODE_FLAG_STATIC_LITERAL, token)
6147static pm_source_file_node_t*
6148pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword) {
6149 pm_source_file_node_t *node = PM_NODE_ALLOC(parser, pm_source_file_node_t);
6150 assert(file_keyword->type == PM_TOKEN_KEYWORD___FILE__);
6152 pm_node_flags_t flags = 0;
6154 switch (parser->frozen_string_literal) {
6155 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6156 flags |= PM_STRING_FLAGS_MUTABLE;
6158 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6159 flags |= PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6163 *node = (pm_source_file_node_t) {
6164 .base = PM_NODE_INIT_TOKEN(parser, PM_SOURCE_FILE_NODE, flags, file_keyword),
6165 .filepath = parser->filepath
6174static pm_source_line_node_t *
6175pm_source_line_node_create(pm_parser_t *parser, const pm_token_t *token) {
6176 assert(token->type == PM_TOKEN_KEYWORD___LINE__);
6177 pm_source_line_node_t *node = PM_NODE_ALLOC(parser, pm_source_line_node_t);
6179 *node = (pm_source_line_node_t) {
6180 .base = PM_NODE_INIT_TOKEN(parser, PM_SOURCE_LINE_NODE, PM_NODE_FLAG_STATIC_LITERAL, token)
6189static pm_splat_node_t *
6190pm_splat_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
6191 pm_splat_node_t *node = PM_NODE_ALLOC(parser, pm_splat_node_t);
6193 *node = (pm_splat_node_t) {
6195 (expression == NULL)
6196 ? PM_NODE_INIT_TOKEN(parser, PM_SPLAT_NODE, 0, operator)
6197 : PM_NODE_INIT_TOKEN_NODE(parser, PM_SPLAT_NODE, 0, operator, expression)
6199 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6200 .expression = expression
6209static pm_statements_node_t *
6210pm_statements_node_create(pm_parser_t *parser) {
6211 pm_statements_node_t *node = PM_NODE_ALLOC(parser, pm_statements_node_t);
6213 *node = (pm_statements_node_t) {
6214 .base = PM_NODE_INIT_BASE(parser, PM_STATEMENTS_NODE, 0),
6225pm_statements_node_body_length(pm_statements_node_t *node) {
6226 return node && node->body.size;
6233pm_statements_node_location_set(pm_statements_node_t *node, const uint8_t *start, const uint8_t *end) {
6234 node->base.location = (pm_location_t) { .start = start, .end = end };
6242pm_statements_node_body_update(pm_statements_node_t *node, pm_node_t *statement) {
6243 if (pm_statements_node_body_length(node) == 0 || statement->location.start < node->base.location.start) {
6244 node->base.location.start = statement->location.start;
6247 if (statement->location.end > node->base.location.end) {
6248 node->base.location.end = statement->location.end;
6256pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline) {
6257 pm_statements_node_body_update(node, statement);
6259 if (node->body.size > 0) {
6260 const pm_node_t *previous = node->body.nodes[node->body.size - 1];
6262 switch (PM_NODE_TYPE(previous)) {
6267 case PM_RETURN_NODE:
6268 pm_parser_warn_node(parser, statement, PM_WARN_UNREACHABLE_STATEMENT);
6275 pm_node_list_append(&node->body, statement);
6276 if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
6283pm_statements_node_body_prepend(pm_statements_node_t *node, pm_node_t *statement) {
6284 pm_statements_node_body_update(node, statement);
6285 pm_node_list_prepend(&node->body, statement);
6286 pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
6292static inline pm_string_node_t *
6293pm_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) {
6294 pm_string_node_t *node = PM_NODE_ALLOC(parser, pm_string_node_t);
6295 pm_node_flags_t flags = 0;
6297 switch (parser->frozen_string_literal) {
6298 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6299 flags = PM_STRING_FLAGS_MUTABLE;
6301 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6302 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6306 const uint8_t *start = (opening->type == PM_TOKEN_NOT_PROVIDED ? content->start : opening->start);
6307 const uint8_t *end = (closing->type == PM_TOKEN_NOT_PROVIDED ? content->end : closing->end);
6309 *node = (pm_string_node_t) {
6310 .base = PM_NODE_INIT(parser, PM_STRING_NODE, flags, start, end),
6311 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
6312 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
6313 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
6314 .unescaped = *string
6323static pm_string_node_t *
6324pm_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6325 return pm_string_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6332static pm_string_node_t *
6333pm_string_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6334 pm_string_node_t *node = pm_string_node_create_unescaped(parser, opening, content, closing, &parser->current_string);
6335 parser->current_string = PM_STRING_EMPTY;
6342static pm_super_node_t *
6343pm_super_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_t *arguments) {
6344 assert(keyword->type == PM_TOKEN_KEYWORD_SUPER);
6345 pm_super_node_t *node = PM_NODE_ALLOC(parser, pm_super_node_t);
6347 const uint8_t *end = pm_arguments_end(arguments);
6349 assert(false && "unreachable");
6352 *node = (pm_super_node_t) {
6353 .base = PM_NODE_INIT(parser, PM_SUPER_NODE, 0, keyword->start, end),
6354 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6355 .lparen_loc = arguments->opening_loc,
6356 .arguments = arguments->arguments,
6357 .rparen_loc = arguments->closing_loc,
6358 .block = arguments->block
6369pm_ascii_only_p(const pm_string_t *contents) {
6370 const size_t length = pm_string_length(contents);
6371 const uint8_t *source = pm_string_source(contents);
6373 for (size_t index = 0; index < length; index++) {
6374 if (source[index] & 0x80) return false;
6384parse_symbol_encoding_validate_utf8(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
6385 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
6386 size_t width = pm_encoding_utf_8_char_width(cursor, end - cursor);
6389 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
6402parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
6403 const pm_encoding_t *encoding = parser->encoding;
6405 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
6406 size_t width = encoding->char_width(cursor, end - cursor);
6409 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
6426static inline pm_node_flags_t
6427parse_symbol_encoding(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents, bool validate) {
6428 if (parser->explicit_encoding != NULL) {
6429 // A Symbol may optionally have its encoding explicitly set. This will
6430 // happen if an escape sequence results in a non-ASCII code point.
6431 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
6432 if (validate) parse_symbol_encoding_validate_utf8(parser, location, contents);
6433 return PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING;
6434 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
6435 return PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING;
6436 } else if (validate) {
6437 parse_symbol_encoding_validate_other(parser, location, contents);
6439 } else if (pm_ascii_only_p(contents)) {
6440 // Ruby stipulates that all source files must use an ASCII-compatible
6441 // encoding. Thus, all symbols appearing in source are eligible for
6442 // "downgrading" to US-ASCII.
6443 return PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING;
6444 } else if (validate) {
6445 parse_symbol_encoding_validate_other(parser, location, contents);
6451static pm_node_flags_t
6452parse_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) {
6453 assert ((modifier == 'n' && modifier_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) ||
6454 (modifier == 'u' && modifier_encoding == PM_ENCODING_UTF_8_ENTRY) ||
6455 (modifier == 'e' && modifier_encoding == PM_ENCODING_EUC_JP_ENTRY) ||
6456 (modifier == 's' && modifier_encoding == PM_ENCODING_WINDOWS_31J_ENTRY));
6458 // There's special validation logic used if a string does not contain any character escape sequences.
6459 if (parser->explicit_encoding == NULL) {
6460 // If an ASCII-only string without character escapes is used with an encoding modifier, then resulting Regexp
6461 // has the modifier encoding, unless the ASCII-8BIT modifier is used, in which case the Regexp "downgrades" to
6462 // the US-ASCII encoding.
6464 return modifier == 'n' ? PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING : flags;
6467 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
6469 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
6471 } else if (parser->encoding != modifier_encoding) {
6472 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_ENCODING_OPTION_MISMATCH, modifier, parser->encoding->name);
6474 if (modifier == 'n' && !ascii_only) {
6475 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));
6482 // 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.
6483 bool mixed_encoding = false;
6485 if (mixed_encoding) {
6486 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
6487 } else if (modifier != 'n' && parser->explicit_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) {
6488 // 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.
6489 bool valid_string_in_modifier_encoding = true;
6491 if (!valid_string_in_modifier_encoding) {
6492 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
6494 } else if (modifier != 'u' && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
6495 // 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.
6496 if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
6497 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));
6501 // We've determined the encoding would naturally be EUC-JP and there is no need to force the encoding to anything else.
6511static pm_node_flags_t
6512parse_and_validate_regular_expression_encoding(pm_parser_t *parser, const pm_string_t *source, bool ascii_only, pm_node_flags_t flags) {
6513 // 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.
6514 bool valid_unicode_range = true;
6515 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY && !valid_unicode_range) {
6516 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));
6520 // US-ASCII strings do not admit multi-byte character literals. However, character escape sequences corresponding
6521 // to multi-byte characters are allowed.
6522 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY && parser->explicit_encoding == NULL && !ascii_only) {
6523 // CRuby will continue processing even though a SyntaxError has already been detected. It may result in the
6524 // following error message appearing twice. We do the same for compatibility.
6525 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
6536 if (flags & PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT) {
6537 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'n', PM_ENCODING_ASCII_8BIT_ENTRY);
6540 if (flags & PM_REGULAR_EXPRESSION_FLAGS_UTF_8) {
6541 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'u', PM_ENCODING_UTF_8_ENTRY);
6544 if (flags & PM_REGULAR_EXPRESSION_FLAGS_EUC_JP) {
6545 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'e', PM_ENCODING_EUC_JP_ENTRY);
6548 if (flags & PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J) {
6549 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 's', PM_ENCODING_WINDOWS_31J_ENTRY);
6552 // At this point no encoding modifiers will be present on the regular expression as they would have already
6553 // been processed. Ruby stipulates that all source files must use an ASCII-compatible encoding. Thus, all
6554 // regular expressions without an encoding modifier appearing in source are eligible for "downgrading" to US-ASCII.
6556 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING;
6559 // A Regexp may optionally have its encoding explicitly set via a character escape sequence in the source string
6560 // or by specifying a modifier.
6562 // NB: an explicitly set encoding is ignored by Ruby if the Regexp consists of only US ASCII code points.
6563 if (parser->explicit_encoding != NULL) {
6564 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
6565 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING;
6566 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
6567 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING;
6578static pm_symbol_node_t *
6579pm_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) {
6580 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
6582 const uint8_t *start = (opening->type == PM_TOKEN_NOT_PROVIDED ? value->start : opening->start);
6583 const uint8_t *end = (closing->type == PM_TOKEN_NOT_PROVIDED ? value->end : closing->end);
6585 *node = (pm_symbol_node_t) {
6586 .base = PM_NODE_INIT(parser, PM_SYMBOL_NODE, PM_NODE_FLAG_STATIC_LITERAL | flags, start, end),
6587 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
6588 .value_loc = PM_LOCATION_TOKEN_VALUE(value),
6589 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
6590 .unescaped = *unescaped
6599static inline pm_symbol_node_t *
6600pm_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
6601 return pm_symbol_node_create_unescaped(parser, opening, value, closing, &PM_STRING_EMPTY, 0);
6607static pm_symbol_node_t *
6608pm_symbol_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
6609 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));
6610 parser->current_string = PM_STRING_EMPTY;
6617static pm_symbol_node_t *
6618pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
6619 pm_symbol_node_t *node;
6621 switch (token->type) {
6622 case PM_TOKEN_LABEL: {
6623 pm_token_t opening = not_provided(parser);
6624 pm_token_t closing = { .type = PM_TOKEN_LABEL_END, .start = token->end - 1, .end = token->end };
6626 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end - 1 };
6627 node = pm_symbol_node_create(parser, &opening, &label, &closing);
6629 assert((label.end - label.start) >= 0);
6630 pm_string_shared_init(&node->unescaped, label.start, label.end);
6631 pm_node_flag_set(UP(node), parse_symbol_encoding(parser, &label, &node->unescaped, false));
6635 case PM_TOKEN_MISSING: {
6636 pm_token_t opening = not_provided(parser);
6637 pm_token_t closing = not_provided(parser);
6639 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end };
6640 node = pm_symbol_node_create(parser, &opening, &label, &closing);
6644 assert(false && "unreachable");
6655static pm_symbol_node_t *
6656pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
6657 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
6659 *node = (pm_symbol_node_t) {
6660 .base = PM_NODE_INIT_BASE(parser, PM_SYMBOL_NODE, PM_NODE_FLAG_STATIC_LITERAL | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING),
6661 .value_loc = PM_LOCATION_NULL_VALUE(parser),
6665 pm_string_constant_init(&node->unescaped, content, strlen(content));
6673pm_symbol_node_label_p(pm_node_t *node) {
6674 const uint8_t *end = NULL;
6676 switch (PM_NODE_TYPE(node)) {
6677 case PM_SYMBOL_NODE:
6678 end = ((pm_symbol_node_t *) node)->closing_loc.end;
6680 case PM_INTERPOLATED_SYMBOL_NODE:
6681 end = ((pm_interpolated_symbol_node_t *) node)->closing_loc.end;
6687 return (end != NULL) && (end[-1] == ':');
6693static pm_symbol_node_t *
6694pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const pm_token_t *opening, const pm_token_t *closing) {
6695 pm_symbol_node_t *new_node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
6697 *new_node = (pm_symbol_node_t) {
6698 .base = PM_NODE_INIT_TOKENS(parser, PM_SYMBOL_NODE, PM_NODE_FLAG_STATIC_LITERAL, opening, closing),
6699 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
6700 .value_loc = node->content_loc,
6701 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
6702 .unescaped = node->unescaped
6705 pm_token_t content = { .type = PM_TOKEN_IDENTIFIER, .start = node->content_loc.start, .end = node->content_loc.end };
6706 pm_node_flag_set(UP(new_node), parse_symbol_encoding(parser, &content, &node->unescaped, true));
6708 // We are explicitly _not_ using pm_node_destroy here because we don't want
6709 // to trash the unescaped string. We could instead copy the string if we
6710 // know that it is owned, but we're taking the fast path for now.
6719static pm_string_node_t *
6720pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
6721 pm_string_node_t *new_node = PM_NODE_ALLOC(parser, pm_string_node_t);
6722 pm_node_flags_t flags = 0;
6724 switch (parser->frozen_string_literal) {
6725 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6726 flags = PM_STRING_FLAGS_MUTABLE;
6728 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6729 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6733 *new_node = (pm_string_node_t) {
6734 .base = PM_NODE_INIT_NODE(parser, PM_STRING_NODE, flags, node),
6735 .opening_loc = node->opening_loc,
6736 .content_loc = node->value_loc,
6737 .closing_loc = node->closing_loc,
6738 .unescaped = node->unescaped
6741 // We are explicitly _not_ using pm_node_destroy here because we don't want
6742 // to trash the unescaped string. We could instead copy the string if we
6743 // know that it is owned, but we're taking the fast path for now.
6752static pm_true_node_t *
6753pm_true_node_create(pm_parser_t *parser, const pm_token_t *token) {
6754 assert(token->type == PM_TOKEN_KEYWORD_TRUE);
6755 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
6757 *node = (pm_true_node_t) {
6758 .base = PM_NODE_INIT_TOKEN(parser, PM_TRUE_NODE, PM_NODE_FLAG_STATIC_LITERAL, token)
6767static pm_true_node_t *
6768pm_true_node_synthesized_create(pm_parser_t *parser) {
6769 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
6771 *node = (pm_true_node_t) {
6772 .base = PM_NODE_INIT_BASE(parser, PM_TRUE_NODE, PM_NODE_FLAG_STATIC_LITERAL)
6781static pm_undef_node_t *
6782pm_undef_node_create(pm_parser_t *parser, const pm_token_t *token) {
6783 assert(token->type == PM_TOKEN_KEYWORD_UNDEF);
6784 pm_undef_node_t *node = PM_NODE_ALLOC(parser, pm_undef_node_t);
6786 *node = (pm_undef_node_t) {
6787 .base = PM_NODE_INIT_TOKEN(parser, PM_UNDEF_NODE, 0, token),
6788 .keyword_loc = PM_LOCATION_TOKEN_VALUE(token),
6799pm_undef_node_append(pm_undef_node_t *node, pm_node_t *name) {
6800 node->base.location.end = name->location.end;
6801 pm_node_list_append(&node->names, name);
6807static pm_unless_node_t *
6808pm_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) {
6809 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6811 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
6812 pm_node_t *end = statements == NULL ? predicate : UP(statements);
6814 *node = (pm_unless_node_t) {
6815 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_UNLESS_NODE, PM_NODE_FLAG_NEWLINE, keyword, end),
6816 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6817 .predicate = predicate,
6818 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
6819 .statements = statements,
6820 .else_clause = NULL,
6821 .end_keyword_loc = { 0 }
6830static pm_unless_node_t *
6831pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *unless_keyword, pm_node_t *predicate) {
6832 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6833 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
6835 pm_statements_node_t *statements = pm_statements_node_create(parser);
6836 pm_statements_node_body_append(parser, statements, statement, true);
6838 *node = (pm_unless_node_t) {
6839 .base = PM_NODE_INIT_NODES(parser, PM_UNLESS_NODE, PM_NODE_FLAG_NEWLINE, statement, predicate),
6840 .keyword_loc = PM_LOCATION_TOKEN_VALUE(unless_keyword),
6841 .predicate = predicate,
6842 .then_keyword_loc = { 0 },
6843 .statements = statements,
6844 .else_clause = NULL,
6845 .end_keyword_loc = { 0 }
6852pm_unless_node_end_keyword_loc_set(pm_unless_node_t *node, const pm_token_t *end_keyword) {
6853 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
6854 node->base.location.end = end_keyword->end;
6863pm_loop_modifier_block_exits(pm_parser_t *parser, pm_statements_node_t *statements) {
6864 assert(parser->current_block_exits != NULL);
6866 // All of the block exits that we want to remove should be within the
6867 // statements, and since we are modifying the statements, we shouldn't have
6868 // to check the end location.
6869 const uint8_t *start = statements->base.location.start;
6871 for (size_t index = parser->current_block_exits->size; index > 0; index--) {
6872 pm_node_t *block_exit = parser->current_block_exits->nodes[index - 1];
6873 if (block_exit->location.start < start) break;
6875 // Implicitly remove from the list by lowering the size.
6876 parser->current_block_exits->size--;
6883static pm_until_node_t *
6884pm_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) {
6885 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
6886 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6888 *node = (pm_until_node_t) {
6889 .base = PM_NODE_INIT_TOKENS(parser, PM_UNTIL_NODE, flags, keyword, closing),
6890 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6891 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
6892 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
6893 .predicate = predicate,
6894 .statements = statements
6903static pm_until_node_t *
6904pm_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) {
6905 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
6906 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6907 pm_loop_modifier_block_exits(parser, statements);
6909 *node = (pm_until_node_t) {
6910 .base = PM_NODE_INIT_NODES(parser, PM_UNTIL_NODE, flags, statements, predicate),
6911 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6912 .do_keyword_loc = { 0 },
6913 .closing_loc = { 0 },
6914 .predicate = predicate,
6915 .statements = statements
6924static pm_when_node_t *
6925pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
6926 pm_when_node_t *node = PM_NODE_ALLOC(parser, pm_when_node_t);
6928 *node = (pm_when_node_t) {
6929 .base = PM_NODE_INIT_TOKEN(parser, PM_WHEN_NODE, 0, keyword),
6930 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6932 .then_keyword_loc = { 0 },
6943pm_when_node_conditions_append(pm_when_node_t *node, pm_node_t *condition) {
6944 node->base.location.end = condition->location.end;
6945 pm_node_list_append(&node->conditions, condition);
6952pm_when_node_then_keyword_loc_set(pm_when_node_t *node, const pm_token_t *then_keyword) {
6953 node->base.location.end = then_keyword->end;
6954 node->then_keyword_loc = PM_LOCATION_TOKEN_VALUE(then_keyword);
6961pm_when_node_statements_set(pm_when_node_t *node, pm_statements_node_t *statements) {
6962 if (statements->base.location.end > node->base.location.end) {
6963 node->base.location.end = statements->base.location.end;
6966 node->statements = statements;
6972static pm_while_node_t *
6973pm_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) {
6974 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
6975 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6977 *node = (pm_while_node_t) {
6978 .base = PM_NODE_INIT_TOKENS(parser, PM_WHILE_NODE, flags, keyword, closing),
6979 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6980 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
6981 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
6982 .predicate = predicate,
6983 .statements = statements
6992static pm_while_node_t *
6993pm_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) {
6994 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
6995 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6996 pm_loop_modifier_block_exits(parser, statements);
6998 *node = (pm_while_node_t) {
6999 .base = PM_NODE_INIT_NODES(parser, PM_WHILE_NODE, flags, statements, predicate),
7000 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7001 .do_keyword_loc = { 0 },
7002 .closing_loc = { 0 },
7003 .predicate = predicate,
7004 .statements = statements
7013static pm_while_node_t *
7014pm_while_node_synthesized_create(pm_parser_t *parser, pm_node_t *predicate, pm_statements_node_t *statements) {
7015 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7017 *node = (pm_while_node_t) {
7018 .base = PM_NODE_INIT_BASE(parser, PM_WHILE_NODE, 0),
7019 .keyword_loc = PM_LOCATION_NULL_VALUE(parser),
7020 .do_keyword_loc = PM_LOCATION_NULL_VALUE(parser),
7021 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
7022 .predicate = predicate,
7023 .statements = statements
7033static pm_x_string_node_t *
7034pm_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) {
7035 pm_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_x_string_node_t);
7037 *node = (pm_x_string_node_t) {
7038 .base = PM_NODE_INIT_TOKENS(parser, PM_X_STRING_NODE, PM_STRING_FLAGS_FROZEN, opening, closing),
7039 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
7040 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
7041 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
7042 .unescaped = *unescaped
7051static inline pm_x_string_node_t *
7052pm_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7053 return pm_xstring_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7059static pm_yield_node_t *
7060pm_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) {
7061 pm_yield_node_t *node = PM_NODE_ALLOC(parser, pm_yield_node_t);
7064 if (rparen_loc->start != NULL) {
7065 end = rparen_loc->end;
7066 } else if (arguments != NULL) {
7067 end = arguments->base.location.end;
7068 } else if (lparen_loc->start != NULL) {
7069 end = lparen_loc->end;
7074 *node = (pm_yield_node_t) {
7075 .base = PM_NODE_INIT(parser, PM_YIELD_NODE, 0, keyword->start, end),
7076 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7077 .lparen_loc = *lparen_loc,
7078 .arguments = arguments,
7079 .rparen_loc = *rparen_loc
7090pm_parser_local_depth_constant_id(pm_parser_t *parser, pm_constant_id_t constant_id) {
7091 pm_scope_t *scope = parser->current_scope;
7094 while (scope != NULL) {
7095 if (pm_locals_find(&scope->locals, constant_id) != UINT32_MAX) return depth;
7096 if (scope->closed) break;
7098 scope = scope->previous;
7111pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
7112 return pm_parser_local_depth_constant_id(parser, pm_parser_constant_id_token(parser, token));
7119pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7120 pm_locals_write(&parser->current_scope->locals, constant_id, start, end, reads);
7126static pm_constant_id_t
7127pm_parser_local_add_location(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7128 pm_constant_id_t constant_id = pm_parser_constant_id_location(parser, start, end);
7129 if (constant_id != 0) pm_parser_local_add(parser, constant_id, start, end, reads);
7136static inline pm_constant_id_t
7137pm_parser_local_add_token(pm_parser_t *parser, pm_token_t *token, uint32_t reads) {
7138 return pm_parser_local_add_location(parser, token->start, token->end, reads);
7144static pm_constant_id_t
7145pm_parser_local_add_owned(pm_parser_t *parser, uint8_t *start, size_t length) {
7146 pm_constant_id_t constant_id = pm_parser_constant_id_owned(parser, start, length);
7147 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
7154static pm_constant_id_t
7155pm_parser_local_add_constant(pm_parser_t *parser, const char *start, size_t length) {
7156 pm_constant_id_t constant_id = pm_parser_constant_id_constant(parser, start, length);
7157 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
7169pm_parser_parameter_name_check(pm_parser_t *parser, const pm_token_t *name) {
7170 // We want to check whether the parameter name is a numbered parameter or
7172 pm_refute_numbered_parameter(parser, name->start, name->end);
7174 // Otherwise we'll fetch the constant id for the parameter name and check
7175 // whether it's already in the current scope.
7176 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, name);
7178 if (pm_locals_find(&parser->current_scope->locals, constant_id) != UINT32_MAX) {
7179 // Add an error if the parameter doesn't start with _ and has been seen before
7180 if ((name->start < name->end) && (*name->start != '_')) {
7181 pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NAME_DUPLICATED);
7192pm_parser_scope_pop(pm_parser_t *parser) {
7193 pm_scope_t *scope = parser->current_scope;
7194 parser->current_scope = scope->previous;
7195 pm_locals_free(&scope->locals);
7196 pm_node_list_free(&scope->implicit_parameters);
7200/******************************************************************************/
7202/******************************************************************************/
7208pm_state_stack_push(pm_state_stack_t *stack, bool value) {
7209 *stack = (*stack << 1) | (value & 1);
7216pm_state_stack_pop(pm_state_stack_t *stack) {
7224pm_state_stack_p(const pm_state_stack_t *stack) {
7229pm_accepts_block_stack_push(pm_parser_t *parser, bool value) {
7230 // Use the negation of the value to prevent stack overflow.
7231 pm_state_stack_push(&parser->accepts_block_stack, !value);
7235pm_accepts_block_stack_pop(pm_parser_t *parser) {
7236 pm_state_stack_pop(&parser->accepts_block_stack);
7240pm_accepts_block_stack_p(pm_parser_t *parser) {
7241 return !pm_state_stack_p(&parser->accepts_block_stack);
7245pm_do_loop_stack_push(pm_parser_t *parser, bool value) {
7246 pm_state_stack_push(&parser->do_loop_stack, value);
7250pm_do_loop_stack_pop(pm_parser_t *parser) {
7251 pm_state_stack_pop(&parser->do_loop_stack);
7255pm_do_loop_stack_p(pm_parser_t *parser) {
7256 return pm_state_stack_p(&parser->do_loop_stack);
7259/******************************************************************************/
7260/* Lexer check helpers */
7261/******************************************************************************/
7267static inline uint8_t
7268peek_at(const pm_parser_t *parser, const uint8_t *cursor) {
7269 if (cursor < parser->end) {
7281static inline uint8_t
7282peek_offset(pm_parser_t *parser, ptrdiff_t offset) {
7283 return peek_at(parser, parser->current.end + offset);
7290static inline uint8_t
7291peek(const pm_parser_t *parser) {
7292 return peek_at(parser, parser->current.end);
7300match(pm_parser_t *parser, uint8_t value) {
7301 if (peek(parser) == value) {
7302 parser->current.end++;
7313match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
7314 if (peek_at(parser, cursor) == '\n') {
7317 if (peek_at(parser, cursor) == '\r' && peek_at(parser, cursor + 1) == '\n') {
7329match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
7330 return match_eol_at(parser, parser->current.end + offset);
7339match_eol(pm_parser_t *parser) {
7340 return match_eol_at(parser, parser->current.end);
7346static inline const uint8_t *
7347next_newline(const uint8_t *cursor, ptrdiff_t length) {
7348 assert(length >= 0);
7350 // Note that it's okay for us to use memchr here to look for \n because none
7351 // of the encodings that we support have \n as a component of a multi-byte
7353 return memchr(cursor, '\n', (size_t) length);
7360ambiguous_operator_p(const pm_parser_t *parser, bool space_seen) {
7361 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));
7369parser_lex_magic_comment_encoding_value(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
7370 const pm_encoding_t *encoding = pm_encoding_find(start, end);
7372 if (encoding != NULL) {
7373 if (parser->encoding != encoding) {
7374 parser->encoding = encoding;
7375 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
7378 parser->encoding_changed = (encoding != PM_ENCODING_UTF_8_ENTRY);
7390parser_lex_magic_comment_encoding(pm_parser_t *parser) {
7391 const uint8_t *cursor = parser->current.start + 1;
7392 const uint8_t *end = parser->current.end;
7394 bool separator = false;
7396 if (end - cursor <= 6) return;
7397 switch (cursor[6]) {
7398 case 'C': case 'c': cursor += 6; continue;
7399 case 'O': case 'o': cursor += 5; continue;
7400 case 'D': case 'd': cursor += 4; continue;
7401 case 'I': case 'i': cursor += 3; continue;
7402 case 'N': case 'n': cursor += 2; continue;
7403 case 'G': case 'g': cursor += 1; continue;
7410 if (pm_char_is_whitespace(*cursor)) break;
7413 if (pm_strncasecmp(cursor - 6, (const uint8_t *) "coding", 6) == 0) break;
7419 if (++cursor >= end) return;
7420 } while (pm_char_is_whitespace(*cursor));
7422 if (separator) break;
7423 if (*cursor != '=' && *cursor != ':') return;
7429 const uint8_t *value_start = cursor;
7430 while ((*cursor == '-' || *cursor == '_' || parser->encoding->alnum_char(cursor, 1)) && ++cursor < end);
7432 if (!parser_lex_magic_comment_encoding_value(parser, value_start, cursor)) {
7433 // If we were unable to parse the encoding value, then we've got an
7434 // issue because we didn't understand the encoding that the user was
7435 // trying to use. In this case we'll keep using the default encoding but
7436 // add an error to the parser to indicate an unsuccessful parse.
7437 pm_parser_err(parser, value_start, cursor, PM_ERR_INVALID_ENCODING_MAGIC_COMMENT);
7442 PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE,
7443 PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE,
7444 PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID
7445} pm_magic_comment_boolean_value_t;
7451static pm_magic_comment_boolean_value_t
7452parser_lex_magic_comment_boolean_value(const uint8_t *value_start, uint32_t value_length) {
7453 if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "true", 4) == 0) {
7454 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE;
7455 } else if (value_length == 5 && pm_strncasecmp(value_start, (const uint8_t *) "false", 5) == 0) {
7456 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE;
7458 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID;
7463pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
7464 return b == '\'' || b == '"' || b == ':' || b == ';';
7472static inline const uint8_t *
7473parser_lex_magic_comment_emacs_marker(
pm_parser_t *parser,
const uint8_t *cursor,
const uint8_t *end) {
7474 while ((cursor + 3 <= end) && (cursor = pm_memchr(cursor,
'-', (
size_t) (end - cursor), parser->
encoding_changed, parser->
encoding)) != NULL) {
7475 if (cursor + 3 <= end && cursor[1] ==
'*' && cursor[2] ==
'-') {
7494parser_lex_magic_comment(
pm_parser_t *parser,
bool semantic_token_seen) {
7497 const uint8_t *start = parser->
current.start + 1;
7498 const uint8_t *end = parser->
current.end;
7499 if (end - start <= 7)
return false;
7501 const uint8_t *cursor;
7502 bool indicator =
false;
7504 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
7507 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
7518 while (cursor < end) {
7519 while (cursor < end && (pm_char_is_magic_comment_key_delimiter(*cursor) || pm_char_is_whitespace(*cursor))) cursor++;
7521 const uint8_t *key_start = cursor;
7522 while (cursor < end && (!pm_char_is_magic_comment_key_delimiter(*cursor) && !pm_char_is_whitespace(*cursor))) cursor++;
7524 const uint8_t *key_end = cursor;
7525 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7526 if (cursor == end)
break;
7528 if (*cursor ==
':') {
7531 if (!indicator)
return false;
7535 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7536 if (cursor == end)
break;
7538 const uint8_t *value_start;
7539 const uint8_t *value_end;
7541 if (*cursor ==
'"') {
7542 value_start = ++cursor;
7543 for (; cursor < end && *cursor !=
'"'; cursor++) {
7544 if (*cursor ==
'\\' && (cursor + 1 < end)) cursor++;
7547 if (cursor < end && *cursor ==
'"') cursor++;
7549 value_start = cursor;
7550 while (cursor < end && *cursor !=
'"' && *cursor !=
';' && !pm_char_is_whitespace(*cursor)) cursor++;
7555 while (cursor < end && (*cursor ==
';' || pm_char_is_whitespace(*cursor))) cursor++;
7557 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7558 if (cursor != end)
return false;
7564 const size_t key_length = (size_t) (key_end - key_start);
7568 pm_string_shared_init(&key, key_start, key_end);
7570 uint8_t *buffer =
xmalloc(key_length);
7571 if (buffer == NULL)
break;
7573 memcpy(buffer, key_start, key_length);
7574 buffer[dash - key_start] =
'_';
7576 while ((dash = pm_memchr(dash + 1,
'-', (
size_t) (key_end - dash - 1), parser->
encoding_changed, parser->
encoding)) != NULL) {
7577 buffer[dash - key_start] =
'_';
7580 pm_string_owned_init(&key, buffer, key_length);
7585 const uint8_t *key_source = pm_string_source(&key);
7586 uint32_t value_length = (uint32_t) (value_end - value_start);
7592 (key_length == 8 && pm_strncasecmp(key_source, (
const uint8_t *)
"encoding", 8) == 0) ||
7593 (key_length == 6 && pm_strncasecmp(key_source, (
const uint8_t *)
"coding", 6) == 0)
7595 result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
7599 if (key_length == 11) {
7600 if (pm_strncasecmp(key_source, (
const uint8_t *)
"warn_indent", 11) == 0) {
7601 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7602 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7603 PM_PARSER_WARN_TOKEN_FORMAT(
7606 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7608 (
const char *) key_source,
7610 (
const char *) value_start
7613 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7616 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7621 }
else if (key_length == 21) {
7622 if (pm_strncasecmp(key_source, (
const uint8_t *)
"frozen_string_literal", 21) == 0) {
7625 if (semantic_token_seen) {
7626 pm_parser_warn_token(parser, &parser->
current, PM_WARN_IGNORED_FROZEN_STRING_LITERAL);
7628 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7629 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7630 PM_PARSER_WARN_TOKEN_FORMAT(
7633 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7635 (
const char *) key_source,
7637 (
const char *) value_start
7640 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7643 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7649 }
else if (key_length == 24) {
7650 if (pm_strncasecmp(key_source, (
const uint8_t *)
"shareable_constant_value", 24) == 0) {
7651 const uint8_t *cursor = parser->
current.start;
7652 while ((cursor > parser->
start) && ((cursor[-1] ==
' ') || (cursor[-1] ==
'\t'))) cursor--;
7654 if (!((cursor == parser->
start) || (cursor[-1] ==
'\n'))) {
7655 pm_parser_warn_token(parser, &parser->
current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
7656 }
else if (value_length == 4 && pm_strncasecmp(value_start, (
const uint8_t *)
"none", 4) == 0) {
7657 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
7658 }
else if (value_length == 7 && pm_strncasecmp(value_start, (
const uint8_t *)
"literal", 7) == 0) {
7659 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
7660 }
else if (value_length == 23 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_everything", 23) == 0) {
7661 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING);
7662 }
else if (value_length == 17 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_copy", 17) == 0) {
7663 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY);
7665 PM_PARSER_WARN_TOKEN_FORMAT(
7668 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7670 (
const char *) key_source,
7672 (
const char *) value_start
7680 pm_string_free(&key);
7700static const uint32_t context_terminators[] = {
7702 [
PM_CONTEXT_BEGIN] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7705 [
PM_CONTEXT_BEGIN_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7707 [
PM_CONTEXT_BLOCK_KEYWORDS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7711 [
PM_CONTEXT_BLOCK_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7712 [
PM_CONTEXT_CASE_WHEN] = (1U << PM_TOKEN_KEYWORD_WHEN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
7713 [
PM_CONTEXT_CASE_IN] = (1U << PM_TOKEN_KEYWORD_IN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
7714 [
PM_CONTEXT_CLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7717 [
PM_CONTEXT_CLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7718 [
PM_CONTEXT_DEF] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7721 [
PM_CONTEXT_DEF_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7726 [
PM_CONTEXT_ELSIF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
7730 [
PM_CONTEXT_IF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
7732 [
PM_CONTEXT_LAMBDA_DO_END] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7735 [
PM_CONTEXT_LAMBDA_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7738 [
PM_CONTEXT_MODULE] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7741 [
PM_CONTEXT_MODULE_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7745 [
PM_CONTEXT_PREDICATE] = (1U << PM_TOKEN_KEYWORD_THEN) | (1U << PM_TOKEN_NEWLINE) | (1U << PM_TOKEN_SEMICOLON),
7748 [
PM_CONTEXT_SCLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7751 [
PM_CONTEXT_SCLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7753 [
PM_CONTEXT_UNLESS] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7760 return token->type < 32 && (context_terminators[context] & (1U << token->type));
7771 while (context_node != NULL) {
7772 if (context_terminator(context_node->
context, token))
return context_node->
context;
7773 context_node = context_node->
prev;
7782 if (context_node == NULL)
return false;
7807 while (context_node != NULL) {
7808 if (context_node->
context == context)
return true;
7809 context_node = context_node->
prev;
7819 while (context_node != NULL) {
7820 switch (context_node->
context) {
7841 context_node = context_node->
prev;
7856 assert(
false &&
"unreachable");
7914 assert(
false &&
"unreachable");
7923pm_strspn_number_validate(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const uint8_t *invalid) {
7924 if (invalid != NULL) {
7925 pm_diagnostic_id_t diag_id = (invalid == (
string + length - 1)) ? PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING : PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER;
7926 pm_parser_err(parser, invalid, invalid + 1, diag_id);
7931pm_strspn_binary_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
7932 const uint8_t *invalid = NULL;
7933 size_t length = pm_strspn_binary_number(
string, parser->
end -
string, &invalid);
7934 pm_strspn_number_validate(parser,
string, length, invalid);
7939pm_strspn_octal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
7940 const uint8_t *invalid = NULL;
7941 size_t length = pm_strspn_octal_number(
string, parser->
end -
string, &invalid);
7942 pm_strspn_number_validate(parser,
string, length, invalid);
7947pm_strspn_decimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
7948 const uint8_t *invalid = NULL;
7949 size_t length = pm_strspn_decimal_number(
string, parser->
end -
string, &invalid);
7950 pm_strspn_number_validate(parser,
string, length, invalid);
7955pm_strspn_hexadecimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
7956 const uint8_t *invalid = NULL;
7957 size_t length = pm_strspn_hexadecimal_number(
string, parser->
end -
string, &invalid);
7958 pm_strspn_number_validate(parser,
string, length, invalid);
7962static pm_token_type_t
7963lex_optional_float_suffix(
pm_parser_t *parser,
bool* seen_e) {
7964 pm_token_type_t
type = PM_TOKEN_INTEGER;
7968 if (peek(parser) ==
'.') {
7969 if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
7971 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
7972 type = PM_TOKEN_FLOAT;
7982 if ((peek(parser) ==
'e') || (peek(parser) ==
'E')) {
7983 if ((peek_offset(parser, 1) ==
'+') || (peek_offset(parser, 1) ==
'-')) {
7986 if (pm_char_is_decimal_digit(peek(parser))) {
7988 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
7990 pm_parser_err_current(parser, PM_ERR_INVALID_FLOAT_EXPONENT);
7992 }
else if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
7994 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8000 type = PM_TOKEN_FLOAT;
8006static pm_token_type_t
8007lex_numeric_prefix(
pm_parser_t *parser,
bool* seen_e) {
8008 pm_token_type_t
type = PM_TOKEN_INTEGER;
8011 if (peek_offset(parser, -1) ==
'0') {
8012 switch (*parser->
current.end) {
8017 if (pm_char_is_decimal_digit(peek(parser))) {
8018 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8021 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_DECIMAL);
8030 if (pm_char_is_binary_digit(peek(parser))) {
8031 parser->
current.end += pm_strspn_binary_number_validate(parser, parser->
current.end);
8034 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
8044 if (pm_char_is_octal_digit(peek(parser))) {
8045 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8048 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
8064 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8072 if (pm_char_is_hexadecimal_digit(peek(parser))) {
8073 parser->
current.end += pm_strspn_hexadecimal_number_validate(parser, parser->
current.end);
8076 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
8079 parser->
integer_base = PM_INTEGER_BASE_FLAGS_HEXADECIMAL;
8084 type = lex_optional_float_suffix(parser, seen_e);
8091 type = lex_optional_float_suffix(parser, seen_e);
8098 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8101 type = lex_optional_float_suffix(parser, seen_e);
8107 if (peek_offset(parser, 0) ==
'.' && pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8108 const uint8_t *fraction_start = parser->
current.end;
8109 const uint8_t *fraction_end = parser->
current.end + 2;
8110 fraction_end += pm_strspn_decimal_digit(fraction_end, parser->
end - fraction_end);
8111 pm_parser_err(parser, fraction_start, fraction_end, PM_ERR_INVALID_NUMBER_FRACTION);
8117static pm_token_type_t
8119 pm_token_type_t
type = PM_TOKEN_INTEGER;
8123 bool seen_e =
false;
8124 type = lex_numeric_prefix(parser, &seen_e);
8126 const uint8_t *end = parser->
current.end;
8127 pm_token_type_t suffix_type =
type;
8129 if (
type == PM_TOKEN_INTEGER) {
8130 if (match(parser,
'r')) {
8131 suffix_type = PM_TOKEN_INTEGER_RATIONAL;
8133 if (match(parser,
'i')) {
8134 suffix_type = PM_TOKEN_INTEGER_RATIONAL_IMAGINARY;
8136 }
else if (match(parser,
'i')) {
8137 suffix_type = PM_TOKEN_INTEGER_IMAGINARY;
8140 if (!seen_e && match(parser,
'r')) {
8141 suffix_type = PM_TOKEN_FLOAT_RATIONAL;
8143 if (match(parser,
'i')) {
8144 suffix_type = PM_TOKEN_FLOAT_RATIONAL_IMAGINARY;
8146 }
else if (match(parser,
'i')) {
8147 suffix_type = PM_TOKEN_FLOAT_IMAGINARY;
8151 const uint8_t b = peek(parser);
8152 if (b !=
'\0' && (b >= 0x80 || ((b >=
'a' && b <=
'z') || (b >=
'A' && b <=
'Z')) || b ==
'_')) {
8162static pm_token_type_t
8165 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
8166 return PM_TOKEN_GLOBAL_VARIABLE;
8171 bool allow_multiple =
true;
8173 switch (*parser->
current.end) {
8191 return PM_TOKEN_GLOBAL_VARIABLE;
8198 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_BACK_REFERENCE;
8204 if ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0) {
8207 }
while ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0);
8211 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
current, diag_id);
8214 return PM_TOKEN_GLOBAL_VARIABLE;
8227 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_NUMBERED_REFERENCE;
8231 allow_multiple =
false;
8236 if ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0) {
8239 }
while (allow_multiple && (width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0);
8240 }
else if (pm_char_is_whitespace(peek(parser))) {
8243 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
8249 PM_PARSER_ERR_FORMAT(parser, parser->
current.start, end, diag_id, (
int) (end - parser->
current.start), (
const char *) parser->
current.start);
8252 return PM_TOKEN_GLOBAL_VARIABLE;
8269static inline pm_token_type_t
8270lex_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) {
8271 if (memcmp(current_start, value, vlen) == 0) {
8274 if (parser->
lex_state & PM_LEX_STATE_FNAME) {
8275 lex_state_set(parser, PM_LEX_STATE_ENDFN);
8277 lex_state_set(parser, state);
8278 if (state == PM_LEX_STATE_BEG) {
8282 if ((modifier_type != PM_TOKEN_EOF) && !(last_state & (PM_LEX_STATE_BEG | PM_LEX_STATE_LABELED | PM_LEX_STATE_CLASS))) {
8283 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
8284 return modifier_type;
8291 return PM_TOKEN_EOF;
8294static pm_token_type_t
8295lex_identifier(
pm_parser_t *parser,
bool previous_command_start) {
8298 const uint8_t *end = parser->
end;
8299 const uint8_t *current_start = parser->
current.start;
8300 const uint8_t *current_end = parser->
current.end;
8303 if (encoding_changed) {
8304 while ((width = char_is_identifier(parser, current_end, end - current_end)) > 0) {
8305 current_end += width;
8308 while ((width = char_is_identifier_utf8(current_end, end - current_end)) > 0) {
8309 current_end += width;
8312 parser->
current.end = current_end;
8316 width = (size_t) (current_end - current_start);
8318 if (current_end < end) {
8319 if (((current_end + 1 >= end) || (current_end[1] !=
'=')) && (match(parser,
'!') || match(parser,
'?'))) {
8325 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
8326 (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')
8330 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
8331 (void) match(parser,
':');
8332 return PM_TOKEN_LABEL;
8335 if (parser->
lex_state != PM_LEX_STATE_DOT) {
8336 if (width == 8 && (lex_keyword(parser, current_start,
"defined?", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_DEFINED, PM_TOKEN_EOF) != PM_TOKEN_EOF)) {
8337 return PM_TOKEN_KEYWORD_DEFINED;
8341 return PM_TOKEN_METHOD_NAME;
8344 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,
'=')) {
8347 return PM_TOKEN_IDENTIFIER;
8351 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
8352 peek(parser) ==
':' && peek_offset(parser, 1) !=
':'
8356 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
8357 (void) match(parser,
':');
8358 return PM_TOKEN_LABEL;
8362 if (parser->
lex_state != PM_LEX_STATE_DOT) {
8363 pm_token_type_t
type;
8366 if (lex_keyword(parser, current_start,
"do", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_DO, PM_TOKEN_EOF) != PM_TOKEN_EOF) {
8367 if (pm_do_loop_stack_p(parser)) {
8368 return PM_TOKEN_KEYWORD_DO_LOOP;
8370 return PM_TOKEN_KEYWORD_DO;
8373 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;
8374 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;
8375 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;
8378 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;
8379 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;
8380 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;
8381 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;
8382 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;
8383 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;
8384 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;
8387 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;
8388 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;
8389 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;
8390 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;
8391 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;
8392 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;
8393 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;
8394 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;
8397 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;
8398 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;
8399 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;
8400 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;
8401 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;
8402 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;
8403 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;
8404 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;
8405 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;
8406 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;
8407 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;
8408 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;
8409 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;
8412 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;
8413 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;
8414 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;
8415 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;
8416 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;
8419 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;
8420 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;
8423 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;
8428 if (encoding_changed) {
8429 return parser->
encoding->
isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8431 return pm_encoding_utf_8_isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8457static pm_token_type_t
8458lex_interpolation(
pm_parser_t *parser,
const uint8_t *pound) {
8461 if (pound + 1 >= parser->
end) {
8462 parser->
current.end = pound + 1;
8463 return PM_TOKEN_STRING_CONTENT;
8472 if (pound + 2 >= parser->
end) {
8473 parser->
current.end = pound + 1;
8474 return PM_TOKEN_STRING_CONTENT;
8479 const uint8_t *variable = pound + 2;
8480 if (*variable ==
'@' && pound + 3 < parser->
end) variable++;
8482 if (char_is_identifier_start(parser, variable, parser->
end - variable)) {
8486 if (pound > parser->
current.start) {
8488 return PM_TOKEN_STRING_CONTENT;
8493 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
8494 parser->
current.end = pound + 1;
8495 return PM_TOKEN_EMBVAR;
8501 parser->
current.end = pound + 1;
8502 return PM_TOKEN_NOT_PROVIDED;
8507 if (pound + 2 >= parser->
end) {
8508 parser->
current.end = pound + 1;
8509 return PM_TOKEN_STRING_CONTENT;
8515 const uint8_t *check = pound + 2;
8517 if (pound[2] ==
'-') {
8518 if (pound + 3 >= parser->
end) {
8519 parser->
current.end = pound + 2;
8520 return PM_TOKEN_STRING_CONTENT;
8531 char_is_identifier_start(parser, check, parser->
end - check) ||
8532 (pound[2] !=
'-' && (pm_char_is_decimal_digit(pound[2]) || char_is_global_name_punctuation(pound[2])))
8537 if (pound > parser->
current.start) {
8539 return PM_TOKEN_STRING_CONTENT;
8544 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
8545 parser->
current.end = pound + 1;
8546 return PM_TOKEN_EMBVAR;
8551 parser->
current.end = pound + 1;
8552 return PM_TOKEN_NOT_PROVIDED;
8557 if (pound > parser->
current.start) {
8559 return PM_TOKEN_STRING_CONTENT;
8566 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBEXPR });
8567 parser->
current.end = pound + 2;
8569 pm_do_loop_stack_push(parser,
false);
8570 return PM_TOKEN_EMBEXPR_BEGIN;
8575 parser->
current.end = pound + 1;
8576 return PM_TOKEN_NOT_PROVIDED;
8580static const uint8_t PM_ESCAPE_FLAG_NONE = 0x0;
8581static const uint8_t PM_ESCAPE_FLAG_CONTROL = 0x1;
8582static const uint8_t PM_ESCAPE_FLAG_META = 0x2;
8583static const uint8_t PM_ESCAPE_FLAG_SINGLE = 0x4;
8584static const uint8_t PM_ESCAPE_FLAG_REGEXP = 0x8;
8589static const bool ascii_printable_chars[] = {
8590 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
8591 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8592 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8593 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8594 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8595 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
8596 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8597 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
8601char_is_ascii_printable(
const uint8_t b) {
8602 return (b < 0x80) && ascii_printable_chars[b];
8609static inline uint8_t
8610escape_hexadecimal_digit(
const uint8_t value) {
8611 return (uint8_t) ((value <=
'9') ? (value -
'0') : (value & 0x7) + 9);
8619static inline uint32_t
8622 for (
size_t index = 0; index < length; index++) {
8623 if (index != 0) value <<= 4;
8624 value |= escape_hexadecimal_digit(
string[index]);
8629 if (value >= 0xD800 && value <= 0xDFFF) {
8630 if (error_location != NULL) {
8631 pm_parser_err(parser, error_location->
start, error_location->
end, PM_ERR_ESCAPE_INVALID_UNICODE);
8633 pm_parser_err(parser,
string,
string + length, PM_ERR_ESCAPE_INVALID_UNICODE);
8644static inline uint8_t
8645escape_byte(uint8_t value,
const uint8_t flags) {
8646 if (flags & PM_ESCAPE_FLAG_CONTROL) value &= 0x9f;
8647 if (flags & PM_ESCAPE_FLAG_META) value |= 0x80;
8655escape_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) {
8659 if (value >= 0x80 || flags & PM_ESCAPE_FLAG_SINGLE) {
8667 if (!pm_buffer_append_unicode_codepoint(buffer, value)) {
8668 pm_parser_err(parser, start, end, PM_ERR_ESCAPE_INVALID_UNICODE);
8669 pm_buffer_append_byte(buffer, 0xEF);
8670 pm_buffer_append_byte(buffer, 0xBF);
8671 pm_buffer_append_byte(buffer, 0xBD);
8683 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_MIXED_ENCODING, parser->
encoding->
name);
8689 pm_buffer_append_byte(buffer,
byte);
8709 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8710 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X",
byte);
8713 escape_write_byte_encoded(parser, buffer,
byte);
8725 width = pm_encoding_utf_8_char_width(parser->
current.end, parser->
end - parser->
current.end);
8729 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(*parser->
current.end++, flags));
8730 }
else if (width > 1) {
8732 pm_buffer_t *b = (flags & PM_ESCAPE_FLAG_REGEXP) ? regular_expression_buffer : buffer;
8733 pm_buffer_append_bytes(b, parser->
current.end, width);
8739 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
8749escape_read_warn(
pm_parser_t *parser, uint8_t flags, uint8_t flag,
const char *
type) {
8750#define FLAG(value) ((value & PM_ESCAPE_FLAG_CONTROL) ? "\\C-" : (value & PM_ESCAPE_FLAG_META) ? "\\M-" : "")
8752 PM_PARSER_WARN_TOKEN_FORMAT(
8755 PM_WARN_INVALID_CHARACTER,
8769 uint8_t peeked = peek(parser);
8773 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\\', flags));
8778 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\'', flags));
8783 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\a', flags));
8788 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\b', flags));
8793 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\033', flags));
8798 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\f', flags));
8803 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\n', flags));
8808 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\r', flags));
8813 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
' ', flags));
8818 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\t', flags));
8823 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\v', flags));
8826 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': {
8827 uint8_t value = (uint8_t) (*parser->
current.end -
'0');
8830 if (pm_char_is_octal_digit(peek(parser))) {
8831 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
8834 if (pm_char_is_octal_digit(peek(parser))) {
8835 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
8840 value = escape_byte(value, flags);
8841 escape_write_byte(parser, buffer, regular_expression_buffer, flags, value);
8845 const uint8_t *start = parser->
current.end - 1;
8848 uint8_t
byte = peek(parser);
8850 if (pm_char_is_hexadecimal_digit(
byte)) {
8851 uint8_t value = escape_hexadecimal_digit(
byte);
8854 byte = peek(parser);
8855 if (pm_char_is_hexadecimal_digit(
byte)) {
8856 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(
byte));
8860 value = escape_byte(value, flags);
8861 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8862 if (flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) {
8863 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X", value);
8865 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
8869 escape_write_byte_encoded(parser, buffer, value);
8871 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
8877 const uint8_t *start = parser->
current.end - 1;
8881 const uint8_t *start = parser->
current.end - 2;
8882 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
8883 }
else if (peek(parser) ==
'{') {
8884 const uint8_t *unicode_codepoints_start = parser->
current.end - 2;
8889 if ((whitespace = pm_strspn_inline_whitespace(parser->
current.end, parser->
end - parser->
current.end)) > 0) {
8890 parser->
current.end += whitespace;
8891 }
else if (peek(parser) ==
'\\' && peek_offset(parser, 1) ==
'n') {
8902 const uint8_t *extra_codepoints_start = NULL;
8903 int codepoints_count = 0;
8906 const uint8_t *unicode_start = parser->
current.end;
8907 size_t hexadecimal_length = pm_strspn_hexadecimal_digit(parser->
current.end, parser->
end - parser->
current.end);
8909 if (hexadecimal_length > 6) {
8911 pm_parser_err(parser, unicode_start, unicode_start + hexadecimal_length, PM_ERR_ESCAPE_INVALID_UNICODE_LONG);
8912 }
else if (hexadecimal_length == 0) {
8915 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8919 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
8921 pm_parser_err(parser, parser->
current.end, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE);
8922 pm_parser_err(parser, parser->
current.end, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
8928 parser->
current.end += hexadecimal_length;
8930 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count == 2) {
8931 extra_codepoints_start = unicode_start;
8934 uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length, NULL);
8935 escape_write_unicode(parser, buffer, flags, unicode_start, parser->
current.end, value);
8942 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count > 1) {
8943 pm_parser_err(parser, extra_codepoints_start, parser->
current.end - 1, PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL);
8947 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_LIST, (
int) (parser->
current.end - start), start);
8948 }
else if (peek(parser) ==
'}') {
8951 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8955 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
8957 pm_parser_err(parser, unicode_codepoints_start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
8961 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8962 pm_buffer_append_bytes(regular_expression_buffer, unicode_codepoints_start, (
size_t) (parser->
current.end - unicode_codepoints_start));
8965 size_t length = pm_strspn_hexadecimal_digit(parser->
current.end, MIN(parser->
end - parser->
current.end, 4));
8968 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8969 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
8971 const uint8_t *start = parser->
current.end - 2;
8972 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
8974 }
else if (length == 4) {
8975 uint32_t value = escape_unicode(parser, parser->
current.end, 4, NULL);
8977 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8978 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end + 4 - start));
8981 escape_write_unicode(parser, buffer, flags, start, parser->
current.end + 4, value);
8984 parser->
current.end += length;
8986 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8990 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
8992 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_UNICODE);
9001 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9002 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9006 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9010 uint8_t peeked = peek(parser);
9014 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9020 if (match(parser,
'u') || match(parser,
'U')) {
9021 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9025 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9029 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9030 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9034 escape_read_warn(parser, flags, 0,
"\\t");
9035 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9038 if (!char_is_ascii_printable(peeked)) {
9039 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9044 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9051 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9052 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9055 if (peek(parser) !=
'-') {
9057 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9063 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9067 uint8_t peeked = peek(parser);
9071 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9077 if (match(parser,
'u') || match(parser,
'U')) {
9078 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9082 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9086 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9087 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9091 escape_read_warn(parser, flags, 0,
"\\t");
9092 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9095 if (!char_is_ascii_printable(peeked)) {
9097 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9102 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9109 if (flags & PM_ESCAPE_FLAG_META) {
9110 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META_REPEAT);
9113 if (peek(parser) !=
'-') {
9115 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
9121 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
9125 uint8_t peeked = peek(parser);
9130 if (match(parser,
'u') || match(parser,
'U')) {
9131 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9135 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_META);
9139 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_META,
"\\s");
9140 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9144 escape_read_warn(parser, flags & ((uint8_t) ~PM_ESCAPE_FLAG_CONTROL), PM_ESCAPE_FLAG_META,
"\\t");
9145 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9148 if (!char_is_ascii_printable(peeked)) {
9150 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
9155 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9160 if (peek_offset(parser, 1) ==
'\n') {
9162 escape_write_byte_encoded(parser, buffer, escape_byte(
'\n', flags));
9168 if ((flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) && !char_is_ascii_printable(peeked)) {
9170 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
9174 escape_write_escape_encoded(parser, buffer, regular_expression_buffer, flags);
9176 pm_parser_err_current(parser, PM_ERR_INVALID_ESCAPE_CHARACTER);
9208static pm_token_type_t
9210 if (lex_state_end_p(parser)) {
9211 lex_state_set(parser, PM_LEX_STATE_BEG);
9212 return PM_TOKEN_QUESTION_MARK;
9216 pm_parser_err_current(parser, PM_ERR_INCOMPLETE_QUESTION_MARK);
9218 return PM_TOKEN_CHARACTER_LITERAL;
9221 if (pm_char_is_whitespace(*parser->
current.end)) {
9222 lex_state_set(parser, PM_LEX_STATE_BEG);
9223 return PM_TOKEN_QUESTION_MARK;
9226 lex_state_set(parser, PM_LEX_STATE_BEG);
9228 if (match(parser,
'\\')) {
9229 lex_state_set(parser, PM_LEX_STATE_END);
9232 pm_buffer_init_capacity(&buffer, 3);
9234 escape_read(parser, &buffer, NULL, PM_ESCAPE_FLAG_SINGLE);
9237 return PM_TOKEN_CHARACTER_LITERAL;
9246 (parser->
current.end + encoding_width >= parser->
end) ||
9247 !char_is_identifier(parser, parser->
current.end + encoding_width, parser->
end - (parser->
current.end + encoding_width))
9250 lex_state_set(parser, PM_LEX_STATE_END);
9251 parser->
current.end += encoding_width;
9253 return PM_TOKEN_CHARACTER_LITERAL;
9257 return PM_TOKEN_QUESTION_MARK;
9264static pm_token_type_t
9266 pm_token_type_t
type = match(parser,
'@') ? PM_TOKEN_CLASS_VARIABLE : PM_TOKEN_INSTANCE_VARIABLE;
9267 const uint8_t *end = parser->
end;
9270 if ((width = char_is_identifier_start(parser, parser->
current.end, end - parser->
current.end)) > 0) {
9273 while ((width = char_is_identifier(parser, parser->
current.end, end - parser->
current.end)) > 0) {
9276 }
else if (parser->
current.end < end && pm_char_is_decimal_digit(*parser->
current.end)) {
9277 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE;
9279 diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS_3_3 : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE_3_3;
9283 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, diag_id, (
int) ((parser->
current.end + width) - parser->
current.start), (
const char *) parser->
current.start);
9285 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_CLASS_VARIABLE_BARE : PM_ERR_INSTANCE_VARIABLE_BARE;
9286 pm_parser_err_token(parser, &parser->
current, diag_id);
9292 lex_mode_pop(parser);
9314 if (comment == NULL)
return NULL;
9329static pm_token_type_t
9332 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
9334 if (newline == NULL) {
9337 pm_newline_list_append(&parser->
newline_list, newline);
9338 parser->
current.end = newline + 1;
9341 parser->
current.type = PM_TOKEN_EMBDOC_BEGIN;
9342 parser_lex_callback(parser);
9345 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_EMBDOC);
9346 if (comment == NULL)
return PM_TOKEN_EOF;
9350 while (parser->
current.end + 4 <= parser->
end) {
9356 (memcmp(parser->
current.end,
"=end", 4) == 0) &&
9359 pm_char_is_whitespace(parser->
current.end[4]) ||
9360 (parser->
current.end[4] ==
'\0') ||
9361 (parser->
current.end[4] ==
'\004') ||
9362 (parser->
current.end[4] ==
'\032')
9365 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
9367 if (newline == NULL) {
9370 pm_newline_list_append(&parser->
newline_list, newline);
9371 parser->
current.end = newline + 1;
9374 parser->
current.type = PM_TOKEN_EMBDOC_END;
9375 parser_lex_callback(parser);
9380 return PM_TOKEN_EMBDOC_END;
9385 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
9387 if (newline == NULL) {
9390 pm_newline_list_append(&parser->
newline_list, newline);
9391 parser->
current.end = newline + 1;
9394 parser->
current.type = PM_TOKEN_EMBDOC_LINE;
9395 parser_lex_callback(parser);
9398 pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
9403 return PM_TOKEN_EOF;
9413 parser->
current.type = PM_TOKEN_IGNORED_NEWLINE;
9414 parser_lex_callback(parser);
9438 const uint8_t *cursor = parser->
current.end;
9440 while (cursor < parser->end && *cursor !=
'\n' && *cursor !=
'#') {
9441 if (!pm_char_is_inline_whitespace(*cursor++))
return false;
9504 pm_buffer_append_byte(&token_buffer->
buffer,
byte);
9521 width = pm_encoding_utf_8_char_width(parser->
current.end, parser->
end - parser->
current.end);
9526 return (width == 0 ? 1 : width);
9534 size_t width = parser_char_width(parser);
9535 pm_buffer_append_bytes(&token_buffer->
buffer, parser->
current.end, width);
9541 size_t width = parser_char_width(parser);
9548pm_slice_ascii_only_p(
const uint8_t *value,
size_t length) {
9549 for (
size_t index = 0; index < length; index++) {
9550 if (value[index] & 0x80)
return false;
9564 pm_string_owned_init(&parser->
current_string, (uint8_t *) pm_buffer_value(&token_buffer->
buffer), pm_buffer_length(&token_buffer->
buffer));
9585 if (token_buffer->
cursor == NULL) {
9588 pm_buffer_append_bytes(&token_buffer->
buffer, token_buffer->
cursor, (
size_t) (parser->
current.end - token_buffer->
cursor));
9589 pm_token_buffer_copy(parser, token_buffer);
9601 pm_regexp_token_buffer_copy(parser, token_buffer);
9605#define PM_TOKEN_BUFFER_DEFAULT_SIZE 16
9617 const uint8_t *start;
9618 if (token_buffer->
cursor == NULL) {
9619 pm_buffer_init_capacity(&token_buffer->
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9620 start = parser->
current.start;
9622 start = token_buffer->
cursor;
9625 const uint8_t *end = parser->
current.end - 1;
9626 assert(end >= start);
9627 pm_buffer_append_bytes(&token_buffer->
buffer, start, (
size_t) (end - start));
9629 token_buffer->
cursor = end;
9634 const uint8_t *start;
9636 pm_buffer_init_capacity(&token_buffer->
base.
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9637 pm_buffer_init_capacity(&token_buffer->
regexp_buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9638 start = parser->
current.start;
9643 const uint8_t *end = parser->
current.end - 1;
9644 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, (
size_t) (end - start));
9645 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, (
size_t) (end - start));
9650#undef PM_TOKEN_BUFFER_DEFAULT_SIZE
9658 size_t whitespace = 0;
9661 case PM_HEREDOC_INDENT_NONE:
9666 case PM_HEREDOC_INDENT_DASH:
9668 *cursor += pm_strspn_inline_whitespace(*cursor, parser->
end - *cursor);
9670 case PM_HEREDOC_INDENT_TILDE:
9673 while (*cursor < parser->end && pm_char_is_inline_whitespace(**cursor)) {
9674 if (**cursor ==
'\t') {
9675 whitespace = (whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
9694 size_t eol_length = match_eol(parser);
9701 parser_flush_heredoc_end(parser);
9707 uint8_t delimiter = *parser->
current.end;
9711 if (eol_length == 2) {
9712 delimiter = *(parser->
current.end + 1);
9715 parser->
current.end += eol_length;
9719 return *parser->
current.end++;
9726#define LEX(token_type) parser->current.type = token_type; parser_lex_callback(parser); return
9745 bool lexed_comment =
false;
9753 case PM_LEX_DEFAULT:
9754 case PM_LEX_EMBEXPR:
9771 bool space_seen =
false;
9775 bool chomping =
true;
9776 while (parser->
current.end < parser->
end && chomping) {
9777 switch (*parser->
current.end) {
9786 if (match_eol_offset(parser, 1)) {
9789 pm_parser_warn(parser, parser->
current.end, parser->
current.end + 1, PM_WARN_UNEXPECTED_CARRIAGE_RETURN);
9795 size_t eol_length = match_eol_offset(parser, 1);
9801 parser->
current.end += eol_length + 1;
9805 }
else if (pm_char_is_inline_whitespace(*parser->
current.end)) {
9838 switch (*parser->
current.end++) {
9846 const uint8_t *ending = next_newline(parser->
current.end, parser->
end - parser->
current.end);
9847 parser->
current.end = ending == NULL ? parser->
end : ending;
9852 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_INLINE);
9855 if (ending) parser->
current.end++;
9856 parser->
current.type = PM_TOKEN_COMMENT;
9857 parser_lex_callback(parser);
9869 parser_lex_magic_comment_encoding(parser);
9873 lexed_comment =
true;
9879 size_t eol_length = match_eol_at(parser, parser->
current.end - 1);
9891 if (!lexed_comment) {
9892 parser->
current.end += eol_length - 1;
9901 parser_flush_heredoc_end(parser);
9906 switch (lex_state_ignored_p(parser)) {
9907 case PM_IGNORED_NEWLINE_NONE:
9909 case PM_IGNORED_NEWLINE_PATTERN:
9911 if (!lexed_comment) parser_lex_ignored_newline(parser);
9912 lex_state_set(parser, PM_LEX_STATE_BEG);
9914 parser->
current.type = PM_TOKEN_NEWLINE;
9918 case PM_IGNORED_NEWLINE_ALL:
9919 if (!lexed_comment) parser_lex_ignored_newline(parser);
9920 lexed_comment =
false;
9921 goto lex_next_token;
9929 next_content += pm_strspn_inline_whitespace(next_content, parser->
end - next_content);
9931 if (next_content < parser->end) {
9937 if (next_content[0] ==
'#') {
9939 const uint8_t *following = next_newline(next_content, parser->
end - next_content);
9941 while (following && (following + 1 < parser->
end)) {
9943 following += pm_strspn_inline_whitespace(following, parser->
end - following);
9947 if (peek_at(parser, following) !=
'#')
break;
9951 following = next_newline(following, parser->
end - following);
9956 if (lex_state_ignored_p(parser)) {
9957 if (!lexed_comment) parser_lex_ignored_newline(parser);
9958 lexed_comment =
false;
9959 goto lex_next_token;
9965 (peek_at(parser, following) ==
'.') ||
9966 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'.')
9968 if (!lexed_comment) parser_lex_ignored_newline(parser);
9969 lexed_comment =
false;
9970 goto lex_next_token;
9980 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'&') ||
9981 (peek_at(parser, following) ==
'|' && peek_at(parser, following + 1) ==
'|') ||
9983 peek_at(parser, following) ==
'a' &&
9984 peek_at(parser, following + 1) ==
'n' &&
9985 peek_at(parser, following + 2) ==
'd' &&
9986 peek_at(parser, next_content + 3) !=
'!' &&
9987 peek_at(parser, next_content + 3) !=
'?' &&
9988 !char_is_identifier(parser, following + 3, parser->
end - (following + 3))
9991 peek_at(parser, following) ==
'o' &&
9992 peek_at(parser, following + 1) ==
'r' &&
9993 peek_at(parser, next_content + 2) !=
'!' &&
9994 peek_at(parser, next_content + 2) !=
'?' &&
9995 !char_is_identifier(parser, following + 2, parser->
end - (following + 2))
9999 if (!lexed_comment) parser_lex_ignored_newline(parser);
10000 lexed_comment =
false;
10001 goto lex_next_token;
10007 if (next_content[0] ==
'.') {
10011 if (peek_at(parser, next_content + 1) ==
'.') {
10012 if (!lexed_comment) parser_lex_ignored_newline(parser);
10013 lex_state_set(parser, PM_LEX_STATE_BEG);
10015 parser->
current.type = PM_TOKEN_NEWLINE;
10019 if (!lexed_comment) parser_lex_ignored_newline(parser);
10020 lex_state_set(parser, PM_LEX_STATE_DOT);
10021 parser->
current.start = next_content;
10022 parser->
current.end = next_content + 1;
10029 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'.') {
10030 if (!lexed_comment) parser_lex_ignored_newline(parser);
10031 lex_state_set(parser, PM_LEX_STATE_DOT);
10032 parser->
current.start = next_content;
10033 parser->
current.end = next_content + 2;
10035 LEX(PM_TOKEN_AMPERSAND_DOT);
10041 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'&') {
10042 if (!lexed_comment) parser_lex_ignored_newline(parser);
10043 lex_state_set(parser, PM_LEX_STATE_BEG);
10044 parser->
current.start = next_content;
10045 parser->
current.end = next_content + 2;
10047 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
10052 if (peek_at(parser, next_content) ==
'|' && peek_at(parser, next_content + 1) ==
'|') {
10053 if (!lexed_comment) parser_lex_ignored_newline(parser);
10054 lex_state_set(parser, PM_LEX_STATE_BEG);
10055 parser->
current.start = next_content;
10056 parser->
current.end = next_content + 2;
10058 LEX(PM_TOKEN_PIPE_PIPE);
10064 peek_at(parser, next_content) ==
'a' &&
10065 peek_at(parser, next_content + 1) ==
'n' &&
10066 peek_at(parser, next_content + 2) ==
'd' &&
10067 peek_at(parser, next_content + 3) !=
'!' &&
10068 peek_at(parser, next_content + 3) !=
'?' &&
10069 !char_is_identifier(parser, next_content + 3, parser->
end - (next_content + 3))
10071 if (!lexed_comment) parser_lex_ignored_newline(parser);
10072 lex_state_set(parser, PM_LEX_STATE_BEG);
10073 parser->
current.start = next_content;
10074 parser->
current.end = next_content + 3;
10077 LEX(PM_TOKEN_KEYWORD_AND);
10083 peek_at(parser, next_content) ==
'o' &&
10084 peek_at(parser, next_content + 1) ==
'r' &&
10085 peek_at(parser, next_content + 2) !=
'!' &&
10086 peek_at(parser, next_content + 2) !=
'?' &&
10087 !char_is_identifier(parser, next_content + 2, parser->
end - (next_content + 2))
10089 if (!lexed_comment) parser_lex_ignored_newline(parser);
10090 lex_state_set(parser, PM_LEX_STATE_BEG);
10091 parser->
current.start = next_content;
10092 parser->
current.end = next_content + 2;
10095 LEX(PM_TOKEN_KEYWORD_OR);
10102 lex_state_set(parser, PM_LEX_STATE_BEG);
10104 parser->
current.type = PM_TOKEN_NEWLINE;
10105 if (!lexed_comment) parser_lex_callback(parser);
10115 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10116 LEX(PM_TOKEN_COMMA);
10120 pm_token_type_t
type = PM_TOKEN_PARENTHESIS_LEFT;
10122 if (space_seen && (lex_state_arg_p(parser) || parser->
lex_state == (PM_LEX_STATE_END | PM_LEX_STATE_LABEL))) {
10123 type = PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES;
10127 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10128 pm_do_loop_stack_push(parser,
false);
10135 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10136 pm_do_loop_stack_pop(parser);
10137 LEX(PM_TOKEN_PARENTHESIS_RIGHT);
10141 lex_state_set(parser, PM_LEX_STATE_BEG);
10143 LEX(PM_TOKEN_SEMICOLON);
10148 pm_token_type_t
type = PM_TOKEN_BRACKET_LEFT;
10150 if (lex_state_operator_p(parser)) {
10151 if (match(parser,
']')) {
10153 lex_state_set(parser, PM_LEX_STATE_ARG);
10154 LEX(match(parser,
'=') ? PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL : PM_TOKEN_BRACKET_LEFT_RIGHT);
10157 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABEL);
10161 if (lex_state_beg_p(parser) || (lex_state_arg_p(parser) && (space_seen || lex_state_p(parser, PM_LEX_STATE_LABELED)))) {
10162 type = PM_TOKEN_BRACKET_LEFT_ARRAY;
10165 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10166 pm_do_loop_stack_push(parser,
false);
10172 lex_state_set(parser, PM_LEX_STATE_END);
10173 pm_do_loop_stack_pop(parser);
10174 LEX(PM_TOKEN_BRACKET_RIGHT);
10178 pm_token_type_t
type = PM_TOKEN_BRACE_LEFT;
10183 lex_state_set(parser, PM_LEX_STATE_BEG);
10184 type = PM_TOKEN_LAMBDA_BEGIN;
10185 }
else if (lex_state_p(parser, PM_LEX_STATE_LABELED)) {
10187 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10188 }
else if (lex_state_p(parser, PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_END | PM_LEX_STATE_ENDFN)) {
10191 lex_state_set(parser, PM_LEX_STATE_BEG);
10192 }
else if (lex_state_p(parser, PM_LEX_STATE_ENDARG)) {
10195 lex_state_set(parser, PM_LEX_STATE_BEG);
10198 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10203 pm_do_loop_stack_push(parser,
false);
10211 pm_do_loop_stack_pop(parser);
10214 lex_mode_pop(parser);
10215 LEX(PM_TOKEN_EMBEXPR_END);
10219 lex_state_set(parser, PM_LEX_STATE_END);
10220 LEX(PM_TOKEN_BRACE_RIGHT);
10224 if (match(parser,
'*')) {
10225 if (match(parser,
'=')) {
10226 lex_state_set(parser, PM_LEX_STATE_BEG);
10227 LEX(PM_TOKEN_STAR_STAR_EQUAL);
10230 pm_token_type_t
type = PM_TOKEN_STAR_STAR;
10232 if (lex_state_spcarg_p(parser, space_seen)) {
10233 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR_STAR);
10234 type = PM_TOKEN_USTAR_STAR;
10235 }
else if (lex_state_beg_p(parser)) {
10236 type = PM_TOKEN_USTAR_STAR;
10237 }
else if (ambiguous_operator_p(parser, space_seen)) {
10238 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"**",
"argument prefix");
10241 if (lex_state_operator_p(parser)) {
10242 lex_state_set(parser, PM_LEX_STATE_ARG);
10244 lex_state_set(parser, PM_LEX_STATE_BEG);
10250 if (match(parser,
'=')) {
10251 lex_state_set(parser, PM_LEX_STATE_BEG);
10252 LEX(PM_TOKEN_STAR_EQUAL);
10255 pm_token_type_t
type = PM_TOKEN_STAR;
10257 if (lex_state_spcarg_p(parser, space_seen)) {
10258 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR);
10259 type = PM_TOKEN_USTAR;
10260 }
else if (lex_state_beg_p(parser)) {
10261 type = PM_TOKEN_USTAR;
10262 }
else if (ambiguous_operator_p(parser, space_seen)) {
10263 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"*",
"argument prefix");
10266 if (lex_state_operator_p(parser)) {
10267 lex_state_set(parser, PM_LEX_STATE_ARG);
10269 lex_state_set(parser, PM_LEX_STATE_BEG);
10277 if (lex_state_operator_p(parser)) {
10278 lex_state_set(parser, PM_LEX_STATE_ARG);
10279 if (match(parser,
'@')) {
10280 LEX(PM_TOKEN_BANG);
10283 lex_state_set(parser, PM_LEX_STATE_BEG);
10286 if (match(parser,
'=')) {
10287 LEX(PM_TOKEN_BANG_EQUAL);
10290 if (match(parser,
'~')) {
10291 LEX(PM_TOKEN_BANG_TILDE);
10294 LEX(PM_TOKEN_BANG);
10299 current_token_starts_line(parser) &&
10301 memcmp(parser->
current.end,
"begin", 5) == 0 &&
10302 (pm_char_is_whitespace(peek_offset(parser, 5)) || (peek_offset(parser, 5) ==
'\0'))
10304 pm_token_type_t
type = lex_embdoc(parser);
10305 if (
type == PM_TOKEN_EOF) {
10309 goto lex_next_token;
10312 if (lex_state_operator_p(parser)) {
10313 lex_state_set(parser, PM_LEX_STATE_ARG);
10315 lex_state_set(parser, PM_LEX_STATE_BEG);
10318 if (match(parser,
'>')) {
10319 LEX(PM_TOKEN_EQUAL_GREATER);
10322 if (match(parser,
'~')) {
10323 LEX(PM_TOKEN_EQUAL_TILDE);
10326 if (match(parser,
'=')) {
10327 LEX(match(parser,
'=') ? PM_TOKEN_EQUAL_EQUAL_EQUAL : PM_TOKEN_EQUAL_EQUAL);
10330 LEX(PM_TOKEN_EQUAL);
10334 if (match(parser,
'<')) {
10336 !lex_state_p(parser, PM_LEX_STATE_DOT | PM_LEX_STATE_CLASS) &&
10337 !lex_state_end_p(parser) &&
10338 (!lex_state_p(parser, PM_LEX_STATE_ARG_ANY) || lex_state_p(parser, PM_LEX_STATE_LABELED) || space_seen)
10340 const uint8_t *end = parser->
current.end;
10345 if (match(parser,
'-')) {
10346 indent = PM_HEREDOC_INDENT_DASH;
10348 else if (match(parser,
'~')) {
10349 indent = PM_HEREDOC_INDENT_TILDE;
10352 if (match(parser,
'`')) {
10353 quote = PM_HEREDOC_QUOTE_BACKTICK;
10355 else if (match(parser,
'"')) {
10356 quote = PM_HEREDOC_QUOTE_DOUBLE;
10358 else if (match(parser,
'\'')) {
10359 quote = PM_HEREDOC_QUOTE_SINGLE;
10362 const uint8_t *ident_start = parser->
current.end;
10367 }
else if (quote == PM_HEREDOC_QUOTE_NONE && (width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) == 0) {
10370 if (quote == PM_HEREDOC_QUOTE_NONE) {
10371 parser->
current.end += width;
10373 while ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end))) {
10374 parser->
current.end += width;
10380 if (*parser->
current.end ==
'\r' || *parser->
current.end ==
'\n')
break;
10385 size_t ident_length = (size_t) (parser->
current.end - ident_start);
10386 bool ident_error =
false;
10388 if (quote != PM_HEREDOC_QUOTE_NONE && !match(parser, (uint8_t) quote)) {
10389 pm_parser_err(parser, ident_start, ident_start + ident_length, PM_ERR_HEREDOC_IDENTIFIER);
10390 ident_error =
true;
10395 .mode = PM_LEX_HEREDOC,
10398 .ident_start = ident_start,
10399 .ident_length = ident_length,
10403 .next_start = parser->
current.end,
10405 .line_continuation =
false
10410 const uint8_t *body_start = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10412 if (body_start == NULL) {
10417 if (!ident_error) pm_parser_err_heredoc_term(parser, ident_start, ident_length);
10418 body_start = parser->
end;
10422 pm_newline_list_append(&parser->
newline_list, body_start);
10431 LEX(PM_TOKEN_HEREDOC_START);
10435 if (match(parser,
'=')) {
10436 lex_state_set(parser, PM_LEX_STATE_BEG);
10437 LEX(PM_TOKEN_LESS_LESS_EQUAL);
10440 if (ambiguous_operator_p(parser, space_seen)) {
10441 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"<<",
"here document");
10444 if (lex_state_operator_p(parser)) {
10445 lex_state_set(parser, PM_LEX_STATE_ARG);
10447 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
10448 lex_state_set(parser, PM_LEX_STATE_BEG);
10451 LEX(PM_TOKEN_LESS_LESS);
10454 if (lex_state_operator_p(parser)) {
10455 lex_state_set(parser, PM_LEX_STATE_ARG);
10457 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
10458 lex_state_set(parser, PM_LEX_STATE_BEG);
10461 if (match(parser,
'=')) {
10462 if (match(parser,
'>')) {
10463 LEX(PM_TOKEN_LESS_EQUAL_GREATER);
10466 LEX(PM_TOKEN_LESS_EQUAL);
10469 LEX(PM_TOKEN_LESS);
10473 if (match(parser,
'>')) {
10474 if (lex_state_operator_p(parser)) {
10475 lex_state_set(parser, PM_LEX_STATE_ARG);
10477 lex_state_set(parser, PM_LEX_STATE_BEG);
10479 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_GREATER_EQUAL : PM_TOKEN_GREATER_GREATER);
10482 if (lex_state_operator_p(parser)) {
10483 lex_state_set(parser, PM_LEX_STATE_ARG);
10485 lex_state_set(parser, PM_LEX_STATE_BEG);
10488 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_EQUAL : PM_TOKEN_GREATER);
10492 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
10493 lex_mode_push_string(parser,
true, label_allowed,
'\0',
'"');
10494 LEX(PM_TOKEN_STRING_BEGIN);
10499 if (lex_state_p(parser, PM_LEX_STATE_FNAME)) {
10500 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10501 LEX(PM_TOKEN_BACKTICK);
10504 if (lex_state_p(parser, PM_LEX_STATE_DOT)) {
10505 if (previous_command_start) {
10506 lex_state_set(parser, PM_LEX_STATE_CMDARG);
10508 lex_state_set(parser, PM_LEX_STATE_ARG);
10511 LEX(PM_TOKEN_BACKTICK);
10514 lex_mode_push_string(parser,
true,
false,
'\0',
'`');
10515 LEX(PM_TOKEN_BACKTICK);
10520 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
10521 lex_mode_push_string(parser,
false, label_allowed,
'\0',
'\'');
10522 LEX(PM_TOKEN_STRING_BEGIN);
10527 LEX(lex_question_mark(parser));
10531 if (match(parser,
'&')) {
10532 lex_state_set(parser, PM_LEX_STATE_BEG);
10534 if (match(parser,
'=')) {
10535 LEX(PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
10538 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
10541 if (match(parser,
'=')) {
10542 lex_state_set(parser, PM_LEX_STATE_BEG);
10543 LEX(PM_TOKEN_AMPERSAND_EQUAL);
10546 if (match(parser,
'.')) {
10547 lex_state_set(parser, PM_LEX_STATE_DOT);
10548 LEX(PM_TOKEN_AMPERSAND_DOT);
10551 pm_token_type_t
type = PM_TOKEN_AMPERSAND;
10552 if (lex_state_spcarg_p(parser, space_seen)) {
10553 if ((peek(parser) !=
':') || (peek_offset(parser, 1) ==
'\0')) {
10554 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
10556 const uint8_t delim = peek_offset(parser, 1);
10558 if ((delim !=
'\'') && (delim !=
'"') && !char_is_identifier(parser, parser->
current.end + 1, parser->
end - (parser->
current.end + 1))) {
10559 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
10563 type = PM_TOKEN_UAMPERSAND;
10564 }
else if (lex_state_beg_p(parser)) {
10565 type = PM_TOKEN_UAMPERSAND;
10566 }
else if (ambiguous_operator_p(parser, space_seen)) {
10567 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"&",
"argument prefix");
10570 if (lex_state_operator_p(parser)) {
10571 lex_state_set(parser, PM_LEX_STATE_ARG);
10573 lex_state_set(parser, PM_LEX_STATE_BEG);
10581 if (match(parser,
'|')) {
10582 if (match(parser,
'=')) {
10583 lex_state_set(parser, PM_LEX_STATE_BEG);
10584 LEX(PM_TOKEN_PIPE_PIPE_EQUAL);
10587 if (lex_state_p(parser, PM_LEX_STATE_BEG)) {
10589 LEX(PM_TOKEN_PIPE);
10592 lex_state_set(parser, PM_LEX_STATE_BEG);
10593 LEX(PM_TOKEN_PIPE_PIPE);
10596 if (match(parser,
'=')) {
10597 lex_state_set(parser, PM_LEX_STATE_BEG);
10598 LEX(PM_TOKEN_PIPE_EQUAL);
10601 if (lex_state_operator_p(parser)) {
10602 lex_state_set(parser, PM_LEX_STATE_ARG);
10604 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10607 LEX(PM_TOKEN_PIPE);
10611 if (lex_state_operator_p(parser)) {
10612 lex_state_set(parser, PM_LEX_STATE_ARG);
10614 if (match(parser,
'@')) {
10615 LEX(PM_TOKEN_UPLUS);
10618 LEX(PM_TOKEN_PLUS);
10621 if (match(parser,
'=')) {
10622 lex_state_set(parser, PM_LEX_STATE_BEG);
10623 LEX(PM_TOKEN_PLUS_EQUAL);
10627 lex_state_beg_p(parser) ||
10628 (lex_state_spcarg_p(parser, space_seen) ? (pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS),
true) :
false)
10630 lex_state_set(parser, PM_LEX_STATE_BEG);
10632 if (pm_char_is_decimal_digit(peek(parser))) {
10634 pm_token_type_t
type = lex_numeric(parser);
10635 lex_state_set(parser, PM_LEX_STATE_END);
10639 LEX(PM_TOKEN_UPLUS);
10642 if (ambiguous_operator_p(parser, space_seen)) {
10643 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"+",
"unary operator");
10646 lex_state_set(parser, PM_LEX_STATE_BEG);
10647 LEX(PM_TOKEN_PLUS);
10652 if (lex_state_operator_p(parser)) {
10653 lex_state_set(parser, PM_LEX_STATE_ARG);
10655 if (match(parser,
'@')) {
10656 LEX(PM_TOKEN_UMINUS);
10659 LEX(PM_TOKEN_MINUS);
10662 if (match(parser,
'=')) {
10663 lex_state_set(parser, PM_LEX_STATE_BEG);
10664 LEX(PM_TOKEN_MINUS_EQUAL);
10667 if (match(parser,
'>')) {
10668 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10669 LEX(PM_TOKEN_MINUS_GREATER);
10672 bool spcarg = lex_state_spcarg_p(parser, space_seen);
10673 bool is_beg = lex_state_beg_p(parser);
10674 if (!is_beg && spcarg) {
10675 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS);
10678 if (is_beg || spcarg) {
10679 lex_state_set(parser, PM_LEX_STATE_BEG);
10680 LEX(pm_char_is_decimal_digit(peek(parser)) ? PM_TOKEN_UMINUS_NUM : PM_TOKEN_UMINUS);
10683 if (ambiguous_operator_p(parser, space_seen)) {
10684 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"-",
"unary operator");
10687 lex_state_set(parser, PM_LEX_STATE_BEG);
10688 LEX(PM_TOKEN_MINUS);
10693 bool beg_p = lex_state_beg_p(parser);
10695 if (match(parser,
'.')) {
10696 if (match(parser,
'.')) {
10699 if (lex_state_p(parser, PM_LEX_STATE_END)) {
10700 lex_state_set(parser, PM_LEX_STATE_BEG);
10702 lex_state_set(parser, PM_LEX_STATE_ENDARG);
10704 LEX(PM_TOKEN_UDOT_DOT_DOT);
10708 pm_parser_warn_token(parser, &parser->
current, PM_WARN_DOT_DOT_DOT_EOL);
10711 lex_state_set(parser, PM_LEX_STATE_BEG);
10712 LEX(beg_p ? PM_TOKEN_UDOT_DOT_DOT : PM_TOKEN_DOT_DOT_DOT);
10715 lex_state_set(parser, PM_LEX_STATE_BEG);
10716 LEX(beg_p ? PM_TOKEN_UDOT_DOT : PM_TOKEN_DOT_DOT);
10719 lex_state_set(parser, PM_LEX_STATE_DOT);
10734 pm_token_type_t
type = lex_numeric(parser);
10735 lex_state_set(parser, PM_LEX_STATE_END);
10741 if (match(parser,
':')) {
10742 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)) {
10743 lex_state_set(parser, PM_LEX_STATE_BEG);
10744 LEX(PM_TOKEN_UCOLON_COLON);
10747 lex_state_set(parser, PM_LEX_STATE_DOT);
10748 LEX(PM_TOKEN_COLON_COLON);
10751 if (lex_state_end_p(parser) || pm_char_is_whitespace(peek(parser)) || peek(parser) ==
'#') {
10752 lex_state_set(parser, PM_LEX_STATE_BEG);
10753 LEX(PM_TOKEN_COLON);
10756 if (peek(parser) ==
'"' || peek(parser) ==
'\'') {
10757 lex_mode_push_string(parser, peek(parser) ==
'"',
false,
'\0', *parser->
current.end);
10761 lex_state_set(parser, PM_LEX_STATE_FNAME);
10762 LEX(PM_TOKEN_SYMBOL_BEGIN);
10766 if (lex_state_beg_p(parser)) {
10767 lex_mode_push_regexp(parser,
'\0',
'/');
10768 LEX(PM_TOKEN_REGEXP_BEGIN);
10771 if (match(parser,
'=')) {
10772 lex_state_set(parser, PM_LEX_STATE_BEG);
10773 LEX(PM_TOKEN_SLASH_EQUAL);
10776 if (lex_state_spcarg_p(parser, space_seen)) {
10777 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_SLASH);
10778 lex_mode_push_regexp(parser,
'\0',
'/');
10779 LEX(PM_TOKEN_REGEXP_BEGIN);
10782 if (ambiguous_operator_p(parser, space_seen)) {
10783 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"/",
"regexp literal");
10786 if (lex_state_operator_p(parser)) {
10787 lex_state_set(parser, PM_LEX_STATE_ARG);
10789 lex_state_set(parser, PM_LEX_STATE_BEG);
10792 LEX(PM_TOKEN_SLASH);
10796 if (lex_state_operator_p(parser)) {
10797 lex_state_set(parser, PM_LEX_STATE_ARG);
10799 lex_state_set(parser, PM_LEX_STATE_BEG);
10801 LEX(match(parser,
'=') ? PM_TOKEN_CARET_EQUAL : PM_TOKEN_CARET);
10805 if (lex_state_operator_p(parser)) {
10806 (void) match(parser,
'@');
10807 lex_state_set(parser, PM_LEX_STATE_ARG);
10809 lex_state_set(parser, PM_LEX_STATE_BEG);
10812 LEX(PM_TOKEN_TILDE);
10820 if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->
current.end >= parser->
end)) {
10821 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT_EOF);
10822 LEX(PM_TOKEN_PERCENT);
10825 if (!lex_state_beg_p(parser) && match(parser,
'=')) {
10826 lex_state_set(parser, PM_LEX_STATE_BEG);
10827 LEX(PM_TOKEN_PERCENT_EQUAL);
10829 lex_state_beg_p(parser) ||
10830 (lex_state_p(parser, PM_LEX_STATE_FITEM) && (peek(parser) ==
's')) ||
10831 lex_state_spcarg_p(parser, space_seen)
10834 if (*parser->
current.end >= 0x80) {
10835 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
10838 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10839 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10840 LEX(PM_TOKEN_STRING_BEGIN);
10845 uint8_t delimiter = peek_offset(parser, 1);
10847 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
10848 goto lex_next_token;
10851 switch (peek(parser)) {
10856 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
10858 lex_mode_push_list_eof(parser);
10861 LEX(PM_TOKEN_PERCENT_LOWER_I);
10867 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
10869 lex_mode_push_list_eof(parser);
10872 LEX(PM_TOKEN_PERCENT_UPPER_I);
10878 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10879 lex_mode_push_regexp(parser, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10881 lex_mode_push_regexp(parser,
'\0',
'\0');
10884 LEX(PM_TOKEN_REGEXP_BEGIN);
10890 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10891 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10893 lex_mode_push_string_eof(parser);
10896 LEX(PM_TOKEN_STRING_BEGIN);
10902 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10903 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10905 lex_mode_push_string_eof(parser);
10908 LEX(PM_TOKEN_STRING_BEGIN);
10914 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10915 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10916 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
10918 lex_mode_push_string_eof(parser);
10921 LEX(PM_TOKEN_SYMBOL_BEGIN);
10927 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
10929 lex_mode_push_list_eof(parser);
10932 LEX(PM_TOKEN_PERCENT_LOWER_W);
10938 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
10940 lex_mode_push_list_eof(parser);
10943 LEX(PM_TOKEN_PERCENT_UPPER_W);
10949 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10950 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10952 lex_mode_push_string_eof(parser);
10955 LEX(PM_TOKEN_PERCENT_LOWER_X);
10962 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
10963 goto lex_next_token;
10967 if (ambiguous_operator_p(parser, space_seen)) {
10968 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"%",
"string literal");
10971 lex_state_set(parser, lex_state_operator_p(parser) ? PM_LEX_STATE_ARG : PM_LEX_STATE_BEG);
10972 LEX(PM_TOKEN_PERCENT);
10977 pm_token_type_t
type = lex_global_variable(parser);
10982 lex_mode_pop(parser);
10985 lex_state_set(parser, PM_LEX_STATE_END);
10991 lex_state_set(parser, parser->
lex_state & PM_LEX_STATE_FNAME ? PM_LEX_STATE_ENDFN : PM_LEX_STATE_END);
10992 LEX(lex_at_variable(parser));
10995 if (*parser->
current.start !=
'_') {
10996 size_t width = char_is_identifier_start(parser, parser->
current.start, parser->
end - parser->
current.start);
11003 if (*parser->
current.start >= 0x80) {
11004 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *parser->
current.start);
11005 }
else if (*parser->
current.start ==
'\\') {
11006 switch (peek_at(parser, parser->
current.start + 1)) {
11009 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped space");
11013 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped form feed");
11017 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped horizontal tab");
11021 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped vertical tab");
11024 if (peek_at(parser, parser->
current.start + 2) !=
'\n') {
11026 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped carriage return");
11031 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"backslash");
11034 }
else if (char_is_ascii_printable(*parser->
current.start)) {
11035 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_PRINTABLE_CHARACTER, *parser->
current.start);
11037 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_CHARACTER, *parser->
current.start);
11040 goto lex_next_token;
11046 pm_token_type_t
type = lex_identifier(parser, previous_command_start);
11054 current_token_starts_line(parser) &&
11055 (memcmp(parser->
current.start,
"__END__", 7) == 0) &&
11056 (parser->
current.end == parser->
end || match_eol(parser))
11061 const uint8_t *cursor = parser->
current.end;
11062 while ((cursor = next_newline(cursor, parser->
end - cursor)) != NULL) {
11063 pm_newline_list_append(&parser->
newline_list, cursor++);
11067 parser->
current.type = PM_TOKEN___END__;
11068 parser_lex_callback(parser);
11078 if (
type == PM_TOKEN_IDENTIFIER ||
type == PM_TOKEN_CONSTANT ||
type == PM_TOKEN_METHOD_NAME) {
11079 if (lex_state_p(parser, PM_LEX_STATE_BEG_ANY | PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_DOT)) {
11080 if (previous_command_start) {
11081 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11083 lex_state_set(parser, PM_LEX_STATE_ARG);
11085 }
else if (parser->
lex_state == PM_LEX_STATE_FNAME) {
11086 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11088 lex_state_set(parser, PM_LEX_STATE_END);
11093 !(last_state & (PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME)) &&
11094 (
type == PM_TOKEN_IDENTIFIER) &&
11095 ((pm_parser_local_depth(parser, &parser->
current) != -1) ||
11096 pm_token_is_numbered_parameter(parser->
current.start, parser->
current.end))
11098 lex_state_set(parser, PM_LEX_STATE_END | PM_LEX_STATE_LABEL);
11105 case PM_LEX_LIST: {
11119 whitespace = pm_strspn_inline_whitespace(parser->
current.end, parser->
end - parser->
current.end);
11120 if (peek_offset(parser, (ptrdiff_t)whitespace) ==
'\n') {
11127 if (whitespace > 0) {
11128 parser->
current.end += whitespace;
11129 if (peek_offset(parser, -1) ==
'\n') {
11131 parser_flush_heredoc_end(parser);
11133 LEX(PM_TOKEN_WORDS_SEP);
11145 const uint8_t *breakpoints = lex_mode->
as.list.
breakpoints;
11146 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11152 while (breakpoint != NULL) {
11155 if (pm_char_is_whitespace(*breakpoint)) {
11156 parser->
current.end = breakpoint;
11157 pm_token_buffer_flush(parser, &token_buffer);
11158 LEX(PM_TOKEN_STRING_CONTENT);
11167 parser->
current.end = breakpoint + 1;
11168 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11175 if (breakpoint > parser->
current.start) {
11176 parser->
current.end = breakpoint;
11177 pm_token_buffer_flush(parser, &token_buffer);
11178 LEX(PM_TOKEN_STRING_CONTENT);
11183 parser->
current.end = breakpoint + 1;
11184 lex_mode_pop(parser);
11185 lex_state_set(parser, PM_LEX_STATE_END);
11186 LEX(PM_TOKEN_STRING_END);
11190 if (*breakpoint ==
'\0') {
11191 breakpoint = pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->
end - (breakpoint + 1),
true);
11198 if (*breakpoint ==
'\\') {
11199 parser->
current.end = breakpoint + 1;
11208 pm_token_buffer_escape(parser, &token_buffer);
11209 uint8_t peeked = peek(parser);
11217 pm_token_buffer_push_byte(&token_buffer, peeked);
11222 if (peek(parser) !=
'\n') {
11223 pm_token_buffer_push_byte(&token_buffer,
'\r');
11228 pm_token_buffer_push_byte(&token_buffer,
'\n');
11234 parser_flush_heredoc_end(parser);
11235 pm_token_buffer_copy(parser, &token_buffer);
11236 LEX(PM_TOKEN_STRING_CONTENT);
11246 pm_token_buffer_push_byte(&token_buffer, peeked);
11249 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
11251 pm_token_buffer_push_byte(&token_buffer,
'\\');
11252 pm_token_buffer_push_escaped(&token_buffer, parser);
11259 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11264 if (*breakpoint ==
'#') {
11265 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11267 if (
type == PM_TOKEN_NOT_PROVIDED) {
11272 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11276 if (
type == PM_TOKEN_STRING_CONTENT) {
11277 pm_token_buffer_flush(parser, &token_buffer);
11286 parser->
current.end = breakpoint + 1;
11287 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11293 pm_token_buffer_flush(parser, &token_buffer);
11294 LEX(PM_TOKEN_STRING_CONTENT);
11300 pm_token_buffer_flush(parser, &token_buffer);
11301 LEX(PM_TOKEN_STRING_CONTENT);
11303 case PM_LEX_REGEXP: {
11325 const uint8_t *breakpoints = lex_mode->
as.regexp.
breakpoints;
11326 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11329 while (breakpoint != NULL) {
11331 bool is_terminator = (*breakpoint == term);
11336 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
11337 if (term ==
'\n') {
11338 is_terminator =
true;
11344 if (term ==
'\r') {
11345 is_terminator =
false;
11351 if (is_terminator) {
11353 parser->
current.end = breakpoint + 1;
11354 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11362 if (breakpoint > parser->
current.start) {
11363 parser->
current.end = breakpoint;
11364 pm_regexp_token_buffer_flush(parser, &token_buffer);
11365 LEX(PM_TOKEN_STRING_CONTENT);
11369 size_t eol_length = match_eol_at(parser, breakpoint);
11371 parser->
current.end = breakpoint + eol_length;
11380 parser->
current.end = breakpoint + 1;
11387 lex_mode_pop(parser);
11388 lex_state_set(parser, PM_LEX_STATE_END);
11389 LEX(PM_TOKEN_REGEXP_END);
11394 if (*breakpoint && *breakpoint == lex_mode->
as.regexp.
incrementor) {
11395 parser->
current.end = breakpoint + 1;
11396 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11401 switch (*breakpoint) {
11404 parser->
current.end = breakpoint + 1;
11405 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11408 if (peek_at(parser, breakpoint + 1) !=
'\n') {
11409 parser->
current.end = breakpoint + 1;
11410 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11415 parser->
current.end = breakpoint;
11416 pm_regexp_token_buffer_escape(parser, &token_buffer);
11424 pm_newline_list_append(&parser->
newline_list, breakpoint);
11425 parser->
current.end = breakpoint + 1;
11426 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11430 parser->
current.end = breakpoint + 1;
11431 parser_flush_heredoc_end(parser);
11432 pm_regexp_token_buffer_flush(parser, &token_buffer);
11433 LEX(PM_TOKEN_STRING_CONTENT);
11438 parser->
current.end = breakpoint + 1;
11447 pm_regexp_token_buffer_escape(parser, &token_buffer);
11448 uint8_t peeked = peek(parser);
11453 if (peek(parser) !=
'\n') {
11455 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11457 pm_regexp_token_buffer_push_byte(&token_buffer,
'\r');
11458 pm_token_buffer_push_byte(&token_buffer.
base,
'\r');
11467 parser_flush_heredoc_end(parser);
11468 pm_regexp_token_buffer_copy(parser, &token_buffer);
11469 LEX(PM_TOKEN_STRING_CONTENT);
11490 case '$':
case ')':
case '*':
case '+':
11491 case '.':
case '>':
case '?':
case ']':
11492 case '^':
case '|':
case '}':
11493 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11499 pm_regexp_token_buffer_push_byte(&token_buffer, peeked);
11500 pm_token_buffer_push_byte(&token_buffer.
base, peeked);
11505 if (peeked < 0x80) pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11506 pm_regexp_token_buffer_push_escaped(&token_buffer, parser);
11511 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11517 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11519 if (
type == PM_TOKEN_NOT_PROVIDED) {
11524 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11528 if (
type == PM_TOKEN_STRING_CONTENT) {
11529 pm_regexp_token_buffer_flush(parser, &token_buffer);
11535 assert(
false &&
"unreachable");
11541 pm_regexp_token_buffer_flush(parser, &token_buffer);
11542 LEX(PM_TOKEN_STRING_CONTENT);
11548 pm_regexp_token_buffer_flush(parser, &token_buffer);
11549 LEX(PM_TOKEN_STRING_CONTENT);
11551 case PM_LEX_STRING: {
11570 const uint8_t *breakpoints = lex_mode->
as.string.
breakpoints;
11571 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11577 while (breakpoint != NULL) {
11582 parser->
current.end = breakpoint + 1;
11583 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11588 bool is_terminator = (*breakpoint == term);
11593 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
11594 if (term ==
'\n') {
11595 is_terminator =
true;
11601 if (term ==
'\r') {
11602 is_terminator =
false;
11609 if (is_terminator) {
11613 parser->
current.end = breakpoint + 1;
11614 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11621 if (breakpoint > parser->
current.start) {
11622 parser->
current.end = breakpoint;
11623 pm_token_buffer_flush(parser, &token_buffer);
11624 LEX(PM_TOKEN_STRING_CONTENT);
11629 size_t eol_length = match_eol_at(parser, breakpoint);
11631 parser->
current.end = breakpoint + eol_length;
11640 parser->
current.end = breakpoint + 1;
11643 if (lex_mode->
as.string.
label_allowed && (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')) {
11645 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
11646 lex_mode_pop(parser);
11647 LEX(PM_TOKEN_LABEL_END);
11654 parser_flush_heredoc_end(parser);
11657 lex_state_set(parser, PM_LEX_STATE_END);
11658 lex_mode_pop(parser);
11659 LEX(PM_TOKEN_STRING_END);
11662 switch (*breakpoint) {
11665 parser->
current.end = breakpoint + 1;
11666 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11669 if (peek_at(parser, breakpoint + 1) !=
'\n') {
11670 parser->
current.end = breakpoint + 1;
11671 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11678 parser->
current.end = breakpoint;
11679 pm_token_buffer_escape(parser, &token_buffer);
11680 token_buffer.
cursor = breakpoint;
11689 pm_newline_list_append(&parser->
newline_list, breakpoint);
11690 parser->
current.end = breakpoint + 1;
11691 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11695 parser->
current.end = breakpoint + 1;
11696 parser_flush_heredoc_end(parser);
11697 pm_token_buffer_flush(parser, &token_buffer);
11698 LEX(PM_TOKEN_STRING_CONTENT);
11701 parser->
current.end = breakpoint + 1;
11710 pm_token_buffer_escape(parser, &token_buffer);
11711 uint8_t peeked = peek(parser);
11715 pm_token_buffer_push_byte(&token_buffer,
'\\');
11720 if (peek(parser) !=
'\n') {
11722 pm_token_buffer_push_byte(&token_buffer,
'\\');
11724 pm_token_buffer_push_byte(&token_buffer,
'\r');
11730 pm_token_buffer_push_byte(&token_buffer,
'\\');
11731 pm_token_buffer_push_byte(&token_buffer,
'\n');
11738 parser_flush_heredoc_end(parser);
11739 pm_token_buffer_copy(parser, &token_buffer);
11740 LEX(PM_TOKEN_STRING_CONTENT);
11750 pm_token_buffer_push_byte(&token_buffer, peeked);
11753 pm_token_buffer_push_byte(&token_buffer, peeked);
11756 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
11758 pm_token_buffer_push_byte(&token_buffer,
'\\');
11759 pm_token_buffer_push_escaped(&token_buffer, parser);
11766 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11770 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11772 if (
type == PM_TOKEN_NOT_PROVIDED) {
11777 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11781 if (
type == PM_TOKEN_STRING_CONTENT) {
11782 pm_token_buffer_flush(parser, &token_buffer);
11788 assert(
false &&
"unreachable");
11793 pm_token_buffer_flush(parser, &token_buffer);
11794 LEX(PM_TOKEN_STRING_CONTENT);
11800 pm_token_buffer_flush(parser, &token_buffer);
11801 LEX(PM_TOKEN_STRING_CONTENT);
11803 case PM_LEX_HEREDOC: {
11830 lex_state_set(parser, PM_LEX_STATE_END);
11831 lex_mode_pop(parser);
11832 LEX(PM_TOKEN_HEREDOC_END);
11835 const uint8_t *ident_start = heredoc_lex_mode->
ident_start;
11840 if (current_token_starts_line(parser)) {
11841 const uint8_t *start = parser->
current.start;
11843 if (!line_continuation && (start + ident_length <= parser->end)) {
11844 const uint8_t *newline = next_newline(start, parser->
end - start);
11845 const uint8_t *ident_end = newline;
11846 const uint8_t *terminator_end = newline;
11848 if (newline == NULL) {
11849 terminator_end = parser->
end;
11850 ident_end = parser->
end;
11853 if (newline[-1] ==
'\r') {
11858 const uint8_t *terminator_start = ident_end - ident_length;
11859 const uint8_t *cursor = start;
11861 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
11862 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
11868 (cursor == terminator_start) &&
11869 (memcmp(terminator_start, ident_start, ident_length) == 0)
11871 if (newline != NULL) {
11872 pm_newline_list_append(&parser->
newline_list, newline);
11875 parser->
current.end = terminator_end;
11883 lex_state_set(parser, PM_LEX_STATE_END);
11884 lex_mode_pop(parser);
11885 LEX(PM_TOKEN_HEREDOC_END);
11889 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, heredoc_lex_mode->
indent);
11891 heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE &&
11894 peek_at(parser, start) !=
'\n'
11903 uint8_t breakpoints[] =
"\r\n\\#";
11906 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
11907 breakpoints[3] =
'\0';
11910 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11912 bool was_line_continuation =
false;
11914 while (breakpoint != NULL) {
11915 switch (*breakpoint) {
11918 parser->
current.end = breakpoint + 1;
11919 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11922 parser->
current.end = breakpoint + 1;
11924 if (peek_at(parser, breakpoint + 1) !=
'\n') {
11925 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11932 pm_token_buffer_escape(parser, &token_buffer);
11933 token_buffer.
cursor = breakpoint;
11938 parser_flush_heredoc_end(parser);
11939 parser->
current.end = breakpoint + 1;
11940 pm_token_buffer_flush(parser, &token_buffer);
11941 LEX(PM_TOKEN_STRING_CONTENT);
11944 pm_newline_list_append(&parser->
newline_list, breakpoint);
11948 const uint8_t *start = breakpoint + 1;
11950 if (!was_line_continuation && (start + ident_length <= parser->end)) {
11953 const uint8_t *newline = next_newline(start, parser->
end - start);
11955 if (newline == NULL) {
11956 newline = parser->
end;
11957 }
else if (newline[-1] ==
'\r') {
11962 const uint8_t *terminator_start = newline - ident_length;
11966 const uint8_t *cursor = start;
11968 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
11969 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
11975 cursor == terminator_start &&
11976 (memcmp(terminator_start, ident_start, ident_length) == 0)
11978 parser->
current.end = breakpoint + 1;
11979 pm_token_buffer_flush(parser, &token_buffer);
11980 LEX(PM_TOKEN_STRING_CONTENT);
11984 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->
as.heredoc.
base.
indent);
11991 if (lex_mode->
as.heredoc.
base.
indent == PM_HEREDOC_INDENT_TILDE) {
11996 parser->
current.end = breakpoint + 1;
11997 pm_token_buffer_flush(parser, &token_buffer);
11998 LEX(PM_TOKEN_STRING_CONTENT);
12003 parser->
current.end = breakpoint + 1;
12004 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12014 parser->
current.end = breakpoint + 1;
12023 pm_token_buffer_escape(parser, &token_buffer);
12024 uint8_t peeked = peek(parser);
12026 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12030 if (peek(parser) !=
'\n') {
12031 pm_token_buffer_push_byte(&token_buffer,
'\\');
12032 pm_token_buffer_push_byte(&token_buffer,
'\r');
12037 pm_token_buffer_push_byte(&token_buffer,
'\\');
12038 pm_token_buffer_push_byte(&token_buffer,
'\n');
12040 breakpoint = parser->
current.end;
12043 pm_token_buffer_push_byte(&token_buffer,
'\\');
12044 pm_token_buffer_push_escaped(&token_buffer, parser);
12051 if (peek(parser) !=
'\n') {
12052 pm_token_buffer_push_byte(&token_buffer,
'\r');
12060 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12061 const uint8_t *end = parser->
current.end;
12069 parser->
current.end = breakpoint;
12070 pm_token_buffer_flush(parser, &token_buffer);
12074 parser->
current.end = end + 1;
12076 LEX(PM_TOKEN_STRING_CONTENT);
12079 was_line_continuation =
true;
12081 breakpoint = parser->
current.end;
12084 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12090 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12094 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12096 if (
type == PM_TOKEN_NOT_PROVIDED) {
12102 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12106 if (
type == PM_TOKEN_STRING_CONTENT) {
12107 pm_token_buffer_flush(parser, &token_buffer);
12113 assert(
false &&
"unreachable");
12116 was_line_continuation =
false;
12121 pm_token_buffer_flush(parser, &token_buffer);
12122 LEX(PM_TOKEN_STRING_CONTENT);
12128 pm_token_buffer_flush(parser, &token_buffer);
12129 LEX(PM_TOKEN_STRING_CONTENT);
12133 assert(
false &&
"unreachable");
12151 PM_BINDING_POWER_UNSET = 0,
12152 PM_BINDING_POWER_STATEMENT = 2,
12153 PM_BINDING_POWER_MODIFIER_RESCUE = 4,
12154 PM_BINDING_POWER_MODIFIER = 6,
12155 PM_BINDING_POWER_COMPOSITION = 8,
12156 PM_BINDING_POWER_NOT = 10,
12157 PM_BINDING_POWER_MATCH = 12,
12158 PM_BINDING_POWER_DEFINED = 14,
12159 PM_BINDING_POWER_MULTI_ASSIGNMENT = 16,
12160 PM_BINDING_POWER_ASSIGNMENT = 18,
12161 PM_BINDING_POWER_TERNARY = 20,
12162 PM_BINDING_POWER_RANGE = 22,
12163 PM_BINDING_POWER_LOGICAL_OR = 24,
12164 PM_BINDING_POWER_LOGICAL_AND = 26,
12165 PM_BINDING_POWER_EQUALITY = 28,
12166 PM_BINDING_POWER_COMPARISON = 30,
12167 PM_BINDING_POWER_BITWISE_OR = 32,
12168 PM_BINDING_POWER_BITWISE_AND = 34,
12169 PM_BINDING_POWER_SHIFT = 36,
12170 PM_BINDING_POWER_TERM = 38,
12171 PM_BINDING_POWER_FACTOR = 40,
12172 PM_BINDING_POWER_UMINUS = 42,
12173 PM_BINDING_POWER_EXPONENT = 44,
12174 PM_BINDING_POWER_UNARY = 46,
12175 PM_BINDING_POWER_INDEX = 48,
12176 PM_BINDING_POWER_CALL = 50,
12177 PM_BINDING_POWER_MAX = 52
12178} pm_binding_power_t;
12201#define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true, false }
12202#define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, false }
12203#define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true, false }
12204#define NON_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, true }
12205#define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false, false }
12209 [PM_TOKEN_KEYWORD_RESCUE_MODIFIER] = { PM_BINDING_POWER_MODIFIER_RESCUE, PM_BINDING_POWER_COMPOSITION,
true,
false },
12212 [PM_TOKEN_KEYWORD_IF_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12213 [PM_TOKEN_KEYWORD_UNLESS_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12214 [PM_TOKEN_KEYWORD_UNTIL_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12215 [PM_TOKEN_KEYWORD_WHILE_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12218 [PM_TOKEN_KEYWORD_AND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
12219 [PM_TOKEN_KEYWORD_OR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
12222 [PM_TOKEN_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
12223 [PM_TOKEN_KEYWORD_IN] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
12226 [PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
12227 [PM_TOKEN_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
12228 [PM_TOKEN_CARET_EQUAL] = BINDING_POWER_ASSIGNMENT,
12229 [PM_TOKEN_EQUAL] = BINDING_POWER_ASSIGNMENT,
12230 [PM_TOKEN_GREATER_GREATER_EQUAL] = BINDING_POWER_ASSIGNMENT,
12231 [PM_TOKEN_LESS_LESS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12232 [PM_TOKEN_MINUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12233 [PM_TOKEN_PERCENT_EQUAL] = BINDING_POWER_ASSIGNMENT,
12234 [PM_TOKEN_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
12235 [PM_TOKEN_PIPE_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
12236 [PM_TOKEN_PLUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12237 [PM_TOKEN_SLASH_EQUAL] = BINDING_POWER_ASSIGNMENT,
12238 [PM_TOKEN_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
12239 [PM_TOKEN_STAR_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
12242 [PM_TOKEN_QUESTION_MARK] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_TERNARY),
12245 [PM_TOKEN_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
12246 [PM_TOKEN_DOT_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
12247 [PM_TOKEN_UDOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
12248 [PM_TOKEN_UDOT_DOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
12251 [PM_TOKEN_PIPE_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_OR),
12254 [PM_TOKEN_AMPERSAND_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_AND),
12257 [PM_TOKEN_BANG_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12258 [PM_TOKEN_BANG_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12259 [PM_TOKEN_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12260 [PM_TOKEN_EQUAL_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12261 [PM_TOKEN_EQUAL_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12262 [PM_TOKEN_LESS_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12265 [PM_TOKEN_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12266 [PM_TOKEN_GREATER_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12267 [PM_TOKEN_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12268 [PM_TOKEN_LESS_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12271 [PM_TOKEN_CARET] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12272 [PM_TOKEN_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12275 [PM_TOKEN_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_AND),
12278 [PM_TOKEN_GREATER_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
12279 [PM_TOKEN_LESS_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
12282 [PM_TOKEN_MINUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
12283 [PM_TOKEN_PLUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
12286 [PM_TOKEN_PERCENT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12287 [PM_TOKEN_SLASH] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12288 [PM_TOKEN_STAR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12289 [PM_TOKEN_USTAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_FACTOR),
12292 [PM_TOKEN_UMINUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UMINUS),
12293 [PM_TOKEN_UMINUS_NUM] = { PM_BINDING_POWER_UMINUS, PM_BINDING_POWER_MAX,
false,
false },
12296 [PM_TOKEN_STAR_STAR] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_EXPONENT),
12297 [PM_TOKEN_USTAR_STAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12300 [PM_TOKEN_BANG] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12301 [PM_TOKEN_TILDE] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12302 [PM_TOKEN_UPLUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12305 [PM_TOKEN_BRACKET_LEFT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_INDEX),
12308 [PM_TOKEN_COLON_COLON] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
12309 [PM_TOKEN_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
12310 [PM_TOKEN_AMPERSAND_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL)
12313#undef BINDING_POWER_ASSIGNMENT
12314#undef LEFT_ASSOCIATIVE
12315#undef RIGHT_ASSOCIATIVE
12316#undef RIGHT_ASSOCIATIVE_UNARY
12330match2(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
12331 return match1(parser, type1) || match1(parser, type2);
12338match3(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3) {
12339 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3);
12346match4(
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) {
12347 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4);
12354match7(
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) {
12355 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7);
12362match8(
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) {
12363 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);
12374 if (match1(parser,
type)) {
12375 parser_lex(parser);
12386accept2(
pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
12387 if (match2(parser, type1, type2)) {
12388 parser_lex(parser);
12407 if (accept1(parser,
type))
return;
12410 pm_parser_err(parser, location, location, diag_id);
12422 if (accept2(parser, type1, type2))
return;
12425 pm_parser_err(parser, location, location, diag_id);
12436expect1_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
12437 if (match1(parser, PM_TOKEN_HEREDOC_END)) {
12438 parser_lex(parser);
12440 pm_parser_err_heredoc_term(parser, ident_start, ident_length);
12454 if (accept1(parser,
type))
return;
12456 pm_parser_err(parser, opening->
start, opening->
end, diag_id);
12463parse_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);
12470parse_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) {
12471 pm_node_t *node = parse_expression(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
12472 pm_assert_value_expression(parser, node);
12495token_begins_expression_p(pm_token_type_t
type) {
12497 case PM_TOKEN_EQUAL_GREATER:
12498 case PM_TOKEN_KEYWORD_IN:
12502 case PM_TOKEN_BRACE_RIGHT:
12503 case PM_TOKEN_BRACKET_RIGHT:
12504 case PM_TOKEN_COLON:
12505 case PM_TOKEN_COMMA:
12506 case PM_TOKEN_EMBEXPR_END:
12508 case PM_TOKEN_LAMBDA_BEGIN:
12509 case PM_TOKEN_KEYWORD_DO:
12510 case PM_TOKEN_KEYWORD_DO_LOOP:
12511 case PM_TOKEN_KEYWORD_END:
12512 case PM_TOKEN_KEYWORD_ELSE:
12513 case PM_TOKEN_KEYWORD_ELSIF:
12514 case PM_TOKEN_KEYWORD_ENSURE:
12515 case PM_TOKEN_KEYWORD_THEN:
12516 case PM_TOKEN_KEYWORD_RESCUE:
12517 case PM_TOKEN_KEYWORD_WHEN:
12518 case PM_TOKEN_NEWLINE:
12519 case PM_TOKEN_PARENTHESIS_RIGHT:
12520 case PM_TOKEN_SEMICOLON:
12526 assert(pm_binding_powers[
type].left == PM_BINDING_POWER_UNSET);
12528 case PM_TOKEN_UAMPERSAND:
12532 case PM_TOKEN_UCOLON_COLON:
12533 case PM_TOKEN_UMINUS:
12534 case PM_TOKEN_UMINUS_NUM:
12535 case PM_TOKEN_UPLUS:
12536 case PM_TOKEN_BANG:
12537 case PM_TOKEN_TILDE:
12538 case PM_TOKEN_UDOT_DOT:
12539 case PM_TOKEN_UDOT_DOT_DOT:
12546 return pm_binding_powers[
type].left == PM_BINDING_POWER_UNSET;
12555parse_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) {
12556 if (accept1(parser, PM_TOKEN_USTAR)) {
12558 pm_node_t *expression = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
12559 return UP(pm_splat_node_create(parser, &
operator, expression));
12562 return parse_value_expression(parser, binding_power, accepts_command_call,
false, diag_id, depth);
12566pm_node_unreference_each(
const pm_node_t *node,
void *data) {
12567 switch (PM_NODE_TYPE(node)) {
12572 case PM_BREAK_NODE:
12574 case PM_REDO_NODE: {
12578 while (index < parser->current_block_exits->size) {
12581 if (block_exit == node) {
12604 case PM_LOCAL_VARIABLE_READ_NODE:
12605 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
12609 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
12610 if (implicit_parameters->
nodes[index] == node) {
12614 if (index != implicit_parameters->
size - 1) {
12615 memmove(&implicit_parameters->
nodes[index], &implicit_parameters->
nodes[index + 1], (implicit_parameters->
size - index - 1) *
sizeof(pm_node_t *));
12618 implicit_parameters->
size--;
12636pm_node_unreference(
pm_parser_t *parser,
const pm_node_t *node) {
12637 pm_visit_node(node, pm_node_unreference_each, parser);
12651 size_t length = constant->
length;
12652 uint8_t *name =
xcalloc(length + 1,
sizeof(uint8_t));
12653 if (name == NULL)
return;
12655 memcpy(name, constant->
start, length);
12656 name[length] =
'=';
12661 *name_field = pm_constant_pool_insert_owned(&parser->
constant_pool, name, length + 1);
12671parse_unwriteable_target(
pm_parser_t *parser, pm_node_t *target) {
12672 switch (PM_NODE_TYPE(target)) {
12673 case PM_SOURCE_ENCODING_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
12674 case PM_FALSE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
12675 case PM_SOURCE_FILE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
12676 case PM_SOURCE_LINE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
12677 case PM_NIL_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
12678 case PM_SELF_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
12679 case PM_TRUE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
12684 pm_local_variable_target_node_t *result = pm_local_variable_target_node_create(parser, &target->
location, name, 0);
12686 pm_node_destroy(parser, target);
12699parse_target(
pm_parser_t *parser, pm_node_t *target,
bool multiple,
bool splat_parent) {
12700 switch (PM_NODE_TYPE(target)) {
12701 case PM_MISSING_NODE:
12703 case PM_SOURCE_ENCODING_NODE:
12704 case PM_FALSE_NODE:
12705 case PM_SOURCE_FILE_NODE:
12706 case PM_SOURCE_LINE_NODE:
12709 case PM_TRUE_NODE: {
12712 return parse_unwriteable_target(parser, target);
12714 case PM_CLASS_VARIABLE_READ_NODE:
12715 assert(
sizeof(pm_class_variable_target_node_t) ==
sizeof(pm_class_variable_read_node_t));
12716 target->
type = PM_CLASS_VARIABLE_TARGET_NODE;
12718 case PM_CONSTANT_PATH_NODE:
12719 if (context_def_p(parser)) {
12720 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
12723 assert(
sizeof(pm_constant_path_target_node_t) ==
sizeof(pm_constant_path_node_t));
12724 target->
type = PM_CONSTANT_PATH_TARGET_NODE;
12727 case PM_CONSTANT_READ_NODE:
12728 if (context_def_p(parser)) {
12729 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
12732 assert(
sizeof(pm_constant_target_node_t) ==
sizeof(pm_constant_read_node_t));
12733 target->
type = PM_CONSTANT_TARGET_NODE;
12736 case PM_BACK_REFERENCE_READ_NODE:
12737 case PM_NUMBERED_REFERENCE_READ_NODE:
12738 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
12740 case PM_GLOBAL_VARIABLE_READ_NODE:
12741 assert(
sizeof(pm_global_variable_target_node_t) ==
sizeof(pm_global_variable_read_node_t));
12742 target->
type = PM_GLOBAL_VARIABLE_TARGET_NODE;
12744 case PM_LOCAL_VARIABLE_READ_NODE: {
12747 pm_node_unreference(parser, target);
12750 const pm_local_variable_read_node_t *cast = (
const pm_local_variable_read_node_t *) target;
12751 uint32_t name = cast->
name;
12752 uint32_t depth = cast->
depth;
12753 pm_locals_unread(&pm_parser_scope_find(parser, depth)->locals, name);
12755 assert(
sizeof(pm_local_variable_target_node_t) ==
sizeof(pm_local_variable_read_node_t));
12756 target->
type = PM_LOCAL_VARIABLE_TARGET_NODE;
12760 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
12762 pm_node_t *node = UP(pm_local_variable_target_node_create(parser, &target->
location, name, 0));
12764 pm_node_unreference(parser, target);
12765 pm_node_destroy(parser, target);
12769 case PM_INSTANCE_VARIABLE_READ_NODE:
12770 assert(
sizeof(pm_instance_variable_target_node_t) ==
sizeof(pm_instance_variable_read_node_t));
12771 target->
type = PM_INSTANCE_VARIABLE_TARGET_NODE;
12773 case PM_MULTI_TARGET_NODE:
12774 if (splat_parent) {
12777 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
12781 case PM_SPLAT_NODE: {
12782 pm_splat_node_t *splat = (pm_splat_node_t *) target;
12790 case PM_CALL_NODE: {
12791 pm_call_node_t *call = (pm_call_node_t *) target;
12802 (call->
block == NULL)
12817 pm_node_destroy(parser, target);
12819 return UP(pm_local_variable_target_node_create(parser, &message_loc, name, 0));
12823 if (multiple && PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
12824 pm_parser_err_node(parser, (
const pm_node_t *) call, PM_ERR_UNEXPECTED_SAFE_NAVIGATION);
12827 parse_write_name(parser, &call->
name);
12828 return UP(pm_call_target_node_create(parser, call));
12835 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
12836 return UP(pm_index_target_node_create(parser, call));
12844 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
12854parse_target_validate(
pm_parser_t *parser, pm_node_t *target,
bool multiple) {
12855 pm_node_t *result = parse_target(parser, target, multiple,
false);
12860 !match1(parser, PM_TOKEN_EQUAL) &&
12862 !(context_p(parser,
PM_CONTEXT_PARENS) && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
12864 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
12875parse_shareable_constant_write(
pm_parser_t *parser, pm_node_t *write) {
12878 if (shareable_constant != PM_SCOPE_SHAREABLE_CONSTANT_NONE) {
12879 return UP(pm_shareable_constant_node_create(parser, write, shareable_constant));
12890 switch (PM_NODE_TYPE(target)) {
12891 case PM_MISSING_NODE:
12892 pm_node_destroy(parser, value);
12894 case PM_CLASS_VARIABLE_READ_NODE: {
12895 pm_class_variable_write_node_t *node = pm_class_variable_write_node_create(parser, (pm_class_variable_read_node_t *) target,
operator, value);
12896 pm_node_destroy(parser, target);
12899 case PM_CONSTANT_PATH_NODE: {
12900 pm_node_t *node = UP(pm_constant_path_write_node_create(parser, (pm_constant_path_node_t *) target,
operator, value));
12902 if (context_def_p(parser)) {
12903 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
12906 return parse_shareable_constant_write(parser, node);
12908 case PM_CONSTANT_READ_NODE: {
12909 pm_node_t *node = UP(pm_constant_write_node_create(parser, (pm_constant_read_node_t *) target,
operator, value));
12911 if (context_def_p(parser)) {
12912 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
12915 pm_node_destroy(parser, target);
12916 return parse_shareable_constant_write(parser, node);
12918 case PM_BACK_REFERENCE_READ_NODE:
12919 case PM_NUMBERED_REFERENCE_READ_NODE:
12920 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
12922 case PM_GLOBAL_VARIABLE_READ_NODE: {
12923 pm_global_variable_write_node_t *node = pm_global_variable_write_node_create(parser, target,
operator, value);
12924 pm_node_destroy(parser, target);
12927 case PM_LOCAL_VARIABLE_READ_NODE: {
12928 pm_local_variable_read_node_t *local_read = (pm_local_variable_read_node_t *) target;
12933 uint32_t depth = local_read->
depth;
12934 pm_scope_t *scope = pm_parser_scope_find(parser, depth);
12937 pm_diagnostic_id_t diag_id = (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND) ? PM_ERR_EXPRESSION_NOT_WRITABLE_NUMBERED : PM_ERR_PARAMETER_NUMBERED_RESERVED;
12939 pm_node_unreference(parser, target);
12942 pm_locals_unread(&scope->
locals, name);
12943 pm_node_destroy(parser, target);
12945 return UP(pm_local_variable_write_node_create(parser, name, depth, value, &name_loc,
operator));
12947 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
12949 pm_node_t *node = UP(pm_local_variable_write_node_create(parser, name, 0, value, &target->
location,
operator));
12951 pm_node_unreference(parser, target);
12952 pm_node_destroy(parser, target);
12956 case PM_INSTANCE_VARIABLE_READ_NODE: {
12957 pm_node_t *write_node = UP(pm_instance_variable_write_node_create(parser, (pm_instance_variable_read_node_t *) target,
operator, value));
12958 pm_node_destroy(parser, target);
12961 case PM_MULTI_TARGET_NODE:
12962 return UP(pm_multi_write_node_create(parser, (pm_multi_target_node_t *) target,
operator, value));
12963 case PM_SPLAT_NODE: {
12964 pm_splat_node_t *splat = (pm_splat_node_t *) target;
12970 pm_multi_target_node_t *multi_target = pm_multi_target_node_create(parser);
12971 pm_multi_target_node_targets_append(parser, multi_target, UP(splat));
12973 return UP(pm_multi_write_node_create(parser, multi_target,
operator, value));
12975 case PM_CALL_NODE: {
12976 pm_call_node_t *call = (pm_call_node_t *) target;
12987 (call->
block == NULL)
13001 pm_parser_local_add_location(parser, message.
start, message.
end, 0);
13002 pm_node_destroy(parser, target);
13005 target = UP(pm_local_variable_write_node_create(parser, constant_id, 0, value, &message,
operator));
13007 pm_refute_numbered_parameter(parser, message.
start, message.
end);
13022 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
13025 pm_arguments_node_arguments_append(arguments, value);
13027 call->
equal_loc = PM_LOCATION_TOKEN_VALUE(
operator);
13029 parse_write_name(parser, &call->
name);
13030 pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
13039 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
13041 call->
arguments = pm_arguments_node_create(parser);
13044 pm_arguments_node_arguments_append(call->
arguments, value);
13048 call->
name = pm_parser_constant_id_constant(parser,
"[]=", 3);
13049 call->
equal_loc = PM_LOCATION_TOKEN_VALUE(
operator);
13053 pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
13068 pm_node_unreference(parser, value);
13069 pm_node_destroy(parser, value);
13076 pm_parser_err_token(parser,
operator, PM_ERR_WRITE_TARGET_UNEXPECTED);
13088parse_unwriteable_write(
pm_parser_t *parser, pm_node_t *target,
const pm_token_t *equals, pm_node_t *value) {
13089 switch (PM_NODE_TYPE(target)) {
13090 case PM_SOURCE_ENCODING_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13091 case PM_FALSE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13092 case PM_SOURCE_FILE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13093 case PM_SOURCE_LINE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13094 case PM_NIL_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13095 case PM_SELF_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13096 case PM_TRUE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13101 pm_local_variable_write_node_t *result = pm_local_variable_write_node_create(parser, name, 0, value, &target->
location, equals);
13103 pm_node_destroy(parser, target);
13118parse_targets(
pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13119 bool has_rest = PM_NODE_TYPE_P(first_target, PM_SPLAT_NODE);
13121 pm_multi_target_node_t *result = pm_multi_target_node_create(parser);
13122 pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target,
true,
false));
13124 while (accept1(parser, PM_TOKEN_COMMA)) {
13125 if (accept1(parser, PM_TOKEN_USTAR)) {
13130 pm_parser_err_previous(parser, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
13134 pm_node_t *name = NULL;
13136 if (token_begins_expression_p(parser->
current.type)) {
13137 name = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13138 name = parse_target(parser, name,
true,
true);
13141 pm_node_t *splat = UP(pm_splat_node_create(parser, &star_operator, name));
13142 pm_multi_target_node_targets_append(parser, result, splat);
13144 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
13146 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13147 target = parse_target(parser, target,
true,
false);
13149 pm_multi_target_node_targets_append(parser, result, target);
13150 context_pop(parser);
13151 }
else if (token_begins_expression_p(parser->
current.type)) {
13152 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13153 target = parse_target(parser, target,
true,
false);
13155 pm_multi_target_node_targets_append(parser, result, target);
13156 }
else if (!match1(parser, PM_TOKEN_EOF)) {
13159 pm_node_t *rest = UP(pm_implicit_rest_node_create(parser, &parser->
previous));
13160 pm_multi_target_node_targets_append(parser, result, rest);
13173parse_targets_validate(
pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13174 pm_node_t *result = parse_targets(parser, first_target, binding_power, depth);
13175 accept1(parser, PM_TOKEN_NEWLINE);
13178 if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
13179 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13188static pm_statements_node_t *
13192 while (accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE));
13195 if (context_terminator(context, &parser->
current))
return NULL;
13197 pm_statements_node_t *statements = pm_statements_node_create(parser);
13201 context_push(parser, context);
13204 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
13205 pm_statements_node_body_append(parser, statements, node,
true);
13218 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
13221 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13222 if (context_terminator(context, &parser->
current))
break;
13232 if (context_terminator(context, &parser->
current))
break;
13244 if (PM_NODE_TYPE_P(node, PM_MISSING_NODE)) {
13245 parser_lex(parser);
13251 if (match1(parser, PM_TOKEN_EOF)) {
13256 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13257 if (context_terminator(context, &parser->
current))
break;
13258 }
else if (!accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_EOF)) {
13268 context_pop(parser);
13269 bool last_value =
true;
13273 last_value =
false;
13278 pm_void_statements_check(parser, statements, last_value);
13289 const pm_node_t *duplicated = pm_static_literals_add(&parser->
newline_list, parser->
start_line, literals, node,
true);
13291 if (duplicated != NULL) {
13295 pm_diagnostic_list_append_format(
13299 PM_WARN_DUPLICATED_HASH_KEY,
13300 (
int) pm_buffer_length(&buffer),
13301 pm_buffer_value(&buffer),
13305 pm_buffer_free(&buffer);
13315 pm_node_t *previous;
13317 if ((previous = pm_static_literals_add(&parser->
newline_list, parser->
start_line, literals, node,
false)) != NULL) {
13318 pm_diagnostic_list_append_format(
13322 PM_WARN_DUPLICATED_WHEN_CLAUSE,
13334 assert(PM_NODE_TYPE_P(node, PM_HASH_NODE) || PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE));
13335 bool contains_keyword_splat =
false;
13338 pm_node_t *element;
13340 switch (parser->
current.type) {
13341 case PM_TOKEN_USTAR_STAR: {
13342 parser_lex(parser);
13344 pm_node_t *value = NULL;
13346 if (match1(parser, PM_TOKEN_BRACE_LEFT)) {
13352 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
13353 }
else if (token_begins_expression_p(parser->
current.type)) {
13354 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
13356 pm_parser_scope_forwarding_keywords_check(parser, &
operator);
13359 element = UP(pm_assoc_splat_node_create(parser, value, &
operator));
13360 contains_keyword_splat =
true;
13363 case PM_TOKEN_LABEL: {
13365 parser_lex(parser);
13367 pm_node_t *key = UP(pm_symbol_node_label_create(parser, &label));
13368 pm_hash_key_static_literals_add(parser, literals, key);
13371 pm_node_t *value = NULL;
13373 if (token_begins_expression_p(parser->
current.type)) {
13374 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_EXPRESSION_AFTER_LABEL, (uint16_t) (depth + 1));
13377 pm_token_t constant = { .type = PM_TOKEN_CONSTANT, .start = label.
start, .end = label.
end - 1 };
13378 value = UP(pm_constant_read_node_create(parser, &constant));
13381 pm_token_t identifier = { .type = PM_TOKEN_IDENTIFIER, .start = label.
start, .end = label.
end - 1 };
13383 if (identifier.
end[-1] ==
'!' || identifier.
end[-1] ==
'?') {
13384 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, identifier, PM_ERR_INVALID_LOCAL_VARIABLE_READ);
13386 depth = pm_parser_local_depth(parser, &identifier);
13390 value = UP(pm_call_node_variable_call_create(parser, &identifier));
13392 value = UP(pm_local_variable_read_node_create(parser, &identifier, (uint32_t) depth));
13397 value = UP(pm_implicit_node_create(parser, value));
13400 element = UP(pm_assoc_node_create(parser, key, &
operator, value));
13404 pm_node_t *key = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_HASH_KEY, (uint16_t) (depth + 1));
13408 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
13409 pm_node_flag_set(key, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
13412 pm_hash_key_static_literals_add(parser, literals, key);
13415 if (pm_symbol_node_label_p(key)) {
13416 operator = not_provided(parser);
13418 expect1(parser, PM_TOKEN_EQUAL_GREATER, PM_ERR_HASH_ROCKET);
13422 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
13423 element = UP(pm_assoc_node_create(parser, key, &
operator, value));
13428 if (PM_NODE_TYPE_P(node, PM_HASH_NODE)) {
13429 pm_hash_node_elements_append((pm_hash_node_t *) node, element);
13431 pm_keyword_hash_node_elements_append((pm_keyword_hash_node_t *) node, element);
13435 if (!accept1(parser, PM_TOKEN_COMMA))
break;
13439 if (match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL))
continue;
13443 if (token_begins_expression_p(parser->
current.type))
continue;
13449 return contains_keyword_splat;
13453argument_allowed_for_bare_hash(
pm_parser_t *parser, pm_node_t *argument) {
13454 if (pm_symbol_node_label_p(argument)) {
13458 switch (PM_NODE_TYPE(argument)) {
13459 case PM_CALL_NODE: {
13460 pm_call_node_t *cast = (pm_call_node_t *) argument;
13462 if (PM_NODE_FLAG_P(cast->
arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS | PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
13465 if (cast->
block != NULL) {
13473 return accept1(parser, PM_TOKEN_EQUAL_GREATER);
13482 arguments->
arguments = pm_arguments_node_create(parser);
13485 pm_arguments_node_arguments_append(arguments->
arguments, argument);
13492parse_arguments(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_forwarding, pm_token_type_t terminator, uint16_t depth) {
13493 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].left;
13498 match2(parser, terminator, PM_TOKEN_EOF) ||
13499 (binding_power != PM_BINDING_POWER_UNSET && binding_power < PM_BINDING_POWER_RANGE) ||
13505 bool parsed_first_argument =
false;
13506 bool parsed_bare_hash =
false;
13507 bool parsed_block_argument =
false;
13508 bool parsed_forwarding_arguments =
false;
13510 while (!match1(parser, PM_TOKEN_EOF)) {
13511 if (parsed_forwarding_arguments) {
13512 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES);
13515 pm_node_t *argument = NULL;
13517 switch (parser->
current.type) {
13518 case PM_TOKEN_USTAR_STAR:
13519 case PM_TOKEN_LABEL: {
13520 if (parsed_bare_hash) {
13521 pm_parser_err_current(parser, PM_ERR_ARGUMENT_BARE_HASH);
13524 pm_keyword_hash_node_t *hash = pm_keyword_hash_node_create(parser);
13525 argument = UP(hash);
13528 bool contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(hash), (uint16_t) (depth + 1));
13530 parse_arguments_append(parser, arguments, argument);
13532 pm_node_flags_t flags = PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
13533 if (contains_keyword_splat) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
13534 pm_node_flag_set(UP(arguments->
arguments), flags);
13536 pm_static_literals_free(&hash_keys);
13537 parsed_bare_hash =
true;
13541 case PM_TOKEN_UAMPERSAND: {
13542 parser_lex(parser);
13544 pm_node_t *expression = NULL;
13546 if (token_begins_expression_p(parser->
current.type)) {
13547 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
13549 pm_parser_scope_forwarding_block_check(parser, &
operator);
13552 argument = UP(pm_block_argument_node_create(parser, &
operator, expression));
13553 if (parsed_block_argument) {
13554 parse_arguments_append(parser, arguments, argument);
13556 arguments->
block = argument;
13559 if (match1(parser, PM_TOKEN_COMMA)) {
13560 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK);
13563 parsed_block_argument =
true;
13566 case PM_TOKEN_USTAR: {
13567 parser_lex(parser);
13570 if (match4(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_SEMICOLON, PM_TOKEN_BRACKET_RIGHT)) {
13571 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
13572 argument = UP(pm_splat_node_create(parser, &
operator, NULL));
13573 if (parsed_bare_hash) {
13574 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
13577 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT, (uint16_t) (depth + 1));
13579 if (parsed_bare_hash) {
13580 pm_parser_err(parser,
operator.start, expression->
location.
end, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
13583 argument = UP(pm_splat_node_create(parser, &
operator, expression));
13586 parse_arguments_append(parser, arguments, argument);
13589 case PM_TOKEN_UDOT_DOT_DOT: {
13590 if (accepts_forwarding) {
13591 parser_lex(parser);
13593 if (token_begins_expression_p(parser->
current.type)) {
13598 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_RANGE,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
13603 if (PM_NODE_TYPE_P(right, PM_RANGE_NODE)) {
13604 pm_range_node_t *range = (pm_range_node_t *) right;
13605 pm_parser_err(parser, range->operator_loc.start, range->operator_loc.end, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
13608 argument = UP(pm_range_node_create(parser, NULL, &
operator, right));
13610 pm_parser_scope_forwarding_all_check(parser, &parser->
previous);
13611 if (parsed_first_argument && terminator == PM_TOKEN_EOF) {
13612 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORWARDING_UNBOUND);
13615 argument = UP(pm_forwarding_arguments_node_create(parser, &parser->
previous));
13616 parse_arguments_append(parser, arguments, argument);
13617 pm_node_flag_set(UP(arguments->
arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING);
13619 parsed_forwarding_arguments =
true;
13626 if (argument == NULL) {
13627 argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, !parsed_first_argument,
true, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
13630 bool contains_keywords =
false;
13631 bool contains_keyword_splat =
false;
13633 if (argument_allowed_for_bare_hash(parser, argument)){
13634 if (parsed_bare_hash) {
13635 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
13639 if (parser->
previous.
type == PM_TOKEN_EQUAL_GREATER) {
13642 operator = not_provided(parser);
13645 pm_keyword_hash_node_t *bare_hash = pm_keyword_hash_node_create(parser);
13646 contains_keywords =
true;
13650 pm_hash_key_static_literals_add(parser, &hash_keys, argument);
13653 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
13654 argument = UP(pm_assoc_node_create(parser, argument, &
operator, value));
13656 pm_keyword_hash_node_elements_append(bare_hash, argument);
13657 argument = UP(bare_hash);
13660 if (accept1(parser, PM_TOKEN_COMMA) && (
13661 token_begins_expression_p(parser->
current.type) ||
13662 match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL)
13664 contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(bare_hash), (uint16_t) (depth + 1));
13667 pm_static_literals_free(&hash_keys);
13668 parsed_bare_hash =
true;
13671 parse_arguments_append(parser, arguments, argument);
13673 pm_node_flags_t flags = 0;
13674 if (contains_keywords) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
13675 if (contains_keyword_splat) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
13676 pm_node_flag_set(UP(arguments->
arguments), flags);
13682 parsed_first_argument =
true;
13685 if (PM_NODE_TYPE_P(argument, PM_MISSING_NODE) || parser->
recovering)
break;
13690 bool accepted_newline =
false;
13691 if (terminator != PM_TOKEN_EOF) {
13692 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
13695 if (parser->
previous.
type == PM_TOKEN_COMMA && parsed_bare_hash) {
13699 }
else if (accept1(parser, PM_TOKEN_COMMA)) {
13702 if (accepted_newline) {
13703 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
13709 if (PM_NODE_TYPE_P(argument, PM_CALL_NODE)) {
13710 pm_call_node_t *call = (pm_call_node_t *) argument;
13712 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
13724 if (match1(parser, terminator))
break;
13738static pm_multi_target_node_t *
13739parse_required_destructured_parameter(
pm_parser_t *parser) {
13740 expect1(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_ERR_EXPECT_LPAREN_REQ_PARAMETER);
13742 pm_multi_target_node_t *node = pm_multi_target_node_create(parser);
13743 pm_multi_target_node_opening_set(node, &parser->
previous);
13752 if (node->
lefts.
size > 0 && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
13753 param = UP(pm_implicit_rest_node_create(parser, &parser->
previous));
13754 pm_multi_target_node_targets_append(parser, node, param);
13755 pm_parser_err_current(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
13759 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
13760 param = UP(parse_required_destructured_parameter(parser));
13761 }
else if (accept1(parser, PM_TOKEN_USTAR)) {
13763 pm_node_t *value = NULL;
13765 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
13767 value = UP(pm_required_parameter_node_create(parser, &name));
13768 if (pm_parser_parameter_name_check(parser, &name)) {
13769 pm_node_flag_set_repeated_parameter(value);
13771 pm_parser_local_add_token(parser, &name, 1);
13774 param = UP(pm_splat_node_create(parser, &star, value));
13776 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EXPECT_IDENT_REQ_PARAMETER);
13779 param = UP(pm_required_parameter_node_create(parser, &name));
13780 if (pm_parser_parameter_name_check(parser, &name)) {
13781 pm_node_flag_set_repeated_parameter(param);
13783 pm_parser_local_add_token(parser, &name, 1);
13786 pm_multi_target_node_targets_append(parser, node, param);
13787 }
while (accept1(parser, PM_TOKEN_COMMA));
13789 accept1(parser, PM_TOKEN_NEWLINE);
13790 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN_REQ_PARAMETER);
13791 pm_multi_target_node_closing_set(node, &parser->
previous);
13801 PM_PARAMETERS_NO_CHANGE = 0,
13802 PM_PARAMETERS_ORDER_NOTHING_AFTER = 1,
13803 PM_PARAMETERS_ORDER_KEYWORDS_REST,
13804 PM_PARAMETERS_ORDER_KEYWORDS,
13805 PM_PARAMETERS_ORDER_REST,
13806 PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
13807 PM_PARAMETERS_ORDER_OPTIONAL,
13808 PM_PARAMETERS_ORDER_NAMED,
13809 PM_PARAMETERS_ORDER_NONE,
13810} pm_parameters_order_t;
13815static pm_parameters_order_t parameters_ordering[PM_TOKEN_MAXIMUM] = {
13816 [0] = PM_PARAMETERS_NO_CHANGE,
13817 [PM_TOKEN_UAMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
13818 [PM_TOKEN_AMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
13819 [PM_TOKEN_UDOT_DOT_DOT] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
13820 [PM_TOKEN_IDENTIFIER] = PM_PARAMETERS_ORDER_NAMED,
13821 [PM_TOKEN_PARENTHESIS_LEFT] = PM_PARAMETERS_ORDER_NAMED,
13822 [PM_TOKEN_EQUAL] = PM_PARAMETERS_ORDER_OPTIONAL,
13823 [PM_TOKEN_LABEL] = PM_PARAMETERS_ORDER_KEYWORDS,
13824 [PM_TOKEN_USTAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
13825 [PM_TOKEN_STAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
13826 [PM_TOKEN_USTAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST,
13827 [PM_TOKEN_STAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST
13839 pm_parameters_order_t state = parameters_ordering[token->type];
13840 if (state == PM_PARAMETERS_NO_CHANGE)
return true;
13844 if (*current == PM_PARAMETERS_ORDER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
13845 *current = PM_PARAMETERS_ORDER_AFTER_OPTIONAL;
13847 }
else if (*current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
13851 if (token->type == PM_TOKEN_USTAR && *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
13852 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_STAR);
13854 }
else if (token->type == PM_TOKEN_UDOT_DOT_DOT && (*current >= PM_PARAMETERS_ORDER_KEYWORDS_REST && *current <= PM_PARAMETERS_ORDER_AFTER_OPTIONAL)) {
13855 pm_parser_err_token(parser, token, *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL ? PM_ERR_PARAMETER_FORWARDING_AFTER_REST : PM_ERR_PARAMETER_ORDER);
13857 }
else if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
13859 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_ORDER);
13863 if (state < *current) *current = state;
13870static pm_parameters_node_t *
13873 pm_binding_power_t binding_power,
13874 bool uses_parentheses,
13875 bool allows_trailing_comma,
13876 bool allows_forwarding_parameters,
13877 bool accepts_blocks_in_defaults,
13882 pm_do_loop_stack_push(parser,
false);
13884 pm_parameters_node_t *params = pm_parameters_node_create(parser);
13885 pm_parameters_order_t order = PM_PARAMETERS_ORDER_NONE;
13888 bool parsing =
true;
13890 switch (parser->
current.type) {
13891 case PM_TOKEN_PARENTHESIS_LEFT: {
13892 update_parameter_state(parser, &parser->
current, &order);
13893 pm_node_t *param = UP(parse_required_destructured_parameter(parser));
13895 if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
13896 pm_parameters_node_requireds_append(params, param);
13898 pm_parameters_node_posts_append(params, param);
13902 case PM_TOKEN_UAMPERSAND:
13903 case PM_TOKEN_AMPERSAND: {
13904 update_parameter_state(parser, &parser->
current, &order);
13905 parser_lex(parser);
13910 bool repeated =
false;
13911 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
13913 repeated = pm_parser_parameter_name_check(parser, &name);
13914 pm_parser_local_add_token(parser, &name, 1);
13916 name = not_provided(parser);
13920 pm_block_parameter_node_t *param = pm_block_parameter_node_create(parser, &name, &
operator);
13922 pm_node_flag_set_repeated_parameter(UP(param));
13924 if (params->
block == NULL) {
13925 pm_parameters_node_block_set(params, param);
13927 pm_parser_err_node(parser, UP(param), PM_ERR_PARAMETER_BLOCK_MULTI);
13928 pm_parameters_node_posts_append(params, UP(param));
13933 case PM_TOKEN_UDOT_DOT_DOT: {
13934 if (!allows_forwarding_parameters) {
13935 pm_parser_err_current(parser, diag_id_forwarding);
13938 bool succeeded = update_parameter_state(parser, &parser->
current, &order);
13939 parser_lex(parser);
13942 pm_forwarding_parameter_node_t *param = pm_forwarding_parameter_node_create(parser, &parser->
previous);
13948 pm_parameters_node_posts_append(params, keyword_rest);
13949 if (succeeded) pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD);
13953 pm_parameters_node_keyword_rest_set(params, UP(param));
13956 case PM_TOKEN_CLASS_VARIABLE:
13957 case PM_TOKEN_IDENTIFIER:
13958 case PM_TOKEN_CONSTANT:
13959 case PM_TOKEN_INSTANCE_VARIABLE:
13960 case PM_TOKEN_GLOBAL_VARIABLE:
13961 case PM_TOKEN_METHOD_NAME: {
13962 parser_lex(parser);
13964 case PM_TOKEN_CONSTANT:
13965 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
13967 case PM_TOKEN_INSTANCE_VARIABLE:
13968 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
13970 case PM_TOKEN_GLOBAL_VARIABLE:
13971 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
13973 case PM_TOKEN_CLASS_VARIABLE:
13974 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
13976 case PM_TOKEN_METHOD_NAME:
13977 pm_parser_err_previous(parser, PM_ERR_PARAMETER_METHOD_NAME);
13982 if (parser->
current.type == PM_TOKEN_EQUAL) {
13983 update_parameter_state(parser, &parser->
current, &order);
13985 update_parameter_state(parser, &parser->
previous, &order);
13989 bool repeated = pm_parser_parameter_name_check(parser, &name);
13990 pm_parser_local_add_token(parser, &name, 1);
13992 if (match1(parser, PM_TOKEN_EQUAL)) {
13995 parser_lex(parser);
14000 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14001 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
14002 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14004 pm_optional_parameter_node_t *param = pm_optional_parameter_node_create(parser, &name, &
operator, value);
14007 pm_node_flag_set_repeated_parameter(UP(param));
14009 pm_parameters_node_optionals_append(params, param);
14015 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, name, PM_ERR_PARAMETER_CIRCULAR);
14018 context_pop(parser);
14027 }
else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14028 pm_required_parameter_node_t *param = pm_required_parameter_node_create(parser, &name);
14030 pm_node_flag_set_repeated_parameter(UP(param));
14032 pm_parameters_node_requireds_append(params, UP(param));
14034 pm_required_parameter_node_t *param = pm_required_parameter_node_create(parser, &name);
14036 pm_node_flag_set_repeated_parameter(UP(param));
14038 pm_parameters_node_posts_append(params, UP(param));
14043 case PM_TOKEN_LABEL: {
14044 if (!uses_parentheses && !in_block) parser->
in_keyword_arg =
true;
14045 update_parameter_state(parser, &parser->
current, &order);
14048 parser_lex(parser);
14055 pm_parser_err(parser, local.
start, local.
end, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14056 }
else if (local.
end[-1] ==
'!' || local.
end[-1] ==
'?') {
14057 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
14060 bool repeated = pm_parser_parameter_name_check(parser, &local);
14061 pm_parser_local_add_token(parser, &local, 1);
14063 switch (parser->
current.type) {
14064 case PM_TOKEN_COMMA:
14065 case PM_TOKEN_PARENTHESIS_RIGHT:
14066 case PM_TOKEN_PIPE: {
14067 context_pop(parser);
14069 pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14071 pm_node_flag_set_repeated_parameter(param);
14074 pm_parameters_node_keywords_append(params, param);
14077 case PM_TOKEN_SEMICOLON:
14078 case PM_TOKEN_NEWLINE: {
14079 context_pop(parser);
14081 if (uses_parentheses) {
14086 pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14088 pm_node_flag_set_repeated_parameter(param);
14091 pm_parameters_node_keywords_append(params, param);
14097 if (token_begins_expression_p(parser->
current.type)) {
14101 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14102 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT_KW, (uint16_t) (depth + 1));
14103 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14106 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_PARAMETER_CIRCULAR);
14109 param = UP(pm_optional_keyword_parameter_node_create(parser, &name, value));
14112 param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14116 pm_node_flag_set_repeated_parameter(param);
14119 context_pop(parser);
14120 pm_parameters_node_keywords_append(params, param);
14135 case PM_TOKEN_USTAR:
14136 case PM_TOKEN_STAR: {
14137 update_parameter_state(parser, &parser->
current, &order);
14138 parser_lex(parser);
14142 bool repeated =
false;
14144 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14146 repeated = pm_parser_parameter_name_check(parser, &name);
14147 pm_parser_local_add_token(parser, &name, 1);
14149 name = not_provided(parser);
14153 pm_node_t *param = UP(pm_rest_parameter_node_create(parser, &
operator, &name));
14155 pm_node_flag_set_repeated_parameter(param);
14158 if (params->
rest == NULL) {
14159 pm_parameters_node_rest_set(params, param);
14161 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_SPLAT_MULTI);
14162 pm_parameters_node_posts_append(params, param);
14167 case PM_TOKEN_STAR_STAR:
14168 case PM_TOKEN_USTAR_STAR: {
14169 pm_parameters_order_t previous_order = order;
14170 update_parameter_state(parser, &parser->
current, &order);
14171 parser_lex(parser);
14176 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
14177 if (previous_order <= PM_PARAMETERS_ORDER_KEYWORDS) {
14178 pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_NO_KW);
14181 param = UP(pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous));
14185 bool repeated =
false;
14186 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14188 repeated = pm_parser_parameter_name_check(parser, &name);
14189 pm_parser_local_add_token(parser, &name, 1);
14191 name = not_provided(parser);
14195 param = UP(pm_keyword_rest_parameter_node_create(parser, &
operator, &name));
14197 pm_node_flag_set_repeated_parameter(param);
14202 pm_parameters_node_keyword_rest_set(params, param);
14204 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI);
14205 pm_parameters_node_posts_append(params, param);
14212 if (allows_trailing_comma && order >= PM_PARAMETERS_ORDER_NAMED) {
14215 pm_node_t *param = UP(pm_implicit_rest_node_create(parser, &parser->
previous));
14217 if (params->
rest == NULL) {
14218 pm_parameters_node_rest_set(params, param);
14220 pm_parser_err_node(parser, UP(param), PM_ERR_PARAMETER_SPLAT_MULTI);
14221 pm_parameters_node_posts_append(params, UP(param));
14224 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14235 if (!parsing)
break;
14237 bool accepted_newline =
false;
14238 if (uses_parentheses) {
14239 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
14242 if (accept1(parser, PM_TOKEN_COMMA)) {
14245 if (accepted_newline) {
14246 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14254 pm_do_loop_stack_pop(parser);
14258 pm_node_destroy(parser, UP(params));
14290token_column(
const pm_parser_t *parser,
size_t newline_index,
const pm_token_t *token,
bool break_on_non_space) {
14292 const uint8_t *end = token->start;
14296 newline_index == 0 &&
14297 parser->
start[0] == 0xef &&
14298 parser->
start[1] == 0xbb &&
14299 parser->
start[2] == 0xbf
14302 int64_t column = 0;
14303 for (; cursor < end; cursor++) {
14306 column = ((column / PM_TAB_WHITESPACE_SIZE) + 1) * PM_TAB_WHITESPACE_SIZE;
14313 if (break_on_non_space)
return -1;
14326parser_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) {
14331 size_t closing_newline_index = token_newline_index(parser);
14332 if (opening_newline_index == closing_newline_index)
return;
14337 int64_t opening_column = token_column(parser, opening_newline_index, opening_token, !if_after_else);
14338 if (!if_after_else && (opening_column == -1))
return;
14345 int64_t closing_column = token_column(parser, closing_newline_index, closing_token,
true);
14346 if ((closing_column == -1) || (opening_column == closing_column))
return;
14350 if (allow_indent && (closing_column > opening_column))
return;
14353 PM_PARSER_WARN_FORMAT(
14355 closing_token->
start,
14356 closing_token->
end,
14357 PM_WARN_INDENTATION_MISMATCH,
14358 (
int) (closing_token->
end - closing_token->
start),
14359 (
const char *) closing_token->
start,
14360 (
int) (opening_token->
end - opening_token->
start),
14361 (
const char *) opening_token->
start,
14362 ((int32_t) opening_newline_index) + parser->
start_line
14367 PM_RESCUES_BEGIN = 1,
14374} pm_rescues_type_t;
14381parse_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) {
14382 pm_rescue_node_t *current = NULL;
14384 while (match1(parser, PM_TOKEN_KEYWORD_RESCUE)) {
14385 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14386 parser_lex(parser);
14388 pm_rescue_node_t *rescue = pm_rescue_node_create(parser, &parser->
previous);
14390 switch (parser->
current.type) {
14391 case PM_TOKEN_EQUAL_GREATER: {
14395 parser_lex(parser);
14396 pm_rescue_node_operator_set(rescue, &parser->
previous);
14398 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
14399 reference = parse_target(parser, reference,
false,
false);
14401 pm_rescue_node_reference_set(rescue, reference);
14404 case PM_TOKEN_NEWLINE:
14405 case PM_TOKEN_SEMICOLON:
14406 case PM_TOKEN_KEYWORD_THEN:
14411 if (token_begins_expression_p(parser->
current.type) || match1(parser, PM_TOKEN_USTAR)) {
14416 pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED,
false, PM_ERR_RESCUE_EXPRESSION, (uint16_t) (depth + 1));
14417 pm_rescue_node_exceptions_append(rescue, expression);
14421 if (match3(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_THEN))
break;
14425 if (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
14426 pm_rescue_node_operator_set(rescue, &parser->
previous);
14428 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
14429 reference = parse_target(parser, reference,
false,
false);
14431 pm_rescue_node_reference_set(rescue, reference);
14434 }
while (accept1(parser, PM_TOKEN_COMMA));
14439 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
14440 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
14444 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_RESCUE_TERM);
14448 if (!match3(parser, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_END)) {
14449 pm_accepts_block_stack_push(parser,
true);
14463 pm_statements_node_t *statements = parse_statements(parser, context, (uint16_t) (depth + 1));
14464 if (statements != NULL) pm_rescue_node_statements_set(rescue, statements);
14466 pm_accepts_block_stack_pop(parser);
14467 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14470 if (current == NULL) {
14471 pm_begin_node_rescue_clause_set(parent_node, rescue);
14473 pm_rescue_node_subsequent_set(current, rescue);
14482 if (current != NULL) {
14486 while (clause != NULL) {
14493 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
14494 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14495 opening_newline_index = token_newline_index(parser);
14497 else_keyword = parser->
current;
14498 opening = &else_keyword;
14500 parser_lex(parser);
14501 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14503 pm_statements_node_t *else_statements = NULL;
14504 if (!match2(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_ENSURE)) {
14505 pm_accepts_block_stack_push(parser,
true);
14519 else_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
14520 pm_accepts_block_stack_pop(parser);
14522 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14525 pm_else_node_t *else_clause = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
current);
14526 pm_begin_node_else_clause_set(parent_node, else_clause);
14530 if (current == NULL) pm_parser_err_node(parser, UP(else_clause), PM_ERR_BEGIN_LONELY_ELSE);
14533 if (match1(parser, PM_TOKEN_KEYWORD_ENSURE)) {
14534 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14537 parser_lex(parser);
14538 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14540 pm_statements_node_t *ensure_statements = NULL;
14541 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
14542 pm_accepts_block_stack_push(parser,
true);
14556 ensure_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
14557 pm_accepts_block_stack_pop(parser);
14559 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14562 pm_ensure_node_t *ensure_clause = pm_ensure_node_create(parser, &ensure_keyword, ensure_statements, &parser->
current);
14563 pm_begin_node_ensure_clause_set(parent_node, ensure_clause);
14566 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
14567 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14568 pm_begin_node_end_keyword_set(parent_node, &parser->
current);
14571 pm_begin_node_end_keyword_set(parent_node, &end_keyword);
14579static pm_begin_node_t *
14580parse_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) {
14581 pm_token_t begin_keyword = not_provided(parser);
14582 pm_begin_node_t *node = pm_begin_node_create(parser, &begin_keyword, statements);
14584 parse_rescues(parser, opening_newline_index, opening, node,
type, (uint16_t) (depth + 1));
14593static pm_block_parameters_node_t *
14594parse_block_parameters(
14596 bool allows_trailing_comma,
14598 bool is_lambda_literal,
14599 bool accepts_blocks_in_defaults,
14602 pm_parameters_node_t *parameters = NULL;
14603 if (!match1(parser, PM_TOKEN_SEMICOLON)) {
14604 if (!is_lambda_literal) {
14607 parameters = parse_parameters(
14609 is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
14611 allows_trailing_comma,
14613 accepts_blocks_in_defaults,
14615 is_lambda_literal ? PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_LAMBDA : PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_BLOCK,
14616 (uint16_t) (depth + 1)
14618 if (!is_lambda_literal) {
14619 context_pop(parser);
14623 pm_block_parameters_node_t *block_parameters = pm_block_parameters_node_create(parser, parameters, opening);
14624 if ((opening->
type != PM_TOKEN_NOT_PROVIDED)) {
14625 accept1(parser, PM_TOKEN_NEWLINE);
14627 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
14629 switch (parser->
current.type) {
14630 case PM_TOKEN_CONSTANT:
14631 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14632 parser_lex(parser);
14634 case PM_TOKEN_INSTANCE_VARIABLE:
14635 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
14636 parser_lex(parser);
14638 case PM_TOKEN_GLOBAL_VARIABLE:
14639 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
14640 parser_lex(parser);
14642 case PM_TOKEN_CLASS_VARIABLE:
14643 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
14644 parser_lex(parser);
14647 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_BLOCK_PARAM_LOCAL_VARIABLE);
14651 bool repeated = pm_parser_parameter_name_check(parser, &parser->
previous);
14652 pm_parser_local_add_token(parser, &parser->
previous, 1);
14654 pm_block_local_variable_node_t *local = pm_block_local_variable_node_create(parser, &parser->
previous);
14655 if (repeated) pm_node_flag_set_repeated_parameter(UP(local));
14657 pm_block_parameters_node_append_local(block_parameters, local);
14658 }
while (accept1(parser, PM_TOKEN_COMMA));
14662 return block_parameters;
14670outer_scope_using_numbered_parameters_p(
pm_parser_t *parser) {
14672 if (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND)
return true;
14683static const char *
const pm_numbered_parameter_names[] = {
14684 "_1",
"_2",
"_3",
"_4",
"_5",
"_6",
"_7",
"_8",
"_9"
14698 if (parameters != NULL) {
14700 if (implicit_parameters->
size > 0) {
14701 pm_node_t *node = implicit_parameters->
nodes[0];
14703 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
14704 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_ORDINARY);
14705 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
14706 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_ORDINARY);
14708 assert(
false &&
"unreachable");
14717 if (implicit_parameters->
size == 0) {
14724 uint8_t numbered_parameter = 0;
14725 bool it_parameter =
false;
14727 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
14728 pm_node_t *node = implicit_parameters->
nodes[index];
14730 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
14731 if (it_parameter) {
14732 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_IT);
14733 }
else if (outer_scope_using_numbered_parameters_p(parser)) {
14734 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_OUTER_BLOCK);
14736 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK);
14738 numbered_parameter = MAX(numbered_parameter, (uint8_t) (node->
location.
start[1] -
'0'));
14740 assert(
false &&
"unreachable");
14742 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
14743 if (numbered_parameter > 0) {
14744 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_NUMBERED);
14746 it_parameter =
true;
14751 if (numbered_parameter > 0) {
14755 scope->
parameters |= PM_SCOPE_PARAMETERS_NUMBERED_INNER;
14759 return UP(pm_numbered_parameters_node_create(parser, &location, numbered_parameter));
14762 if (it_parameter) {
14763 return UP(pm_it_parameters_node_create(parser, opening, closing));
14772static pm_block_node_t *
14773parse_block(
pm_parser_t *parser, uint16_t depth) {
14775 accept1(parser, PM_TOKEN_NEWLINE);
14777 pm_accepts_block_stack_push(parser,
true);
14778 pm_parser_scope_push(parser,
false);
14780 pm_block_parameters_node_t *block_parameters = NULL;
14782 if (accept1(parser, PM_TOKEN_PIPE)) {
14784 if (match1(parser, PM_TOKEN_PIPE)) {
14785 block_parameters = pm_block_parameters_node_create(parser, NULL, &block_parameters_opening);
14787 parser_lex(parser);
14789 block_parameters = parse_block_parameters(parser,
true, &block_parameters_opening,
false,
true, (uint16_t) (depth + 1));
14790 accept1(parser, PM_TOKEN_NEWLINE);
14792 expect1(parser, PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM);
14795 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
14798 accept1(parser, PM_TOKEN_NEWLINE);
14799 pm_node_t *statements = NULL;
14801 if (opening.
type == PM_TOKEN_BRACE_LEFT) {
14802 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
14806 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE, &opening);
14808 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
14809 if (!match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE)) {
14810 pm_accepts_block_stack_push(parser,
true);
14812 pm_accepts_block_stack_pop(parser);
14815 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
14816 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
14817 statements = UP(parse_rescues_implicit_begin(parser, 0, NULL, opening.
start, (pm_statements_node_t *) statements, PM_RESCUES_BLOCK, (uint16_t) (depth + 1)));
14821 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END, &opening);
14825 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
14826 pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &opening, &parser->
previous);
14828 pm_parser_scope_pop(parser);
14829 pm_accepts_block_stack_pop(parser);
14831 return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->
previous);
14840parse_arguments_list(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_block,
bool accepts_command_call, uint16_t depth) {
14841 bool found =
false;
14843 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
14847 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
14850 pm_accepts_block_stack_push(parser,
true);
14851 parse_arguments(parser, arguments, accepts_block, PM_TOKEN_PARENTHESIS_RIGHT, (uint16_t) (depth + 1));
14853 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
14859 pm_accepts_block_stack_pop(parser);
14862 }
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)) {
14864 pm_accepts_block_stack_push(parser,
false);
14869 parse_arguments(parser, arguments, accepts_block, PM_TOKEN_EOF, (uint16_t) (depth + 1));
14874 if (parser->
previous.
type == PM_TOKEN_COMMA && !match1(parser, PM_TOKEN_SEMICOLON)) {
14878 pm_accepts_block_stack_pop(parser);
14884 if (accepts_block) {
14885 pm_block_node_t *block = NULL;
14887 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
14889 block = parse_block(parser, (uint16_t) (depth + 1));
14890 pm_arguments_validate_block(parser, arguments, block);
14891 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
14893 block = parse_block(parser, (uint16_t) (depth + 1));
14896 if (block != NULL) {
14898 arguments->
block = UP(block);
14900 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_BLOCK_MULTI);
14902 if (arguments->
block != NULL) {
14904 arguments->
arguments = pm_arguments_node_create(parser);
14906 pm_arguments_node_arguments_append(arguments->
arguments, arguments->
block);
14908 arguments->
block = UP(block);
14921parse_return(
pm_parser_t *parser, pm_node_t *node) {
14922 bool in_sclass =
false;
14924 switch (context_node->
context) {
14969 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
14992 assert(
false &&
"unreachable");
14997 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15006parse_block_exit(
pm_parser_t *parser, pm_node_t *node) {
15008 switch (context_node->
context) {
15083 assert(
false &&
"unreachable");
15093static pm_node_list_t *
15094push_block_exits(
pm_parser_t *parser, pm_node_list_t *current_block_exits) {
15097 return previous_block_exits;
15106flush_block_exits(
pm_parser_t *parser, pm_node_list_t *previous_block_exits) {
15107 pm_node_t *block_exit;
15111 switch (PM_NODE_TYPE(block_exit)) {
15112 case PM_BREAK_NODE:
type =
"break";
break;
15113 case PM_NEXT_NODE:
type =
"next";
break;
15114 case PM_REDO_NODE:
type =
"redo";
break;
15115 default: assert(
false &&
"unreachable");
type =
"";
break;
15118 PM_PARSER_ERR_NODE_FORMAT(parser, block_exit, PM_ERR_INVALID_BLOCK_EXIT,
type);
15129pop_block_exits(
pm_parser_t *parser, pm_node_list_t *previous_block_exits) {
15130 if (match2(parser, PM_TOKEN_KEYWORD_WHILE_MODIFIER, PM_TOKEN_KEYWORD_UNTIL_MODIFIER)) {
15135 }
else if (previous_block_exits != NULL) {
15147 flush_block_exits(parser, previous_block_exits);
15151static inline pm_node_t *
15155 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, error_id, (uint16_t) (depth + 1));
15158 bool predicate_closed = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15160 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
15161 predicate_closed =
true;
15165 if (!predicate_closed) {
15166 pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
15169 context_pop(parser);
15173static inline pm_node_t *
15174parse_conditional(
pm_parser_t *parser,
pm_context_t context,
size_t opening_newline_index,
bool if_after_else, uint16_t depth) {
15175 pm_node_list_t current_block_exits = { 0 };
15176 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
15179 pm_token_t then_keyword = not_provided(parser);
15181 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context, &then_keyword, (uint16_t) (depth + 1));
15182 pm_statements_node_t *statements = NULL;
15184 if (!match3(parser, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
15185 pm_accepts_block_stack_push(parser,
true);
15186 statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15187 pm_accepts_block_stack_pop(parser);
15188 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15191 pm_token_t end_keyword = not_provided(parser);
15192 pm_node_t *parent = NULL;
15196 parent = UP(pm_if_node_create(parser, &keyword, predicate, &then_keyword, statements, NULL, &end_keyword));
15199 parent = UP(pm_unless_node_create(parser, &keyword, predicate, &then_keyword, statements));
15202 assert(
false &&
"unreachable");
15206 pm_node_t *current = parent;
15211 while (match1(parser, PM_TOKEN_KEYWORD_ELSIF)) {
15212 if (parser_end_of_line_p(parser)) {
15213 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
15216 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15218 parser_lex(parser);
15220 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER,
PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1));
15221 pm_accepts_block_stack_push(parser,
true);
15223 pm_statements_node_t *statements = parse_statements(parser,
PM_CONTEXT_ELSIF, (uint16_t) (depth + 1));
15224 pm_accepts_block_stack_pop(parser);
15225 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15227 pm_node_t *elsif = UP(pm_if_node_create(parser, &elsif_keyword, predicate, &then_keyword, statements, NULL, &end_keyword));
15228 ((pm_if_node_t *) current)->subsequent = elsif;
15233 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
15234 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15235 opening_newline_index = token_newline_index(parser);
15237 parser_lex(parser);
15240 pm_accepts_block_stack_push(parser,
true);
15241 pm_statements_node_t *else_statements = parse_statements(parser,
PM_CONTEXT_ELSE, (uint16_t) (depth + 1));
15242 pm_accepts_block_stack_pop(parser);
15244 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15245 parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword,
false,
false);
15246 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE, &keyword);
15248 pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
previous);
15252 ((pm_if_node_t *) current)->subsequent = UP(else_node);
15255 ((pm_unless_node_t *) parent)->else_clause = else_node;
15258 assert(
false &&
"unreachable");
15262 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else,
false);
15263 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM, &keyword);
15269 pm_node_t *current = parent;
15270 bool recursing =
true;
15272 while (recursing) {
15273 switch (PM_NODE_TYPE(current)) {
15275 pm_if_node_end_keyword_loc_set((pm_if_node_t *) current, &parser->
previous);
15276 current = ((pm_if_node_t *) current)->subsequent;
15277 recursing = current != NULL;
15280 pm_else_node_end_keyword_loc_set((pm_else_node_t *) current, &parser->
previous);
15292 pm_unless_node_end_keyword_loc_set((pm_unless_node_t *) parent, &parser->
previous);
15295 assert(
false &&
"unreachable");
15299 pop_block_exits(parser, previous_block_exits);
15300 pm_node_list_free(¤t_block_exits);
15309#define PM_CASE_KEYWORD PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15310 case PM_TOKEN_KEYWORD_ALIAS: case PM_TOKEN_KEYWORD_AND: case PM_TOKEN_KEYWORD_BEGIN: case PM_TOKEN_KEYWORD_BEGIN_UPCASE: \
15311 case PM_TOKEN_KEYWORD_BREAK: case PM_TOKEN_KEYWORD_CASE: case PM_TOKEN_KEYWORD_CLASS: case PM_TOKEN_KEYWORD_DEF: \
15312 case PM_TOKEN_KEYWORD_DEFINED: case PM_TOKEN_KEYWORD_DO: case PM_TOKEN_KEYWORD_DO_LOOP: case PM_TOKEN_KEYWORD_ELSE: \
15313 case PM_TOKEN_KEYWORD_ELSIF: case PM_TOKEN_KEYWORD_END: case PM_TOKEN_KEYWORD_END_UPCASE: case PM_TOKEN_KEYWORD_ENSURE: \
15314 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD_FOR: case PM_TOKEN_KEYWORD_IF: case PM_TOKEN_KEYWORD_IN: \
15315 case PM_TOKEN_KEYWORD_MODULE: case PM_TOKEN_KEYWORD_NEXT: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_NOT: \
15316 case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_KEYWORD_REDO: case PM_TOKEN_KEYWORD_RESCUE: case PM_TOKEN_KEYWORD_RETRY: \
15317 case PM_TOKEN_KEYWORD_RETURN: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_SUPER: case PM_TOKEN_KEYWORD_THEN: \
15318 case PM_TOKEN_KEYWORD_TRUE: case PM_TOKEN_KEYWORD_UNDEF: case PM_TOKEN_KEYWORD_UNLESS: case PM_TOKEN_KEYWORD_UNTIL: \
15319 case PM_TOKEN_KEYWORD_WHEN: case PM_TOKEN_KEYWORD_WHILE: case PM_TOKEN_KEYWORD_YIELD
15325#define PM_CASE_OPERATOR PM_TOKEN_AMPERSAND: case PM_TOKEN_BACKTICK: case PM_TOKEN_BANG_EQUAL: \
15326 case PM_TOKEN_BANG_TILDE: case PM_TOKEN_BANG: case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL: \
15327 case PM_TOKEN_BRACKET_LEFT_RIGHT: case PM_TOKEN_CARET: case PM_TOKEN_EQUAL_EQUAL_EQUAL: case PM_TOKEN_EQUAL_EQUAL: \
15328 case PM_TOKEN_EQUAL_TILDE: case PM_TOKEN_GREATER_EQUAL: case PM_TOKEN_GREATER_GREATER: case PM_TOKEN_GREATER: \
15329 case PM_TOKEN_LESS_EQUAL_GREATER: case PM_TOKEN_LESS_EQUAL: case PM_TOKEN_LESS_LESS: case PM_TOKEN_LESS: \
15330 case PM_TOKEN_MINUS: case PM_TOKEN_PERCENT: case PM_TOKEN_PIPE: case PM_TOKEN_PLUS: case PM_TOKEN_SLASH: \
15331 case PM_TOKEN_STAR_STAR: case PM_TOKEN_STAR: case PM_TOKEN_TILDE: case PM_TOKEN_UAMPERSAND: case PM_TOKEN_UMINUS: \
15332 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_UPLUS: case PM_TOKEN_USTAR: case PM_TOKEN_USTAR_STAR
15339#define PM_CASE_PRIMITIVE PM_TOKEN_INTEGER: case PM_TOKEN_INTEGER_IMAGINARY: case PM_TOKEN_INTEGER_RATIONAL: \
15340 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: case PM_TOKEN_FLOAT: case PM_TOKEN_FLOAT_IMAGINARY: \
15341 case PM_TOKEN_FLOAT_RATIONAL: case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY: case PM_TOKEN_SYMBOL_BEGIN: \
15342 case PM_TOKEN_REGEXP_BEGIN: case PM_TOKEN_BACKTICK: case PM_TOKEN_PERCENT_LOWER_X: case PM_TOKEN_PERCENT_LOWER_I: \
15343 case PM_TOKEN_PERCENT_LOWER_W: case PM_TOKEN_PERCENT_UPPER_I: case PM_TOKEN_PERCENT_UPPER_W: \
15344 case PM_TOKEN_STRING_BEGIN: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_TRUE: \
15345 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15346 case PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_MINUS_GREATER: case PM_TOKEN_HEREDOC_START: \
15347 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_CHARACTER_LITERAL
15353#define PM_CASE_PARAMETER PM_TOKEN_UAMPERSAND: case PM_TOKEN_AMPERSAND: case PM_TOKEN_UDOT_DOT_DOT: \
15354 case PM_TOKEN_IDENTIFIER: case PM_TOKEN_LABEL: case PM_TOKEN_USTAR: case PM_TOKEN_STAR: case PM_TOKEN_STAR_STAR: \
15355 case PM_TOKEN_USTAR_STAR: case PM_TOKEN_CONSTANT: case PM_TOKEN_INSTANCE_VARIABLE: case PM_TOKEN_GLOBAL_VARIABLE: \
15356 case PM_TOKEN_CLASS_VARIABLE
15362#define PM_CASE_WRITABLE PM_CLASS_VARIABLE_READ_NODE: case PM_CONSTANT_PATH_NODE: \
15363 case PM_CONSTANT_READ_NODE: case PM_GLOBAL_VARIABLE_READ_NODE: case PM_LOCAL_VARIABLE_READ_NODE: \
15364 case PM_INSTANCE_VARIABLE_READ_NODE: case PM_MULTI_TARGET_NODE: case PM_BACK_REFERENCE_READ_NODE: \
15365 case PM_NUMBERED_REFERENCE_READ_NODE: case PM_IT_LOCAL_VARIABLE_READ_NODE
15369PM_STATIC_ASSERT(__LINE__, ((
int) PM_STRING_FLAGS_FORCED_UTF8_ENCODING) == ((
int) PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING),
"Expected the flags to match.");
15375static inline pm_node_flags_t
15376parse_unescaped_encoding(
const pm_parser_t *parser) {
15381 return PM_STRING_FLAGS_FORCED_UTF8_ENCODING;
15387 return PM_STRING_FLAGS_FORCED_BINARY_ENCODING;
15398parse_string_part(
pm_parser_t *parser, uint16_t depth) {
15399 switch (parser->
current.type) {
15406 case PM_TOKEN_STRING_CONTENT: {
15410 pm_node_t *node = UP(pm_string_node_create_current_string(parser, &opening, &parser->
current, &closing));
15411 pm_node_flag_set(node, parse_unescaped_encoding(parser));
15413 parser_lex(parser);
15422 case PM_TOKEN_EMBEXPR_BEGIN: {
15431 lex_state_set(parser, PM_LEX_STATE_BEG);
15432 parser_lex(parser);
15435 pm_statements_node_t *statements = NULL;
15437 if (!match1(parser, PM_TOKEN_EMBEXPR_END)) {
15438 pm_accepts_block_stack_push(parser,
true);
15440 pm_accepts_block_stack_pop(parser);
15444 lex_state_set(parser, state);
15446 expect1(parser, PM_TOKEN_EMBEXPR_END, PM_ERR_EMBEXPR_END);
15452 if (statements != NULL && statements->
body.
size == 1) {
15453 pm_node_flag_unset(statements->
body.
nodes[0], PM_NODE_FLAG_NEWLINE);
15456 return UP(pm_embedded_statements_node_create(parser, &opening, statements, &closing));
15465 case PM_TOKEN_EMBVAR: {
15470 lex_state_set(parser, PM_LEX_STATE_BEG);
15471 parser_lex(parser);
15474 pm_node_t *variable;
15476 switch (parser->
current.type) {
15479 case PM_TOKEN_BACK_REFERENCE:
15480 parser_lex(parser);
15481 variable = UP(pm_back_reference_read_node_create(parser, &parser->
previous));
15485 case PM_TOKEN_NUMBERED_REFERENCE:
15486 parser_lex(parser);
15487 variable = UP(pm_numbered_reference_read_node_create(parser, &parser->
previous));
15491 case PM_TOKEN_GLOBAL_VARIABLE:
15492 parser_lex(parser);
15493 variable = UP(pm_global_variable_read_node_create(parser, &parser->
previous));
15497 case PM_TOKEN_INSTANCE_VARIABLE:
15498 parser_lex(parser);
15499 variable = UP(pm_instance_variable_read_node_create(parser, &parser->
previous));
15503 case PM_TOKEN_CLASS_VARIABLE:
15504 parser_lex(parser);
15505 variable = UP(pm_class_variable_read_node_create(parser, &parser->
previous));
15511 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EMBVAR_INVALID);
15512 variable = UP(pm_missing_node_create(parser, parser->
current.start, parser->
current.end));
15516 return UP(pm_embedded_variable_node_create(parser, &
operator, variable));
15519 parser_lex(parser);
15520 pm_parser_err_previous(parser, PM_ERR_CANNOT_PARSE_STRING_PART);
15530static const uint8_t *
15531parse_operator_symbol_name(
const pm_token_t *name) {
15532 switch (name->
type) {
15533 case PM_TOKEN_TILDE:
15534 case PM_TOKEN_BANG:
15535 if (name->
end[-1] ==
'@')
return name->
end - 1;
15545 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, opening, &parser->
current, &closing);
15547 const uint8_t *end = parse_operator_symbol_name(&parser->
current);
15549 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15550 parser_lex(parser);
15553 pm_node_flag_set(UP(symbol), PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING);
15567 if (lex_mode->
mode != PM_LEX_STRING) {
15568 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15570 switch (parser->
current.type) {
15571 case PM_CASE_OPERATOR:
15572 return parse_operator_symbol(parser, &opening, next_state == PM_LEX_STATE_NONE ? PM_LEX_STATE_ENDFN : next_state);
15573 case PM_TOKEN_IDENTIFIER:
15574 case PM_TOKEN_CONSTANT:
15575 case PM_TOKEN_INSTANCE_VARIABLE:
15576 case PM_TOKEN_METHOD_NAME:
15577 case PM_TOKEN_CLASS_VARIABLE:
15578 case PM_TOKEN_GLOBAL_VARIABLE:
15579 case PM_TOKEN_NUMBERED_REFERENCE:
15580 case PM_TOKEN_BACK_REFERENCE:
15581 case PM_CASE_KEYWORD:
15582 parser_lex(parser);
15585 expect2(parser, PM_TOKEN_IDENTIFIER, PM_TOKEN_METHOD_NAME, PM_ERR_SYMBOL_INVALID);
15590 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &parser->
previous, &closing);
15593 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->
previous, &symbol->
unescaped,
false));
15600 if (match1(parser, PM_TOKEN_STRING_END)) {
15601 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15602 parser_lex(parser);
15606 return UP(pm_symbol_node_create(parser, &opening, &content, &closing));
15610 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
15614 if (part && PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
15615 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15616 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
15618 return UP(pm_string_node_to_symbol_node(parser, (pm_string_node_t *) part, &opening, &parser->
previous));
15621 pm_interpolated_symbol_node_t *symbol = pm_interpolated_symbol_node_create(parser, &opening, NULL, &opening);
15622 if (part) pm_interpolated_symbol_node_append(symbol, part);
15624 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
15625 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
15626 pm_interpolated_symbol_node_append(symbol, part);
15630 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15631 if (match1(parser, PM_TOKEN_EOF)) {
15632 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_INTERPOLATED);
15634 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
15637 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
15644 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
15647 parser_lex(parser);
15658 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
15659 pm_interpolated_symbol_node_t *symbol = pm_interpolated_symbol_node_create(parser, &opening, NULL, &opening);
15662 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &unescaped));
15663 pm_interpolated_symbol_node_append(symbol, part);
15665 part = UP(pm_string_node_create_unescaped(parser, &bounds, &parser->
current, &bounds, &parser->
current_string));
15666 pm_interpolated_symbol_node_append(symbol, part);
15668 if (next_state != PM_LEX_STATE_NONE) {
15669 lex_state_set(parser, next_state);
15672 parser_lex(parser);
15673 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
15675 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
15680 pm_string_shared_init(&unescaped, content.
start, content.
end);
15683 if (next_state != PM_LEX_STATE_NONE) {
15684 lex_state_set(parser, next_state);
15687 if (match1(parser, PM_TOKEN_EOF)) {
15688 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_DYNAMIC);
15690 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
15693 return UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
false)));
15700static inline pm_node_t *
15701parse_undef_argument(
pm_parser_t *parser, uint16_t depth) {
15702 switch (parser->
current.type) {
15703 case PM_CASE_OPERATOR: {
15704 const pm_token_t opening = not_provided(parser);
15705 return parse_operator_symbol(parser, &opening, PM_LEX_STATE_NONE);
15707 case PM_CASE_KEYWORD:
15708 case PM_TOKEN_CONSTANT:
15709 case PM_TOKEN_IDENTIFIER:
15710 case PM_TOKEN_METHOD_NAME: {
15711 parser_lex(parser);
15715 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &parser->
previous, &closing);
15718 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->
previous, &symbol->
unescaped,
false));
15722 case PM_TOKEN_SYMBOL_BEGIN: {
15724 parser_lex(parser);
15726 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
15729 pm_parser_err_current(parser, PM_ERR_UNDEF_ARGUMENT);
15730 return UP(pm_missing_node_create(parser, parser->
current.start, parser->
current.end));
15740static inline pm_node_t *
15741parse_alias_argument(
pm_parser_t *parser,
bool first, uint16_t depth) {
15742 switch (parser->
current.type) {
15743 case PM_CASE_OPERATOR: {
15744 const pm_token_t opening = not_provided(parser);
15745 return parse_operator_symbol(parser, &opening, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
15747 case PM_CASE_KEYWORD:
15748 case PM_TOKEN_CONSTANT:
15749 case PM_TOKEN_IDENTIFIER:
15750 case PM_TOKEN_METHOD_NAME: {
15751 if (first) lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
15752 parser_lex(parser);
15756 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &parser->
previous, &closing);
15759 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->
previous, &symbol->
unescaped,
false));
15763 case PM_TOKEN_SYMBOL_BEGIN: {
15765 parser_lex(parser);
15767 return parse_symbol(parser, &lex_mode, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
15769 case PM_TOKEN_BACK_REFERENCE:
15770 parser_lex(parser);
15771 return UP(pm_back_reference_read_node_create(parser, &parser->
previous));
15772 case PM_TOKEN_NUMBERED_REFERENCE:
15773 parser_lex(parser);
15774 return UP(pm_numbered_reference_read_node_create(parser, &parser->
previous));
15775 case PM_TOKEN_GLOBAL_VARIABLE:
15776 parser_lex(parser);
15777 return UP(pm_global_variable_read_node_create(parser, &parser->
previous));
15779 pm_parser_err_current(parser, PM_ERR_ALIAS_ARGUMENT);
15780 return UP(pm_missing_node_create(parser, parser->
current.start, parser->
current.end));
15794 if (!is_numbered_param && ((depth = pm_parser_local_depth_constant_id(parser, name_id)) != -1)) {
15795 return UP(pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, (uint32_t) depth,
false));
15799 if (!current_scope->
closed && !(current_scope->
parameters & PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED)) {
15800 if (is_numbered_param) {
15805 uint8_t maximum = (uint8_t) (parser->
previous.
start[1] -
'0');
15806 for (uint8_t number = 1; number <= maximum; number++) {
15807 pm_parser_local_add_constant(parser, pm_numbered_parameter_names[number - 1], 2);
15810 if (!match1(parser, PM_TOKEN_EQUAL)) {
15814 pm_node_t *node = UP(pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, 0,
false));
15819 pm_node_t *node = UP(pm_it_local_variable_read_node_create(parser, &parser->
previous));
15834 pm_node_flags_t flags = 0;
15836 if (!match1(parser, PM_TOKEN_PARENTHESIS_LEFT) && (parser->
previous.
end[-1] !=
'!') && (parser->
previous.
end[-1] !=
'?')) {
15837 pm_node_t *node = parse_variable(parser);
15838 if (node != NULL)
return node;
15839 flags |= PM_CALL_NODE_FLAGS_VARIABLE_CALL;
15842 pm_call_node_t *node = pm_call_node_variable_call_create(parser, &parser->
previous);
15843 pm_node_flag_set(UP(node), flags);
15854parse_method_definition_name(
pm_parser_t *parser) {
15855 switch (parser->
current.type) {
15856 case PM_CASE_KEYWORD:
15857 case PM_TOKEN_CONSTANT:
15858 case PM_TOKEN_METHOD_NAME:
15859 parser_lex(parser);
15861 case PM_TOKEN_IDENTIFIER:
15862 pm_refute_numbered_parameter(parser, parser->
current.start, parser->
current.end);
15863 parser_lex(parser);
15865 case PM_CASE_OPERATOR:
15866 lex_state_set(parser, PM_LEX_STATE_ENDFN);
15867 parser_lex(parser);
15876parse_heredoc_dedent_string(
pm_string_t *
string,
size_t common_whitespace) {
15879 pm_string_ensure_owned(
string);
15884 size_t dest_length = pm_string_length(
string);
15885 const uint8_t *source_cursor = (uint8_t *) string->
source;
15886 const uint8_t *source_end = source_cursor + dest_length;
15891 size_t trimmed_whitespace = 0;
15897 while ((source_cursor < source_end) && pm_char_is_inline_whitespace(*source_cursor) && trimmed_whitespace < common_whitespace) {
15898 if (*source_cursor ==
'\t') {
15899 trimmed_whitespace = (trimmed_whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
15900 if (trimmed_whitespace > common_whitespace)
break;
15902 trimmed_whitespace++;
15909 memmove((uint8_t *) string->source, source_cursor, (
size_t) (source_end - source_cursor));
15910 string->length = dest_length;
15917parse_heredoc_dedent(
pm_parser_t *parser, pm_node_list_t *nodes,
size_t common_whitespace) {
15920 bool dedent_next =
true;
15925 size_t write_index = 0;
15932 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE)) {
15933 nodes->
nodes[write_index++] = node;
15934 dedent_next =
false;
15938 pm_string_node_t *string_node = ((pm_string_node_t *) node);
15940 parse_heredoc_dedent_string(&string_node->
unescaped, common_whitespace);
15944 pm_node_destroy(parser, node);
15946 nodes->
nodes[write_index++] = node;
15950 dedent_next =
true;
15953 nodes->
size = write_index;
15960parse_strings_empty_content(
const uint8_t *location) {
15961 return (
pm_token_t) { .type = PM_TOKEN_STRING_CONTENT, .start = location, .end = location };
15967static inline pm_node_t *
15968parse_strings(
pm_parser_t *parser, pm_node_t *current,
bool accepts_label, uint16_t depth) {
15969 assert(parser->
current.type == PM_TOKEN_STRING_BEGIN);
15970 bool concating =
false;
15972 while (match1(parser, PM_TOKEN_STRING_BEGIN)) {
15973 pm_node_t *node = NULL;
15978 assert(lex_mode->
mode == PM_LEX_STRING);
15980 bool label_allowed = lex_mode->
as.string.
label_allowed && accepts_label;
15983 parser_lex(parser);
15985 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
15986 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
15991 pm_string_node_t *
string = pm_string_node_create(parser, &opening, &content, &parser->
previous);
15995 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16000 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &content, &parser->
previous);
16005 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16006 }
else if (!lex_interpolation) {
16012 if (match1(parser, PM_TOKEN_EOF)) {
16014 content = not_provided(parser);
16017 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_EXPECT_STRING_CONTENT);
16032 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16033 pm_node_list_t parts = { 0 };
16035 pm_token_t delimiters = not_provided(parser);
16036 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, &delimiters, &content, &delimiters, &unescaped));
16037 pm_node_list_append(&parts, part);
16040 part = UP(pm_string_node_create_current_string(parser, &delimiters, &parser->
current, &delimiters));
16041 pm_node_list_append(&parts, part);
16042 parser_lex(parser);
16043 }
while (match1(parser, PM_TOKEN_STRING_CONTENT));
16045 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16046 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous));
16048 pm_node_list_free(&parts);
16049 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16050 node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true)));
16051 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16052 }
else if (match1(parser, PM_TOKEN_EOF)) {
16053 pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
16054 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped));
16055 }
else if (accept1(parser, PM_TOKEN_STRING_END)) {
16056 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped));
16061 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped));
16063 }
else if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16070 parser_lex(parser);
16072 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16073 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped));
16074 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16080 if (!accept1(parser, PM_TOKEN_STRING_END)) {
16082 if (location > parser->
start && location[-1] ==
'\n') location--;
16083 pm_parser_err(parser, location, location, PM_ERR_STRING_LITERAL_EOF);
16088 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16089 node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true)));
16090 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16094 pm_node_list_t parts = { 0 };
16095 pm_token_t string_opening = not_provided(parser);
16096 pm_token_t string_closing = not_provided(parser);
16098 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, &string_opening, &parser->
previous, &string_closing, &unescaped));
16099 pm_node_flag_set(part, parse_unescaped_encoding(parser));
16100 pm_node_list_append(&parts, part);
16102 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16103 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16104 pm_node_list_append(&parts, part);
16108 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16109 node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous));
16110 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16111 }
else if (match1(parser, PM_TOKEN_EOF)) {
16112 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16113 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current));
16115 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16116 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous));
16119 pm_node_list_free(&parts);
16125 pm_node_list_t parts = { 0 };
16128 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16129 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16130 pm_node_list_append(&parts, part);
16134 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16135 node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous));
16136 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16137 }
else if (match1(parser, PM_TOKEN_EOF)) {
16138 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16139 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current));
16141 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16142 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous));
16145 pm_node_list_free(&parts);
16148 if (current == NULL) {
16152 if (PM_NODE_TYPE_P(node, PM_SYMBOL_NODE) || PM_NODE_TYPE_P(node, PM_INTERPOLATED_SYMBOL_NODE)) {
16163 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE) && !PM_NODE_TYPE_P(node, PM_INTERPOLATED_STRING_NODE)) {
16164 pm_parser_err_node(parser, node, PM_ERR_STRING_CONCATENATION);
16170 if (!PM_NODE_TYPE_P(current, PM_STRING_NODE) && !PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
16171 pm_parser_err_node(parser, current, PM_ERR_STRING_CONCATENATION);
16177 pm_interpolated_string_node_t *container = pm_interpolated_string_node_create(parser, &bounds, NULL, &bounds);
16178 pm_interpolated_string_node_append(container, current);
16179 current = UP(container);
16182 pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current, node);
16189#define PM_PARSE_PATTERN_SINGLE 0
16190#define PM_PARSE_PATTERN_TOP 1
16191#define PM_PARSE_PATTERN_MULTI 2
16204 if (peek_at(parser, location->
start) ==
'_')
return;
16206 if (pm_constant_id_list_includes(captures, capture)) {
16207 pm_parser_err(parser, location->
start, location->
end, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
16209 pm_constant_id_list_append(captures, capture);
16220 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
16222 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
16223 node = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous));
16229 if (!match2(parser, PM_TOKEN_BRACKET_LEFT, PM_TOKEN_PARENTHESIS_LEFT)) {
16235 pm_node_t *inner = NULL;
16237 if (accept1(parser, PM_TOKEN_BRACKET_LEFT)) {
16239 accept1(parser, PM_TOKEN_NEWLINE);
16241 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
16242 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16243 accept1(parser, PM_TOKEN_NEWLINE);
16244 expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
16249 parser_lex(parser);
16251 accept1(parser, PM_TOKEN_NEWLINE);
16253 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
16254 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
16255 accept1(parser, PM_TOKEN_NEWLINE);
16256 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
16265 return UP(pm_array_pattern_node_constant_create(parser, node, &opening, &closing));
16272 switch (PM_NODE_TYPE(inner)) {
16273 case PM_ARRAY_PATTERN_NODE: {
16274 pm_array_pattern_node_t *pattern_node = (pm_array_pattern_node_t *) inner;
16281 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16282 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16284 return UP(pattern_node);
16289 case PM_FIND_PATTERN_NODE: {
16290 pm_find_pattern_node_t *pattern_node = (pm_find_pattern_node_t *) inner;
16297 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16298 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16300 return UP(pattern_node);
16305 case PM_HASH_PATTERN_NODE: {
16306 pm_hash_pattern_node_t *pattern_node = (pm_hash_pattern_node_t *) inner;
16313 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16314 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16316 return UP(pattern_node);
16328 pm_array_pattern_node_t *pattern_node = pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
16329 pm_array_pattern_node_requireds_append(pattern_node, inner);
16330 return UP(pattern_node);
16336static pm_splat_node_t *
16340 pm_node_t *name = NULL;
16345 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
16347 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &identifier);
16350 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16351 pm_parser_local_add(parser, constant_id, identifier.
start, identifier.
end, 0);
16354 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&identifier));
16355 name = UP(pm_local_variable_target_node_create(
16357 &PM_LOCATION_TOKEN_VALUE(&identifier),
16359 (uint32_t) (depth == -1 ? 0 : depth)
16364 return pm_splat_node_create(parser, &
operator, name);
16372 assert(parser->
current.type == PM_TOKEN_USTAR_STAR);
16373 parser_lex(parser);
16376 pm_node_t *value = NULL;
16378 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
16379 return UP(pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous));
16382 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
16386 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16390 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
16391 value = UP(pm_local_variable_target_node_create(
16393 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
16395 (uint32_t) (depth == -1 ? 0 : depth)
16399 return UP(pm_assoc_splat_node_create(parser, value, &
operator));
16407pm_slice_is_valid_local(
const pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
16408 ptrdiff_t length = end - start;
16409 if (length == 0)
return false;
16412 size_t width = char_is_identifier_start(parser, start, end - start);
16413 if (width == 0)
return false;
16419 if (pm_encoding_utf_8_isupper_char(start, length))
return false;
16424 const uint8_t *cursor = start + width;
16425 while ((width = char_is_identifier(parser, cursor, end - cursor))) cursor += width;
16426 return cursor == end;
16435 const pm_location_t *value_loc = &((pm_symbol_node_t *) key)->value_loc;
16440 if (pm_slice_is_valid_local(parser, value_loc->
start, value_loc->
end)) {
16441 depth = pm_parser_local_depth_constant_id(parser, constant_id);
16443 pm_parser_err(parser, key->base.location.start, key->base.location.end, PM_ERR_PATTERN_HASH_KEY_LOCALS);
16445 if ((value_loc->
end > value_loc->
start) && ((value_loc->
end[-1] ==
'!') || (value_loc->
end[-1] ==
'?'))) {
16446 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);
16451 pm_parser_local_add(parser, constant_id, value_loc->
start, value_loc->
end, 0);
16454 parse_pattern_capture(parser, captures, constant_id, value_loc);
16455 pm_local_variable_target_node_t *target = pm_local_variable_target_node_create(
16459 (uint32_t) (depth == -1 ? 0 : depth)
16462 return UP(pm_implicit_node_create(parser, UP(target)));
16472 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
16479static pm_hash_pattern_node_t *
16481 pm_node_list_t assocs = { 0 };
16483 pm_node_t *rest = NULL;
16485 switch (PM_NODE_TYPE(first_node)) {
16486 case PM_ASSOC_SPLAT_NODE:
16487 case PM_NO_KEYWORDS_PARAMETER_NODE:
16490 case PM_SYMBOL_NODE: {
16491 if (pm_symbol_node_label_p(first_node)) {
16492 parse_pattern_hash_key(parser, &keys, first_node);
16495 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)) {
16498 value = parse_pattern_hash_implicit_value(parser, captures, (pm_symbol_node_t *) first_node);
16502 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
16506 pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, &
operator, value));
16508 pm_node_list_append(&assocs, assoc);
16517 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;
16518 pm_parser_err_node(parser, first_node, diag_id);
16522 pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, &
operator, value));
16524 pm_node_list_append(&assocs, assoc);
16530 while (accept1(parser, PM_TOKEN_COMMA)) {
16532 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)) {
16534 if (rest != NULL) {
16535 pm_parser_err_token(parser, &parser->
current, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
16541 if (match1(parser, PM_TOKEN_USTAR_STAR)) {
16542 pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures);
16544 if (rest == NULL) {
16547 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
16548 pm_node_list_append(&assocs, assoc);
16553 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
16554 key = parse_strings(parser, NULL,
true, (uint16_t) (depth + 1));
16556 if (PM_NODE_TYPE_P(key, PM_INTERPOLATED_SYMBOL_NODE)) {
16557 pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
16558 }
else if (!pm_symbol_node_label_p(key)) {
16559 pm_parser_err_node(parser, key, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
16562 expect1(parser, PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
16563 key = UP(pm_symbol_node_label_create(parser, &parser->
previous));
16566 parse_pattern_hash_key(parser, &keys, key);
16567 pm_node_t *value = NULL;
16569 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)) {
16570 if (PM_NODE_TYPE_P(key, PM_SYMBOL_NODE)) {
16571 value = parse_pattern_hash_implicit_value(parser, captures, (pm_symbol_node_t *) key);
16573 value = UP(pm_missing_node_create(parser, key->location.end, key->location.end));
16576 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
16580 pm_node_t *assoc = UP(pm_assoc_node_create(parser, key, &
operator, value));
16582 if (rest != NULL) {
16583 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
16586 pm_node_list_append(&assocs, assoc);
16590 pm_hash_pattern_node_t *node = pm_hash_pattern_node_node_list_create(parser, &assocs, rest);
16593 pm_static_literals_free(&keys);
16602 switch (parser->
current.type) {
16603 case PM_TOKEN_IDENTIFIER:
16604 case PM_TOKEN_METHOD_NAME: {
16605 parser_lex(parser);
16609 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16613 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
16614 return UP(pm_local_variable_target_node_create(
16616 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
16618 (uint32_t) (depth == -1 ? 0 : depth)
16621 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
16623 parser_lex(parser);
16625 if (accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
16628 return UP(pm_array_pattern_node_empty_create(parser, &opening, &parser->
previous));
16633 pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16635 accept1(parser, PM_TOKEN_NEWLINE);
16636 expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
16639 switch (PM_NODE_TYPE(inner)) {
16640 case PM_ARRAY_PATTERN_NODE: {
16641 pm_array_pattern_node_t *pattern_node = (pm_array_pattern_node_t *) inner;
16646 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16647 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16649 return UP(pattern_node);
16654 case PM_FIND_PATTERN_NODE: {
16655 pm_find_pattern_node_t *pattern_node = (pm_find_pattern_node_t *) inner;
16660 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16661 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16663 return UP(pattern_node);
16672 pm_array_pattern_node_t *node = pm_array_pattern_node_empty_create(parser, &opening, &closing);
16673 pm_array_pattern_node_requireds_append(node, inner);
16676 case PM_TOKEN_BRACE_LEFT: {
16680 pm_hash_pattern_node_t *node;
16682 parser_lex(parser);
16684 if (accept1(parser, PM_TOKEN_BRACE_RIGHT)) {
16687 node = pm_hash_pattern_node_empty_create(parser, &opening, &parser->
previous);
16689 pm_node_t *first_node;
16691 switch (parser->
current.type) {
16692 case PM_TOKEN_LABEL:
16693 parser_lex(parser);
16694 first_node = UP(pm_symbol_node_label_create(parser, &parser->
previous));
16696 case PM_TOKEN_USTAR_STAR:
16697 first_node = parse_pattern_keyword_rest(parser, captures);
16699 case PM_TOKEN_STRING_BEGIN:
16700 first_node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, PM_ERR_PATTERN_HASH_KEY_LABEL, (uint16_t) (depth + 1));
16704 parser_lex(parser);
16711 node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
16713 accept1(parser, PM_TOKEN_NEWLINE);
16714 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE, &opening);
16720 node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16721 node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16727 case PM_TOKEN_UDOT_DOT:
16728 case PM_TOKEN_UDOT_DOT_DOT: {
16730 parser_lex(parser);
16734 switch (parser->
current.type) {
16735 case PM_CASE_PRIMITIVE: {
16736 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
16737 return UP(pm_range_node_create(parser, NULL, &
operator, right));
16740 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
16741 pm_node_t *right = UP(pm_missing_node_create(parser,
operator.start,
operator.end));
16742 return UP(pm_range_node_create(parser, NULL, &
operator, right));
16746 case PM_CASE_PRIMITIVE: {
16747 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, diag_id, (uint16_t) (depth + 1));
16750 if (pm_symbol_node_label_p(node))
return node;
16753 if (PM_NODE_TYPE(node) == PM_CALL_NODE) {
16754 pm_parser_err_node(parser, node, diag_id);
16757 pm_node_unreference(parser, node);
16758 pm_node_destroy(parser, node);
16759 return UP(missing_node);
16763 if (accept2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
16769 switch (parser->
current.type) {
16770 case PM_CASE_PRIMITIVE: {
16771 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
16772 return UP(pm_range_node_create(parser, node, &
operator, right));
16775 return UP(pm_range_node_create(parser, node, &
operator, NULL));
16781 case PM_TOKEN_CARET: {
16782 parser_lex(parser);
16787 switch (parser->
current.type) {
16788 case PM_TOKEN_IDENTIFIER: {
16789 parser_lex(parser);
16790 pm_node_t *variable = UP(parse_variable(parser));
16792 if (variable == NULL) {
16793 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
previous, PM_ERR_NO_LOCAL_VARIABLE);
16794 variable = UP(pm_local_variable_read_node_missing_create(parser, &parser->
previous, 0));
16797 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16799 case PM_TOKEN_INSTANCE_VARIABLE: {
16800 parser_lex(parser);
16801 pm_node_t *variable = UP(pm_instance_variable_read_node_create(parser, &parser->
previous));
16803 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16805 case PM_TOKEN_CLASS_VARIABLE: {
16806 parser_lex(parser);
16807 pm_node_t *variable = UP(pm_class_variable_read_node_create(parser, &parser->
previous));
16809 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16811 case PM_TOKEN_GLOBAL_VARIABLE: {
16812 parser_lex(parser);
16813 pm_node_t *variable = UP(pm_global_variable_read_node_create(parser, &parser->
previous));
16815 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16817 case PM_TOKEN_NUMBERED_REFERENCE: {
16818 parser_lex(parser);
16819 pm_node_t *variable = UP(pm_numbered_reference_read_node_create(parser, &parser->
previous));
16821 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16823 case PM_TOKEN_BACK_REFERENCE: {
16824 parser_lex(parser);
16825 pm_node_t *variable = UP(pm_back_reference_read_node_create(parser, &parser->
previous));
16827 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16829 case PM_TOKEN_PARENTHESIS_LEFT: {
16834 parser_lex(parser);
16836 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN, (uint16_t) (depth + 1));
16839 accept1(parser, PM_TOKEN_NEWLINE);
16840 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &lparen);
16841 return UP(pm_pinned_expression_node_create(parser, expression, &
operator, &lparen, &parser->
previous));
16846 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
16847 pm_node_t *variable = UP(pm_missing_node_create(parser,
operator.start,
operator.end));
16848 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16852 case PM_TOKEN_UCOLON_COLON: {
16854 parser_lex(parser);
16856 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
16857 pm_constant_path_node_t *node = pm_constant_path_node_create(parser, NULL, &delimiter, &parser->
previous);
16859 return parse_pattern_constant_path(parser, captures, UP(node), (uint16_t) (depth + 1));
16861 case PM_TOKEN_CONSTANT: {
16863 parser_lex(parser);
16865 pm_node_t *node = UP(pm_constant_read_node_create(parser, &constant));
16866 return parse_pattern_constant_path(parser, captures, node, (uint16_t) (depth + 1));
16869 pm_parser_err_current(parser, diag_id);
16870 return UP(pm_missing_node_create(parser, parser->
current.start, parser->
current.end));
16875parse_pattern_alternation_error_each(
const pm_node_t *node,
void *data) {
16876 switch (PM_NODE_TYPE(node)) {
16877 case PM_LOCAL_VARIABLE_TARGET_NODE:
16890parse_pattern_alternation_error(
pm_parser_t *parser,
const pm_node_t *node) {
16891 pm_visit_node(node, parse_pattern_alternation_error_each, parser);
16900 pm_node_t *node = first_node;
16901 bool alternation =
false;
16903 while ((node == NULL) || (alternation = accept1(parser, PM_TOKEN_PIPE))) {
16904 if (alternation && !PM_NODE_TYPE_P(node, PM_ALTERNATION_PATTERN_NODE) && captures->
size) {
16905 parse_pattern_alternation_error(parser, node);
16908 switch (parser->
current.type) {
16909 case PM_TOKEN_IDENTIFIER:
16910 case PM_TOKEN_BRACKET_LEFT_ARRAY:
16911 case PM_TOKEN_BRACE_LEFT:
16912 case PM_TOKEN_CARET:
16913 case PM_TOKEN_CONSTANT:
16914 case PM_TOKEN_UCOLON_COLON:
16915 case PM_TOKEN_UDOT_DOT:
16916 case PM_TOKEN_UDOT_DOT_DOT:
16917 case PM_CASE_PRIMITIVE: {
16918 if (!alternation) {
16919 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
16922 pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
16924 if (captures->
size) parse_pattern_alternation_error(parser, right);
16925 node = UP(pm_alternation_pattern_node_create(parser, node, right, &
operator));
16930 case PM_TOKEN_PARENTHESIS_LEFT:
16931 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
16934 parser_lex(parser);
16936 pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
16937 accept1(parser, PM_TOKEN_NEWLINE);
16938 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
16939 pm_node_t *right = UP(pm_parentheses_node_create(parser, &opening, body, &parser->
previous, 0));
16941 if (!alternation) {
16944 if (captures->
size) parse_pattern_alternation_error(parser, right);
16945 node = UP(pm_alternation_pattern_node_create(parser, node, right, &
operator));
16951 pm_parser_err_current(parser, diag_id);
16952 pm_node_t *right = UP(pm_missing_node_create(parser, parser->
current.start, parser->
current.end));
16954 if (!alternation) {
16957 if (captures->
size) parse_pattern_alternation_error(parser, right);
16958 node = UP(pm_alternation_pattern_node_create(parser, node, right, &parser->
previous));
16968 while (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
16970 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_PATTERN_IDENT_AFTER_HROCKET);
16975 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16979 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
16980 pm_local_variable_target_node_t *target = pm_local_variable_target_node_create(
16982 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
16984 (uint32_t) (depth == -1 ? 0 : depth)
16987 node = UP(pm_capture_pattern_node_create(parser, node, target, &
operator));
16998 pm_node_t *node = NULL;
17000 bool leading_rest =
false;
17001 bool trailing_rest =
false;
17003 switch (parser->
current.type) {
17004 case PM_TOKEN_LABEL: {
17005 parser_lex(parser);
17006 pm_node_t *key = UP(pm_symbol_node_label_create(parser, &parser->
previous));
17007 node = UP(parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1)));
17009 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17010 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17015 case PM_TOKEN_USTAR_STAR: {
17016 node = parse_pattern_keyword_rest(parser, captures);
17017 node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17019 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17020 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17025 case PM_TOKEN_STRING_BEGIN: {
17028 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17030 if (pm_symbol_node_label_p(node)) {
17031 node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17033 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17034 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17040 node = parse_pattern_primitives(parser, captures, node, diag_id, (uint16_t) (depth + 1));
17043 case PM_TOKEN_USTAR: {
17044 if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
17045 parser_lex(parser);
17046 node = UP(parse_pattern_rest(parser, captures));
17047 leading_rest =
true;
17053 node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1));
17059 if (pm_symbol_node_label_p(node)) {
17060 return UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17063 if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser, PM_TOKEN_COMMA)) {
17067 pm_node_list_t nodes = { 0 };
17068 pm_node_list_append(&nodes, node);
17071 while (accept1(parser, PM_TOKEN_COMMA)) {
17073 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)) {
17074 node = UP(pm_implicit_rest_node_create(parser, &parser->
previous));
17075 pm_node_list_append(&nodes, node);
17076 trailing_rest =
true;
17080 if (accept1(parser, PM_TOKEN_USTAR)) {
17081 node = UP(parse_pattern_rest(parser, captures));
17086 if (trailing_rest) {
17087 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
17090 trailing_rest =
true;
17092 node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
17095 pm_node_list_append(&nodes, node);
17102 if (leading_rest && PM_NODE_TYPE_P(nodes.
nodes[nodes.
size - 1], PM_SPLAT_NODE)) {
17103 node = UP(pm_find_pattern_node_create(parser, &nodes));
17105 if (nodes.
size == 2) {
17106 pm_parser_err_node(parser, node, PM_ERR_PATTERN_FIND_MISSING_INNER);
17109 node = UP(pm_array_pattern_node_node_list_create(parser, &nodes));
17111 if (leading_rest && trailing_rest) {
17112 pm_parser_err_node(parser, node, PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS);
17117 }
else if (leading_rest) {
17120 node = UP(pm_array_pattern_node_rest_create(parser, node));
17132parse_negative_numeric(pm_node_t *node) {
17133 switch (PM_NODE_TYPE(node)) {
17134 case PM_INTEGER_NODE: {
17135 pm_integer_node_t *cast = (pm_integer_node_t *) node;
17140 case PM_FLOAT_NODE: {
17141 pm_float_node_t *cast = (pm_float_node_t *) node;
17146 case PM_RATIONAL_NODE: {
17147 pm_rational_node_t *cast = (pm_rational_node_t *) node;
17152 case PM_IMAGINARY_NODE:
17154 parse_negative_numeric(((pm_imaginary_node_t *) node)->numeric);
17157 assert(
false &&
"unreachable");
17170 case PM_ERR_HASH_KEY: {
17174 case PM_ERR_HASH_VALUE:
17175 case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: {
17179 case PM_ERR_UNARY_RECEIVER: {
17184 case PM_ERR_UNARY_DISALLOWED:
17185 case PM_ERR_EXPECT_ARGUMENT: {
17190 pm_parser_err_previous(parser, diag_id);
17199parse_retry(
pm_parser_t *parser,
const pm_node_t *node) {
17200#define CONTEXT_NONE 0
17201#define CONTEXT_THROUGH_ENSURE 1
17202#define CONTEXT_THROUGH_ELSE 2
17205 int context = CONTEXT_NONE;
17207 while (context_node != NULL) {
17208 switch (context_node->
context) {
17229 if (context == CONTEXT_NONE) {
17230 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_WITHOUT_RESCUE);
17231 }
else if (context == CONTEXT_THROUGH_ENSURE) {
17232 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ENSURE);
17233 }
else if (context == CONTEXT_THROUGH_ELSE) {
17234 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ELSE);
17246 context = CONTEXT_THROUGH_ELSE;
17257 context = CONTEXT_THROUGH_ENSURE;
17261 assert(
false &&
"unreachable");
17292 context_node = context_node->
prev;
17296#undef CONTEXT_ENSURE
17304parse_yield(
pm_parser_t *parser,
const pm_node_t *node) {
17307 while (context_node != NULL) {
17308 switch (context_node->
context) {
17333 pm_parser_err_node(parser, node, PM_ERR_INVALID_YIELD);
17337 assert(
false &&
"unreachable");
17379 context_node = context_node->
prev;
17411parse_regular_expression_error(
const uint8_t *start,
const uint8_t *end,
const char *message,
void *data) {
17415 if (callback_data->
shared) {
17421 PM_PARSER_ERR_FORMAT(callback_data->
parser, location.
start, location.
end, PM_ERR_REGEXP_PARSE_ERROR, message);
17428parse_regular_expression_errors(
pm_parser_t *parser, pm_regular_expression_node_t *node) {
17434 .shared = unescaped->
type == PM_STRING_SHARED
17437 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);
17443static inline pm_node_t *
17444parse_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) {
17445 switch (parser->
current.type) {
17446 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
17447 parser_lex(parser);
17449 pm_array_node_t *array = pm_array_node_create(parser, &parser->
previous);
17450 pm_accepts_block_stack_push(parser,
true);
17451 bool parsed_bare_hash =
false;
17453 while (!match2(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_EOF)) {
17454 bool accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
17458 if (accepted_newline && match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17464 if (accept1(parser, PM_TOKEN_COMMA)) {
17467 if (accepted_newline) {
17468 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
17484 if (match1(parser, PM_TOKEN_BRACKET_RIGHT))
break;
17486 pm_node_t *element;
17488 if (accept1(parser, PM_TOKEN_USTAR)) {
17490 pm_node_t *expression = NULL;
17492 if (match3(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_EOF)) {
17493 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
17495 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
17498 element = UP(pm_splat_node_create(parser, &
operator, expression));
17499 }
else if (match2(parser, PM_TOKEN_LABEL, PM_TOKEN_USTAR_STAR)) {
17500 if (parsed_bare_hash) {
17501 pm_parser_err_current(parser, PM_ERR_EXPRESSION_BARE_HASH);
17504 element = UP(pm_keyword_hash_node_create(parser));
17507 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)) {
17508 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
17511 pm_static_literals_free(&hash_keys);
17512 parsed_bare_hash =
true;
17514 element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_ARRAY_EXPRESSION, (uint16_t) (depth + 1));
17516 if (pm_symbol_node_label_p(element) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
17517 if (parsed_bare_hash) {
17518 pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
17521 pm_keyword_hash_node_t *hash = pm_keyword_hash_node_create(parser);
17523 pm_hash_key_static_literals_add(parser, &hash_keys, element);
17526 if (parser->
previous.
type == PM_TOKEN_EQUAL_GREATER) {
17529 operator = not_provided(parser);
17532 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
17533 pm_node_t *assoc = UP(pm_assoc_node_create(parser, element, &
operator, value));
17534 pm_keyword_hash_node_elements_append(hash, assoc);
17536 element = UP(hash);
17537 if (accept1(parser, PM_TOKEN_COMMA) && !match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17538 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
17541 pm_static_literals_free(&hash_keys);
17542 parsed_bare_hash =
true;
17546 pm_array_node_elements_append(array, element);
17547 if (PM_NODE_TYPE_P(element, PM_MISSING_NODE))
break;
17550 accept1(parser, PM_TOKEN_NEWLINE);
17552 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17558 pm_array_node_close_set(array, &parser->
previous);
17559 pm_accepts_block_stack_pop(parser);
17563 case PM_TOKEN_PARENTHESIS_LEFT:
17564 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
17566 pm_node_flags_t flags = 0;
17568 pm_node_list_t current_block_exits = { 0 };
17569 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
17571 parser_lex(parser);
17573 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
17574 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
17575 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
17582 if (match2(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_EOF)) {
17583 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
17585 pop_block_exits(parser, previous_block_exits);
17586 pm_node_list_free(¤t_block_exits);
17588 return UP(pm_parentheses_node_create(parser, &opening, NULL, &parser->
previous, flags));
17593 pm_accepts_block_stack_push(parser,
true);
17595 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
17596 context_pop(parser);
17601 bool terminator_found =
false;
17603 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
17604 terminator_found =
true;
17605 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
17606 }
else if (accept1(parser, PM_TOKEN_NEWLINE)) {
17607 terminator_found =
true;
17610 if (terminator_found) {
17612 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
17613 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
17614 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
17623 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
17624 if (opening.
type == PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
17625 lex_state_set(parser, PM_LEX_STATE_ENDARG);
17628 parser_lex(parser);
17629 pm_accepts_block_stack_pop(parser);
17631 pop_block_exits(parser, previous_block_exits);
17632 pm_node_list_free(¤t_block_exits);
17634 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) || PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
17638 pm_multi_target_node_t *multi_target;
17640 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) && ((pm_multi_target_node_t *) statement)->lparen_loc.start == NULL) {
17641 multi_target = (pm_multi_target_node_t *) statement;
17643 multi_target = pm_multi_target_node_create(parser);
17644 pm_multi_target_node_targets_append(parser, multi_target, statement);
17647 pm_location_t lparen_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17656 if (match1(parser, PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
17657 result = parse_targets(parser, UP(multi_target), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17658 accept1(parser, PM_TOKEN_NEWLINE);
17660 result = UP(multi_target);
17669 }
else if (binding_power != PM_BINDING_POWER_STATEMENT) {
17672 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
17673 }
else if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
17677 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
17686 pm_statements_node_t *statements = pm_statements_node_create(parser);
17687 pm_statements_node_body_append(parser, statements, statement,
true);
17689 return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->
previous, flags));
17696 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
17698 pm_statements_node_t *statements = pm_statements_node_create(parser);
17699 pm_statements_node_body_append(parser, statements, statement,
true);
17703 if (!terminator_found && !match1(parser, PM_TOKEN_EOF)) {
17709 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
17710 pm_statements_node_body_append(parser, statements, node,
true);
17717 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) parser->
recovering =
false;
17723 if (PM_NODE_TYPE_P(node, PM_MISSING_NODE))
break;
17727 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
17728 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
17729 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
break;
17730 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
17732 }
else if (!match1(parser, PM_TOKEN_EOF)) {
17739 context_pop(parser);
17740 pm_accepts_block_stack_pop(parser);
17741 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
17750 if (PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
17751 pm_multi_target_node_t *multi_target = pm_multi_target_node_create(parser);
17752 pm_multi_target_node_targets_append(parser, multi_target, statement);
17754 statement = UP(multi_target);
17758 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE)) {
17760 pm_token_t operator = { .type = PM_TOKEN_EQUAL, .start = offset, .end = offset };
17761 pm_node_t *value = UP(pm_missing_node_create(parser, offset, offset));
17763 statement = UP(pm_multi_write_node_create(parser, (pm_multi_target_node_t *) statement, &
operator, value));
17766 pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
17770 pop_block_exits(parser, previous_block_exits);
17771 pm_node_list_free(¤t_block_exits);
17773 pm_void_statements_check(parser, statements,
true);
17774 return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->
previous, flags));
17776 case PM_TOKEN_BRACE_LEFT: {
17787 pm_accepts_block_stack_push(parser,
true);
17788 parser_lex(parser);
17791 pm_hash_node_t *node = pm_hash_node_create(parser, &opening);
17793 if (!match2(parser, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_EOF)) {
17794 if (current_hash_keys != NULL) {
17795 parse_assocs(parser, current_hash_keys, UP(node), (uint16_t) (depth + 1));
17798 parse_assocs(parser, &hash_keys, UP(node), (uint16_t) (depth + 1));
17799 pm_static_literals_free(&hash_keys);
17802 accept1(parser, PM_TOKEN_NEWLINE);
17805 pm_accepts_block_stack_pop(parser);
17806 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM, &opening);
17807 pm_hash_node_closing_loc_set(node, &parser->
previous);
17811 case PM_TOKEN_CHARACTER_LITERAL: {
17813 pm_node_t *node = UP(pm_string_node_create_current_string(
17816 .type = PM_TOKEN_STRING_BEGIN,
17817 .start = parser->
current.start,
17818 .end = parser->
current.start + 1
17821 .type = PM_TOKEN_STRING_CONTENT,
17822 .start = parser->
current.start + 1,
17828 pm_node_flag_set(node, parse_unescaped_encoding(parser));
17832 parser_lex(parser);
17836 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
17837 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
17842 case PM_TOKEN_CLASS_VARIABLE: {
17843 parser_lex(parser);
17844 pm_node_t *node = UP(pm_class_variable_read_node_create(parser, &parser->
previous));
17846 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
17847 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17852 case PM_TOKEN_CONSTANT: {
17853 parser_lex(parser);
17859 match1(parser, PM_TOKEN_PARENTHESIS_LEFT) ||
17860 (accepts_command_call && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
17861 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
17862 match1(parser, PM_TOKEN_BRACE_LEFT)
17865 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
17866 return UP(pm_call_node_fcall_create(parser, &constant, &arguments));
17869 pm_node_t *node = UP(pm_constant_read_node_create(parser, &parser->
previous));
17871 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
17874 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17879 case PM_TOKEN_UCOLON_COLON: {
17880 parser_lex(parser);
17883 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
17884 pm_node_t *node = UP(pm_constant_path_node_create(parser, NULL, &delimiter, &parser->
previous));
17886 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
17887 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17892 case PM_TOKEN_UDOT_DOT:
17893 case PM_TOKEN_UDOT_DOT_DOT: {
17895 parser_lex(parser);
17897 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));
17903 if (match2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
17904 pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
17907 return UP(pm_range_node_create(parser, NULL, &
operator, right));
17909 case PM_TOKEN_FLOAT:
17910 parser_lex(parser);
17911 return UP(pm_float_node_create(parser, &parser->
previous));
17912 case PM_TOKEN_FLOAT_IMAGINARY:
17913 parser_lex(parser);
17914 return UP(pm_float_node_imaginary_create(parser, &parser->
previous));
17915 case PM_TOKEN_FLOAT_RATIONAL:
17916 parser_lex(parser);
17917 return UP(pm_float_node_rational_create(parser, &parser->
previous));
17918 case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY:
17919 parser_lex(parser);
17920 return UP(pm_float_node_rational_imaginary_create(parser, &parser->
previous));
17921 case PM_TOKEN_NUMBERED_REFERENCE: {
17922 parser_lex(parser);
17923 pm_node_t *node = UP(pm_numbered_reference_read_node_create(parser, &parser->
previous));
17925 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
17926 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17931 case PM_TOKEN_GLOBAL_VARIABLE: {
17932 parser_lex(parser);
17933 pm_node_t *node = UP(pm_global_variable_read_node_create(parser, &parser->
previous));
17935 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
17936 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17941 case PM_TOKEN_BACK_REFERENCE: {
17942 parser_lex(parser);
17943 pm_node_t *node = UP(pm_back_reference_read_node_create(parser, &parser->
previous));
17945 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
17946 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17951 case PM_TOKEN_IDENTIFIER:
17952 case PM_TOKEN_METHOD_NAME: {
17953 parser_lex(parser);
17955 pm_node_t *node = parse_variable_call(parser);
17957 if (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
17962 pm_call_node_t *call = (pm_call_node_t *) node;
17965 if (parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1))) {
17968 pm_node_flag_unset(UP(call), PM_CALL_NODE_FLAGS_VARIABLE_CALL);
17975 const uint8_t *end = pm_arguments_end(&arguments);
17986 (accepts_command_call && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
17987 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
17988 match1(parser, PM_TOKEN_BRACE_LEFT)
17991 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
17992 pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
17994 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
17998 pm_node_unreference(parser, node);
18004 assert(PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE));
18006 if (pm_token_is_numbered_parameter(identifier.
start, identifier.
end)) {
18007 pm_node_unreference(parser, node);
18009 pm_local_variable_read_node_t *cast = (pm_local_variable_read_node_t *) node;
18010 pm_locals_unread(&pm_parser_scope_find(parser, cast->
depth)->locals, cast->
name);
18014 pm_node_destroy(parser, node);
18019 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
18020 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18025 case PM_TOKEN_HEREDOC_START: {
18031 size_t common_whitespace = (size_t) -1;
18034 parser_lex(parser);
18040 if (match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18046 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18047 node = UP(pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->
previous, &
PM_STRING_EMPTY));
18053 }
else if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) == NULL) {
18061 }
else if (PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18066 pm_node_flag_set(part, parse_unescaped_encoding(parser));
18067 pm_string_node_t *cast = (pm_string_node_t *) part;
18069 cast->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
18073 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18074 assert(
sizeof(pm_string_node_t) ==
sizeof(pm_x_string_node_t));
18075 cast->
base.
type = PM_X_STRING_NODE;
18078 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18079 parse_heredoc_dedent_string(&cast->
unescaped, common_whitespace);
18088 pm_node_list_t parts = { 0 };
18089 pm_node_list_append(&parts, part);
18091 while (!match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18092 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
18093 pm_node_list_append(&parts, part);
18099 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18100 pm_interpolated_x_string_node_t *cast = pm_interpolated_xstring_node_create(parser, &opening, &opening);
18101 cast->
parts = parts;
18104 pm_interpolated_xstring_node_closing_set(cast, &parser->
previous);
18109 pm_interpolated_string_node_t *cast = pm_interpolated_string_node_create(parser, &opening, &parts, &opening);
18110 pm_node_list_free(&parts);
18113 pm_interpolated_string_node_closing_set(cast, &parser->
previous);
18121 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18122 pm_node_list_t *nodes;
18123 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18124 nodes = &((pm_interpolated_x_string_node_t *) node)->parts;
18126 nodes = &((pm_interpolated_string_node_t *) node)->parts;
18129 parse_heredoc_dedent(parser, nodes, common_whitespace);
18133 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
18134 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18139 case PM_TOKEN_INSTANCE_VARIABLE: {
18140 parser_lex(parser);
18141 pm_node_t *node = UP(pm_instance_variable_read_node_create(parser, &parser->
previous));
18143 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18144 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18149 case PM_TOKEN_INTEGER: {
18151 parser_lex(parser);
18152 return UP(pm_integer_node_create(parser, base, &parser->
previous));
18154 case PM_TOKEN_INTEGER_IMAGINARY: {
18156 parser_lex(parser);
18157 return UP(pm_integer_node_imaginary_create(parser, base, &parser->
previous));
18159 case PM_TOKEN_INTEGER_RATIONAL: {
18161 parser_lex(parser);
18162 return UP(pm_integer_node_rational_create(parser, base, &parser->
previous));
18164 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: {
18166 parser_lex(parser);
18167 return UP(pm_integer_node_rational_imaginary_create(parser, base, &parser->
previous));
18169 case PM_TOKEN_KEYWORD___ENCODING__:
18170 parser_lex(parser);
18171 return UP(pm_source_encoding_node_create(parser, &parser->
previous));
18172 case PM_TOKEN_KEYWORD___FILE__:
18173 parser_lex(parser);
18174 return UP(pm_source_file_node_create(parser, &parser->
previous));
18175 case PM_TOKEN_KEYWORD___LINE__:
18176 parser_lex(parser);
18177 return UP(pm_source_line_node_create(parser, &parser->
previous));
18178 case PM_TOKEN_KEYWORD_ALIAS: {
18179 if (binding_power != PM_BINDING_POWER_STATEMENT) {
18180 pm_parser_err_current(parser, PM_ERR_STATEMENT_ALIAS);
18183 parser_lex(parser);
18186 pm_node_t *new_name = parse_alias_argument(parser,
true, (uint16_t) (depth + 1));
18187 pm_node_t *old_name = parse_alias_argument(parser,
false, (uint16_t) (depth + 1));
18189 switch (PM_NODE_TYPE(new_name)) {
18190 case PM_BACK_REFERENCE_READ_NODE:
18191 case PM_NUMBERED_REFERENCE_READ_NODE:
18192 case PM_GLOBAL_VARIABLE_READ_NODE: {
18193 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)) {
18194 if (PM_NODE_TYPE_P(old_name, PM_NUMBERED_REFERENCE_READ_NODE)) {
18195 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE);
18198 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18201 return UP(pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name));
18203 case PM_SYMBOL_NODE:
18204 case PM_INTERPOLATED_SYMBOL_NODE: {
18205 if (!PM_NODE_TYPE_P(old_name, PM_SYMBOL_NODE) && !PM_NODE_TYPE_P(old_name, PM_INTERPOLATED_SYMBOL_NODE)) {
18206 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18211 return UP(pm_alias_method_node_create(parser, &keyword, new_name, old_name));
18214 case PM_TOKEN_KEYWORD_CASE: {
18215 size_t opening_newline_index = token_newline_index(parser);
18216 parser_lex(parser);
18219 pm_node_t *predicate = NULL;
18221 pm_node_list_t current_block_exits = { 0 };
18222 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18224 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18225 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18227 }
else if (match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_END)) {
18229 }
else if (!token_begins_expression_p(parser->
current.type)) {
18232 predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CASE_EXPRESSION_AFTER_CASE, (uint16_t) (depth + 1));
18233 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18236 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
18237 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18238 parser_lex(parser);
18240 pop_block_exits(parser, previous_block_exits);
18241 pm_node_list_free(¤t_block_exits);
18243 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18244 return UP(pm_case_node_create(parser, &case_keyword, predicate, &parser->
previous));
18249 pm_token_t end_keyword = not_provided(parser);
18252 if (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18253 pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, &end_keyword);
18259 while (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18260 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18261 parser_lex(parser);
18264 pm_when_node_t *when_node = pm_when_node_create(parser, &when_keyword);
18267 if (accept1(parser, PM_TOKEN_USTAR)) {
18269 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
18271 pm_splat_node_t *splat_node = pm_splat_node_create(parser, &
operator, expression);
18272 pm_when_node_conditions_append(when_node, UP(splat_node));
18274 if (PM_NODE_TYPE_P(expression, PM_MISSING_NODE))
break;
18276 pm_node_t *condition = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_CASE_EXPRESSION_AFTER_WHEN, (uint16_t) (depth + 1));
18277 pm_when_node_conditions_append(when_node, condition);
18281 if (PM_NODE_TYPE_P(condition, PM_MISSING_NODE))
break;
18285 if (PM_NODE_TYPE_P(condition, PM_STRING_NODE)) {
18286 pm_node_flag_set(condition, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
18287 }
else if (PM_NODE_TYPE_P(condition, PM_SOURCE_FILE_NODE)) {
18288 pm_node_flag_set(condition, PM_NODE_FLAG_STATIC_LITERAL);
18291 pm_when_clause_static_literals_add(parser, &literals, condition);
18293 }
while (accept1(parser, PM_TOKEN_COMMA));
18295 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18296 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
18297 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
18300 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_WHEN_DELIMITER);
18301 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
18304 if (!match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18305 pm_statements_node_t *statements = parse_statements(parser,
PM_CONTEXT_CASE_WHEN, (uint16_t) (depth + 1));
18306 if (statements != NULL) {
18307 pm_when_node_statements_set(when_node, statements);
18311 pm_case_node_condition_append(case_node, UP(when_node));
18317 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18320 pm_static_literals_free(&literals);
18321 node = UP(case_node);
18323 pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate, &end_keyword);
18327 if (predicate == NULL) {
18328 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MATCH_MISSING_PREDICATE);
18334 while (match1(parser, PM_TOKEN_KEYWORD_IN)) {
18335 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18340 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
18342 parser_lex(parser);
18347 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));
18350 pm_constant_id_list_free(&captures);
18355 if (accept1(parser, PM_TOKEN_KEYWORD_IF_MODIFIER)) {
18357 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
18358 pattern = UP(pm_if_node_modifier_create(parser, pattern, &keyword, predicate));
18359 }
else if (accept1(parser, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) {
18361 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
18362 pattern = UP(pm_unless_node_modifier_create(parser, pattern, &keyword, predicate));
18369 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18370 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
18373 then_keyword = not_provided(parser);
18376 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_IN_DELIMITER);
18382 pm_statements_node_t *statements;
18383 if (match3(parser, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18391 pm_node_t *condition = UP(pm_in_node_create(parser, pattern, statements, &in_keyword, &then_keyword));
18392 pm_case_match_node_condition_append(case_node, condition);
18398 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18401 node = UP(case_node);
18404 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18405 if (accept1(parser, PM_TOKEN_KEYWORD_ELSE)) {
18407 pm_else_node_t *else_node;
18409 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
18410 else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser,
PM_CONTEXT_ELSE, (uint16_t) (depth + 1)), &parser->
current);
18412 else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->
current);
18415 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
18416 pm_case_node_else_clause_set((pm_case_node_t *) node, else_node);
18418 pm_case_match_node_else_clause_set((pm_case_match_node_t *) node, else_node);
18422 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18423 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM, &case_keyword);
18425 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
18426 pm_case_node_end_keyword_loc_set((pm_case_node_t *) node, &parser->
previous);
18428 pm_case_match_node_end_keyword_loc_set((pm_case_match_node_t *) node, &parser->
previous);
18431 pop_block_exits(parser, previous_block_exits);
18432 pm_node_list_free(¤t_block_exits);
18436 case PM_TOKEN_KEYWORD_BEGIN: {
18437 size_t opening_newline_index = token_newline_index(parser);
18438 parser_lex(parser);
18441 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18443 pm_node_list_t current_block_exits = { 0 };
18444 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18445 pm_statements_node_t *begin_statements = NULL;
18447 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18448 pm_accepts_block_stack_push(parser,
true);
18449 begin_statements = parse_statements(parser,
PM_CONTEXT_BEGIN, (uint16_t) (depth + 1));
18450 pm_accepts_block_stack_pop(parser);
18451 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18454 pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
18455 parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
18456 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM, &begin_keyword);
18459 pm_begin_node_end_keyword_set(begin_node, &parser->
previous);
18461 pop_block_exits(parser, previous_block_exits);
18462 pm_node_list_free(¤t_block_exits);
18464 return UP(begin_node);
18466 case PM_TOKEN_KEYWORD_BEGIN_UPCASE: {
18467 pm_node_list_t current_block_exits = { 0 };
18468 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18470 if (binding_power != PM_BINDING_POWER_STATEMENT) {
18471 pm_parser_err_current(parser, PM_ERR_STATEMENT_PREEXE_BEGIN);
18474 parser_lex(parser);
18477 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_BEGIN_UPCASE_BRACE);
18479 pm_statements_node_t *statements = parse_statements(parser,
PM_CONTEXT_PREEXE, (uint16_t) (depth + 1));
18481 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM, &opening);
18484 pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
18487 flush_block_exits(parser, previous_block_exits);
18488 pm_node_list_free(¤t_block_exits);
18490 return UP(pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous));
18492 case PM_TOKEN_KEYWORD_BREAK:
18493 case PM_TOKEN_KEYWORD_NEXT:
18494 case PM_TOKEN_KEYWORD_RETURN: {
18495 parser_lex(parser);
18501 token_begins_expression_p(parser->
current.type) ||
18502 match2(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)
18504 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].left;
18506 if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
18508 parse_arguments(parser, &arguments,
false, PM_TOKEN_EOF, (uint16_t) (depth + 1));
18511 if (!accepts_command_call && arguments.
arguments != NULL) {
18517 switch (keyword.
type) {
18518 case PM_TOKEN_KEYWORD_BREAK: {
18519 pm_node_t *node = UP(pm_break_node_create(parser, &keyword, arguments.
arguments));
18523 case PM_TOKEN_KEYWORD_NEXT: {
18524 pm_node_t *node = UP(pm_next_node_create(parser, &keyword, arguments.
arguments));
18528 case PM_TOKEN_KEYWORD_RETURN: {
18529 pm_node_t *node = UP(pm_return_node_create(parser, &keyword, arguments.
arguments));
18530 parse_return(parser, node);
18534 assert(
false &&
"unreachable");
18538 case PM_TOKEN_KEYWORD_SUPER: {
18539 parser_lex(parser);
18543 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18548 ((arguments.
block == NULL) || PM_NODE_TYPE_P(arguments.
block, PM_BLOCK_NODE))
18550 return UP(pm_forwarding_super_node_create(parser, &keyword, &arguments));
18553 return UP(pm_super_node_create(parser, &keyword, &arguments));
18555 case PM_TOKEN_KEYWORD_YIELD: {
18556 parser_lex(parser);
18560 parse_arguments_list(parser, &arguments,
false, accepts_command_call, (uint16_t) (depth + 1));
18566 if (arguments.
block != NULL) {
18567 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
18568 pm_node_unreference(parser, arguments.
block);
18569 pm_node_destroy(parser, arguments.
block);
18570 arguments.
block = NULL;
18578 case PM_TOKEN_KEYWORD_CLASS: {
18579 size_t opening_newline_index = token_newline_index(parser);
18580 parser_lex(parser);
18583 pm_do_loop_stack_push(parser,
false);
18585 pm_node_list_t current_block_exits = { 0 };
18586 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18588 if (accept1(parser, PM_TOKEN_LESS_LESS)) {
18590 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));
18592 pm_parser_scope_push(parser,
true);
18593 if (!match2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18597 pm_node_t *statements = NULL;
18598 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18599 pm_accepts_block_stack_push(parser,
true);
18600 statements = UP(parse_statements(parser,
PM_CONTEXT_SCLASS, (uint16_t) (depth + 1)));
18601 pm_accepts_block_stack_pop(parser);
18604 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
18605 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18606 statements = UP(parse_rescues_implicit_begin(parser, opening_newline_index, &class_keyword, class_keyword.
start, (pm_statements_node_t *) statements, PM_RESCUES_SCLASS, (uint16_t) (depth + 1)));
18608 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
18611 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
18616 pm_parser_scope_pop(parser);
18617 pm_do_loop_stack_pop(parser);
18619 flush_block_exits(parser, previous_block_exits);
18620 pm_node_list_free(¤t_block_exits);
18622 return UP(pm_singleton_class_node_create(parser, &locals, &class_keyword, &
operator, expression, statements, &parser->
previous));
18625 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_CLASS_NAME, (uint16_t) (depth + 1));
18627 if (name.
type != PM_TOKEN_CONSTANT) {
18628 pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME);
18632 pm_node_t *superclass;
18634 if (match1(parser, PM_TOKEN_LESS)) {
18635 inheritance_operator = parser->
current;
18636 lex_state_set(parser, PM_LEX_STATE_BEG);
18639 parser_lex(parser);
18641 superclass = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CLASS_SUPERCLASS, (uint16_t) (depth + 1));
18643 inheritance_operator = not_provided(parser);
18647 pm_parser_scope_push(parser,
true);
18649 if (inheritance_operator.
type != PM_TOKEN_NOT_PROVIDED) {
18650 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CLASS_UNEXPECTED_END);
18652 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18654 pm_node_t *statements = NULL;
18656 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18657 pm_accepts_block_stack_push(parser,
true);
18658 statements = UP(parse_statements(parser,
PM_CONTEXT_CLASS, (uint16_t) (depth + 1)));
18659 pm_accepts_block_stack_pop(parser);
18662 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
18663 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18664 statements = UP(parse_rescues_implicit_begin(parser, opening_newline_index, &class_keyword, class_keyword.
start, (pm_statements_node_t *) statements, PM_RESCUES_CLASS, (uint16_t) (depth + 1)));
18666 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
18669 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
18671 if (context_def_p(parser)) {
18672 pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
18678 pm_parser_scope_pop(parser);
18679 pm_do_loop_stack_pop(parser);
18681 if (!PM_NODE_TYPE_P(constant_path, PM_CONSTANT_PATH_NODE) && !(PM_NODE_TYPE_P(constant_path, PM_CONSTANT_READ_NODE))) {
18682 pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
18685 pop_block_exits(parser, previous_block_exits);
18686 pm_node_list_free(¤t_block_exits);
18688 return UP(pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, &inheritance_operator, superclass, statements, &parser->
previous));
18690 case PM_TOKEN_KEYWORD_DEF: {
18691 pm_node_list_t current_block_exits = { 0 };
18692 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18695 size_t opening_newline_index = token_newline_index(parser);
18697 pm_node_t *receiver = NULL;
18705 parser_lex(parser);
18709 bool valid_name =
true;
18711 switch (parser->
current.type) {
18712 case PM_CASE_OPERATOR:
18713 pm_parser_scope_push(parser,
true);
18714 lex_state_set(parser, PM_LEX_STATE_ENDFN);
18715 parser_lex(parser);
18719 case PM_TOKEN_IDENTIFIER: {
18720 parser_lex(parser);
18722 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
18723 receiver = parse_variable_call(parser);
18725 pm_parser_scope_push(parser,
true);
18726 lex_state_set(parser, PM_LEX_STATE_FNAME);
18727 parser_lex(parser);
18730 name = parse_method_definition_name(parser);
18733 pm_parser_scope_push(parser,
true);
18740 case PM_TOKEN_INSTANCE_VARIABLE:
18741 case PM_TOKEN_CLASS_VARIABLE:
18742 case PM_TOKEN_GLOBAL_VARIABLE:
18743 valid_name =
false;
18745 case PM_TOKEN_CONSTANT:
18746 case PM_TOKEN_KEYWORD_NIL:
18747 case PM_TOKEN_KEYWORD_SELF:
18748 case PM_TOKEN_KEYWORD_TRUE:
18749 case PM_TOKEN_KEYWORD_FALSE:
18750 case PM_TOKEN_KEYWORD___FILE__:
18751 case PM_TOKEN_KEYWORD___LINE__:
18752 case PM_TOKEN_KEYWORD___ENCODING__: {
18753 pm_parser_scope_push(parser,
true);
18754 parser_lex(parser);
18758 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
18759 lex_state_set(parser, PM_LEX_STATE_FNAME);
18760 parser_lex(parser);
18763 switch (identifier.
type) {
18764 case PM_TOKEN_CONSTANT:
18765 receiver = UP(pm_constant_read_node_create(parser, &identifier));
18767 case PM_TOKEN_INSTANCE_VARIABLE:
18768 receiver = UP(pm_instance_variable_read_node_create(parser, &identifier));
18770 case PM_TOKEN_CLASS_VARIABLE:
18771 receiver = UP(pm_class_variable_read_node_create(parser, &identifier));
18773 case PM_TOKEN_GLOBAL_VARIABLE:
18774 receiver = UP(pm_global_variable_read_node_create(parser, &identifier));
18776 case PM_TOKEN_KEYWORD_NIL:
18777 receiver = UP(pm_nil_node_create(parser, &identifier));
18779 case PM_TOKEN_KEYWORD_SELF:
18780 receiver = UP(pm_self_node_create(parser, &identifier));
18782 case PM_TOKEN_KEYWORD_TRUE:
18783 receiver = UP(pm_true_node_create(parser, &identifier));
18785 case PM_TOKEN_KEYWORD_FALSE:
18786 receiver = UP(pm_false_node_create(parser, &identifier));
18788 case PM_TOKEN_KEYWORD___FILE__:
18789 receiver = UP(pm_source_file_node_create(parser, &identifier));
18791 case PM_TOKEN_KEYWORD___LINE__:
18792 receiver = UP(pm_source_line_node_create(parser, &identifier));
18794 case PM_TOKEN_KEYWORD___ENCODING__:
18795 receiver = UP(pm_source_encoding_node_create(parser, &identifier));
18801 name = parse_method_definition_name(parser);
18811 case PM_TOKEN_PARENTHESIS_LEFT: {
18816 context_pop(parser);
18817 parser_lex(parser);
18820 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEF_RECEIVER, (uint16_t) (depth + 1));
18822 accept1(parser, PM_TOKEN_NEWLINE);
18823 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
18826 lex_state_set(parser, PM_LEX_STATE_FNAME);
18827 expect2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON, PM_ERR_DEF_RECEIVER_TERM);
18830 receiver = UP(pm_parentheses_node_create(parser, &lparen, expression, &rparen, 0));
18834 pm_parser_scope_push(parser,
true);
18836 name = parse_method_definition_name(parser);
18840 pm_parser_scope_push(parser,
true);
18841 name = parse_method_definition_name(parser);
18847 pm_parameters_node_t *params;
18849 bool accept_endless_def =
true;
18850 switch (parser->
current.type) {
18851 case PM_TOKEN_PARENTHESIS_LEFT: {
18852 parser_lex(parser);
18855 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18858 params = parse_parameters(
18860 PM_BINDING_POWER_DEFINED,
18866 PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
18867 (uint16_t) (depth + 1)
18871 lex_state_set(parser, PM_LEX_STATE_BEG);
18874 context_pop(parser);
18875 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18884 case PM_CASE_PARAMETER: {
18887 if (parser->
current.type == PM_TOKEN_LABEL) {
18888 lex_state_set(parser, parser->
lex_state | PM_LEX_STATE_LABEL);
18891 lparen = not_provided(parser);
18892 rparen = not_provided(parser);
18893 params = parse_parameters(
18895 PM_BINDING_POWER_DEFINED,
18901 PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
18902 (uint16_t) (depth + 1)
18907 accept_endless_def =
false;
18909 context_pop(parser);
18913 lparen = not_provided(parser);
18914 rparen = not_provided(parser);
18917 context_pop(parser);
18922 pm_node_t *statements = NULL;
18926 if (accept1(parser, PM_TOKEN_EQUAL)) {
18927 if (token_is_setter_name(&name)) {
18928 pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
18930 if (!accept_endless_def) {
18931 pm_parser_err_previous(parser, PM_ERR_DEF_ENDLESS_PARAMETERS);
18937 PM_PARSER_ERR_FORMAT(parser, def_keyword.
start, parser->
previous.
end, PM_ERR_UNEXPECTED_PARAMETER_DEFAULT_VALUE,
"endless method definition");
18942 pm_do_loop_stack_push(parser,
false);
18943 statements = UP(pm_statements_node_create(parser));
18945 bool allow_command_call;
18947 allow_command_call = accepts_command_call;
18950 allow_command_call = binding_power == PM_BINDING_POWER_ASSIGNMENT || binding_power < PM_BINDING_POWER_COMPOSITION;
18953 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_DEFINED + 1, allow_command_call,
false, PM_ERR_DEF_ENDLESS, (uint16_t) (depth + 1));
18955 if (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
18959 pm_node_t *value = parse_expression(parser, PM_BINDING_POWER_MATCH + 1,
false,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
18960 context_pop(parser);
18962 statement = UP(pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value));
18965 pm_statements_node_body_append(parser, (pm_statements_node_t *) statements, statement,
false);
18966 pm_do_loop_stack_pop(parser);
18967 context_pop(parser);
18968 end_keyword = not_provided(parser);
18970 equal = not_provided(parser);
18972 if (lparen.
type == PM_TOKEN_NOT_PROVIDED) {
18973 lex_state_set(parser, PM_LEX_STATE_BEG);
18975 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_DEF_PARAMS_TERM);
18977 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18980 pm_accepts_block_stack_push(parser,
true);
18981 pm_do_loop_stack_push(parser,
false);
18983 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18984 pm_accepts_block_stack_push(parser,
true);
18985 statements = UP(parse_statements(parser,
PM_CONTEXT_DEF, (uint16_t) (depth + 1)));
18986 pm_accepts_block_stack_pop(parser);
18989 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
18990 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18991 statements = UP(parse_rescues_implicit_begin(parser, opening_newline_index, &def_keyword, def_keyword.
start, (pm_statements_node_t *) statements, PM_RESCUES_DEF, (uint16_t) (depth + 1)));
18993 parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword,
false,
false);
18996 pm_accepts_block_stack_pop(parser);
18997 pm_do_loop_stack_pop(parser);
18999 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_DEF_TERM, &def_keyword);
19005 pm_parser_scope_pop(parser);
19012 pm_constant_id_t name_id = pm_parser_constant_id_location(parser, name.
start, parse_operator_symbol_name(&name));
19014 flush_block_exits(parser, previous_block_exits);
19015 pm_node_list_free(¤t_block_exits);
19017 return UP(pm_def_node_create(
19033 case PM_TOKEN_KEYWORD_DEFINED: {
19034 parser_lex(parser);
19039 pm_node_t *expression;
19042 bool newline = accept1(parser, PM_TOKEN_NEWLINE);
19044 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19047 if (newline && accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19048 expression = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->
previous, 0));
19049 lparen = not_provided(parser);
19050 rparen = not_provided(parser);
19052 expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19055 rparen = not_provided(parser);
19057 accept1(parser, PM_TOKEN_NEWLINE);
19058 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19063 lparen = not_provided(parser);
19064 rparen = not_provided(parser);
19065 expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19068 context_pop(parser);
19069 return UP(pm_defined_node_create(
19077 case PM_TOKEN_KEYWORD_END_UPCASE: {
19078 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19079 pm_parser_err_current(parser, PM_ERR_STATEMENT_POSTEXE_END);
19082 parser_lex(parser);
19085 if (context_def_p(parser)) {
19086 pm_parser_warn_token(parser, &keyword, PM_WARN_END_IN_METHOD);
19089 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_END_UPCASE_BRACE);
19091 pm_statements_node_t *statements = parse_statements(parser,
PM_CONTEXT_POSTEXE, (uint16_t) (depth + 1));
19093 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM, &opening);
19094 return UP(pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous));
19096 case PM_TOKEN_KEYWORD_FALSE:
19097 parser_lex(parser);
19098 return UP(pm_false_node_create(parser, &parser->
previous));
19099 case PM_TOKEN_KEYWORD_FOR: {
19100 size_t opening_newline_index = token_newline_index(parser);
19101 parser_lex(parser);
19109 if (accept1(parser, PM_TOKEN_USTAR)) {
19111 pm_node_t *name = NULL;
19113 if (token_begins_expression_p(parser->
current.type)) {
19114 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19117 index = UP(pm_splat_node_create(parser, &star_operator, name));
19118 }
else if (token_begins_expression_p(parser->
current.type)) {
19119 index = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
19121 pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX);
19122 index = UP(pm_missing_node_create(parser, for_keyword.
start, for_keyword.
end));
19126 if (match1(parser, PM_TOKEN_COMMA)) {
19127 index = parse_targets(parser, index, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19129 index = parse_target(parser, index,
false,
false);
19132 context_pop(parser);
19133 pm_do_loop_stack_push(parser,
true);
19135 expect1(parser, PM_TOKEN_KEYWORD_IN, PM_ERR_FOR_IN);
19138 pm_node_t *collection = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_FOR_COLLECTION, (uint16_t) (depth + 1));
19139 pm_do_loop_stack_pop(parser);
19142 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19145 do_keyword = not_provided(parser);
19146 if (!match2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE)) {
19151 pm_statements_node_t *statements = NULL;
19152 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19153 statements = parse_statements(parser,
PM_CONTEXT_FOR, (uint16_t) (depth + 1));
19156 parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword,
false,
false);
19157 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM, &for_keyword);
19159 return UP(pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, &do_keyword, &parser->
previous));
19161 case PM_TOKEN_KEYWORD_IF:
19162 if (parser_end_of_line_p(parser)) {
19163 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
19166 size_t opening_newline_index = token_newline_index(parser);
19167 bool if_after_else = parser->
previous.
type == PM_TOKEN_KEYWORD_ELSE;
19168 parser_lex(parser);
19170 return parse_conditional(parser,
PM_CONTEXT_IF, opening_newline_index, if_after_else, (uint16_t) (depth + 1));
19171 case PM_TOKEN_KEYWORD_UNDEF: {
19172 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19173 pm_parser_err_current(parser, PM_ERR_STATEMENT_UNDEF);
19176 parser_lex(parser);
19177 pm_undef_node_t *undef = pm_undef_node_create(parser, &parser->
previous);
19178 pm_node_t *name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19180 if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) {
19181 pm_node_destroy(parser, name);
19183 pm_undef_node_append(undef, name);
19185 while (match1(parser, PM_TOKEN_COMMA)) {
19186 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
19187 parser_lex(parser);
19188 name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19190 if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) {
19191 pm_node_destroy(parser, name);
19195 pm_undef_node_append(undef, name);
19201 case PM_TOKEN_KEYWORD_NOT: {
19202 parser_lex(parser);
19206 pm_node_t *receiver = NULL;
19211 if (!accepts_command_call && !match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19212 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES)) {
19213 pm_parser_err(parser, parser->
previous.
end, parser->
previous.
end + 1, PM_ERR_EXPECT_LPAREN_AFTER_NOT_LPAREN);
19215 accept1(parser, PM_TOKEN_NEWLINE);
19216 pm_parser_err_current(parser, PM_ERR_EXPECT_LPAREN_AFTER_NOT_OTHER);
19219 return UP(pm_missing_node_create(parser, parser->
current.start, parser->
current.end));
19222 accept1(parser, PM_TOKEN_NEWLINE);
19224 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19227 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19228 receiver = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->
previous, 0));
19230 arguments.
opening_loc = PM_LOCATION_TOKEN_VALUE(&lparen);
19231 receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19234 accept1(parser, PM_TOKEN_NEWLINE);
19235 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19240 receiver = parse_expression(parser, PM_BINDING_POWER_NOT,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19243 return UP(pm_call_node_not_create(parser, receiver, &message, &arguments));
19245 case PM_TOKEN_KEYWORD_UNLESS: {
19246 size_t opening_newline_index = token_newline_index(parser);
19247 parser_lex(parser);
19249 return parse_conditional(parser,
PM_CONTEXT_UNLESS, opening_newline_index,
false, (uint16_t) (depth + 1));
19251 case PM_TOKEN_KEYWORD_MODULE: {
19252 pm_node_list_t current_block_exits = { 0 };
19253 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19255 size_t opening_newline_index = token_newline_index(parser);
19256 parser_lex(parser);
19259 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_MODULE_NAME, (uint16_t) (depth + 1));
19264 if (PM_NODE_TYPE_P(constant_path, PM_MISSING_NODE)) {
19265 pop_block_exits(parser, previous_block_exits);
19266 pm_node_list_free(¤t_block_exits);
19269 return UP(pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing));
19272 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
19275 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
19276 constant_path = UP(pm_constant_path_node_create(parser, constant_path, &double_colon, &parser->
previous));
19283 if (name.
type != PM_TOKEN_CONSTANT) {
19284 pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
19287 pm_parser_scope_push(parser,
true);
19288 accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE);
19289 pm_node_t *statements = NULL;
19291 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19292 pm_accepts_block_stack_push(parser,
true);
19293 statements = UP(parse_statements(parser,
PM_CONTEXT_MODULE, (uint16_t) (depth + 1)));
19294 pm_accepts_block_stack_pop(parser);
19297 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
19298 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
19299 statements = UP(parse_rescues_implicit_begin(parser, opening_newline_index, &module_keyword, module_keyword.
start, (pm_statements_node_t *) statements, PM_RESCUES_MODULE, (uint16_t) (depth + 1)));
19301 parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword,
false,
false);
19307 pm_parser_scope_pop(parser);
19308 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM, &module_keyword);
19310 if (context_def_p(parser)) {
19311 pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
19314 pop_block_exits(parser, previous_block_exits);
19315 pm_node_list_free(¤t_block_exits);
19317 return UP(pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->
previous));
19319 case PM_TOKEN_KEYWORD_NIL:
19320 parser_lex(parser);
19321 return UP(pm_nil_node_create(parser, &parser->
previous));
19322 case PM_TOKEN_KEYWORD_REDO: {
19323 parser_lex(parser);
19325 pm_node_t *node = UP(pm_redo_node_create(parser, &parser->
previous));
19330 case PM_TOKEN_KEYWORD_RETRY: {
19331 parser_lex(parser);
19333 pm_node_t *node = UP(pm_retry_node_create(parser, &parser->
previous));
19334 parse_retry(parser, node);
19338 case PM_TOKEN_KEYWORD_SELF:
19339 parser_lex(parser);
19340 return UP(pm_self_node_create(parser, &parser->
previous));
19341 case PM_TOKEN_KEYWORD_TRUE:
19342 parser_lex(parser);
19343 return UP(pm_true_node_create(parser, &parser->
previous));
19344 case PM_TOKEN_KEYWORD_UNTIL: {
19345 size_t opening_newline_index = token_newline_index(parser);
19348 pm_do_loop_stack_push(parser,
true);
19350 parser_lex(parser);
19352 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
19354 pm_do_loop_stack_pop(parser);
19355 context_pop(parser);
19358 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19361 do_keyword = not_provided(parser);
19362 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
19365 pm_statements_node_t *statements = NULL;
19366 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19367 pm_accepts_block_stack_push(parser,
true);
19368 statements = parse_statements(parser,
PM_CONTEXT_UNTIL, (uint16_t) (depth + 1));
19369 pm_accepts_block_stack_pop(parser);
19370 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19373 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19374 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM, &keyword);
19376 return UP(pm_until_node_create(parser, &keyword, &do_keyword, &parser->
previous, predicate, statements, 0));
19378 case PM_TOKEN_KEYWORD_WHILE: {
19379 size_t opening_newline_index = token_newline_index(parser);
19382 pm_do_loop_stack_push(parser,
true);
19384 parser_lex(parser);
19386 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
19388 pm_do_loop_stack_pop(parser);
19389 context_pop(parser);
19392 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19395 do_keyword = not_provided(parser);
19396 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
19399 pm_statements_node_t *statements = NULL;
19400 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19401 pm_accepts_block_stack_push(parser,
true);
19402 statements = parse_statements(parser,
PM_CONTEXT_WHILE, (uint16_t) (depth + 1));
19403 pm_accepts_block_stack_pop(parser);
19404 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19407 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19408 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM, &keyword);
19410 return UP(pm_while_node_create(parser, &keyword, &do_keyword, &parser->
previous, predicate, statements, 0));
19412 case PM_TOKEN_PERCENT_LOWER_I: {
19413 parser_lex(parser);
19415 pm_array_node_t *array = pm_array_node_create(parser, &opening);
19416 pm_node_t *current = NULL;
19418 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19419 accept1(parser, PM_TOKEN_WORDS_SEP);
19420 if (match1(parser, PM_TOKEN_STRING_END))
break;
19424 while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19429 if (current == NULL) {
19430 current = UP(pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing));
19431 parser_lex(parser);
19432 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
19433 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, &opening, &parser->
current, &closing));
19434 parser_lex(parser);
19435 pm_interpolated_symbol_node_append((pm_interpolated_symbol_node_t *) current,
string);
19436 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19437 pm_symbol_node_t *cast = (pm_symbol_node_t *) current;
19441 pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &cast->
unescaped));
19442 pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, &opening, &parser->
previous, &closing));
19443 parser_lex(parser);
19445 pm_interpolated_symbol_node_t *interpolated = pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
19446 pm_interpolated_symbol_node_append(interpolated, first_string);
19447 pm_interpolated_symbol_node_append(interpolated, second_string);
19450 current = UP(interpolated);
19452 assert(
false &&
"unreachable");
19457 pm_array_node_elements_append(array, current);
19460 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_LOWER_ELEMENT);
19465 if (match1(parser, PM_TOKEN_EOF)) {
19466 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
19469 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_LOWER_TERM);
19471 pm_array_node_close_set(array, &closing);
19475 case PM_TOKEN_PERCENT_UPPER_I: {
19476 parser_lex(parser);
19478 pm_array_node_t *array = pm_array_node_create(parser, &opening);
19482 pm_node_t *current = NULL;
19484 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19485 switch (parser->
current.type) {
19486 case PM_TOKEN_WORDS_SEP: {
19487 if (current == NULL) {
19493 pm_array_node_elements_append(array, current);
19497 parser_lex(parser);
19500 case PM_TOKEN_STRING_CONTENT: {
19504 if (current == NULL) {
19508 current = UP(pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing));
19509 parser_lex(parser);
19510 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
19514 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, &opening, &parser->
current, &closing));
19515 parser_lex(parser);
19517 pm_interpolated_symbol_node_append((pm_interpolated_symbol_node_t *) current,
string);
19518 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19522 pm_symbol_node_t *cast = (pm_symbol_node_t *) current;
19526 pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &cast->
unescaped));
19527 pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, &opening, &parser->
previous, &closing));
19528 parser_lex(parser);
19530 pm_interpolated_symbol_node_t *interpolated = pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
19531 pm_interpolated_symbol_node_append(interpolated, first_string);
19532 pm_interpolated_symbol_node_append(interpolated, second_string);
19535 current = UP(interpolated);
19537 assert(
false &&
"unreachable");
19542 case PM_TOKEN_EMBVAR: {
19543 bool start_location_set =
false;
19544 if (current == NULL) {
19550 current = UP(pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing));
19551 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19557 pm_interpolated_symbol_node_t *interpolated = pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
19559 current = UP(pm_symbol_node_to_string_node(parser, (pm_symbol_node_t *) current));
19560 pm_interpolated_symbol_node_append(interpolated, current);
19562 start_location_set =
true;
19563 current = UP(interpolated);
19569 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19570 pm_interpolated_symbol_node_append((pm_interpolated_symbol_node_t *) current, part);
19571 if (!start_location_set) {
19576 case PM_TOKEN_EMBEXPR_BEGIN: {
19577 bool start_location_set =
false;
19578 if (current == NULL) {
19584 current = UP(pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing));
19585 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19592 pm_interpolated_symbol_node_t *interpolated = pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
19594 current = UP(pm_symbol_node_to_string_node(parser, (pm_symbol_node_t *) current));
19595 pm_interpolated_symbol_node_append(interpolated, current);
19597 start_location_set =
true;
19598 current = UP(interpolated);
19599 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
19603 assert(
false &&
"unreachable");
19606 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19607 pm_interpolated_symbol_node_append((pm_interpolated_symbol_node_t *) current, part);
19608 if (!start_location_set) {
19614 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_UPPER_ELEMENT);
19615 parser_lex(parser);
19622 pm_array_node_elements_append(array, current);
19626 if (match1(parser, PM_TOKEN_EOF)) {
19627 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_UPPER_TERM);
19630 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_UPPER_TERM);
19632 pm_array_node_close_set(array, &closing);
19636 case PM_TOKEN_PERCENT_LOWER_W: {
19637 parser_lex(parser);
19639 pm_array_node_t *array = pm_array_node_create(parser, &opening);
19640 pm_node_t *current = NULL;
19642 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19643 accept1(parser, PM_TOKEN_WORDS_SEP);
19644 if (match1(parser, PM_TOKEN_STRING_END))
break;
19648 while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19652 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, &opening, &parser->
current, &closing));
19655 if (current == NULL) {
19657 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
19658 pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current,
string);
19659 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19660 pm_interpolated_string_node_t *interpolated = pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
19661 pm_interpolated_string_node_append(interpolated, current);
19662 pm_interpolated_string_node_append(interpolated,
string);
19663 current = UP(interpolated);
19665 assert(
false &&
"unreachable");
19667 parser_lex(parser);
19671 pm_array_node_elements_append(array, current);
19674 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_LOWER_ELEMENT);
19679 if (match1(parser, PM_TOKEN_EOF)) {
19680 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_LOWER_TERM);
19683 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_LOWER_TERM);
19686 pm_array_node_close_set(array, &closing);
19689 case PM_TOKEN_PERCENT_UPPER_W: {
19690 parser_lex(parser);
19692 pm_array_node_t *array = pm_array_node_create(parser, &opening);
19696 pm_node_t *current = NULL;
19698 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19699 switch (parser->
current.type) {
19700 case PM_TOKEN_WORDS_SEP: {
19705 if (current == NULL) {
19712 pm_array_node_elements_append(array, current);
19716 parser_lex(parser);
19719 case PM_TOKEN_STRING_CONTENT: {
19723 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, &opening, &parser->
current, &closing));
19724 pm_node_flag_set(
string, parse_unescaped_encoding(parser));
19725 parser_lex(parser);
19727 if (current == NULL) {
19733 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
19737 pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current,
string);
19738 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19743 pm_interpolated_string_node_t *interpolated = pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
19744 pm_interpolated_string_node_append(interpolated, current);
19745 pm_interpolated_string_node_append(interpolated,
string);
19746 current = UP(interpolated);
19748 assert(
false &&
"unreachable");
19753 case PM_TOKEN_EMBVAR: {
19754 if (current == NULL) {
19761 current = UP(pm_interpolated_string_node_create(parser, &opening, NULL, &closing));
19762 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19769 pm_interpolated_string_node_t *interpolated = pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
19770 pm_interpolated_string_node_append(interpolated, current);
19771 current = UP(interpolated);
19778 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19779 pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current, part);
19782 case PM_TOKEN_EMBEXPR_BEGIN: {
19783 if (current == NULL) {
19790 current = UP(pm_interpolated_string_node_create(parser, &opening, NULL, &closing));
19791 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19798 pm_interpolated_string_node_t *interpolated = pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
19799 pm_interpolated_string_node_append(interpolated, current);
19800 current = UP(interpolated);
19801 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
19806 assert(
false &&
"unreachable");
19809 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19810 pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current, part);
19814 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_UPPER_ELEMENT);
19815 parser_lex(parser);
19822 pm_array_node_elements_append(array, current);
19826 if (match1(parser, PM_TOKEN_EOF)) {
19827 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_UPPER_TERM);
19830 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_UPPER_TERM);
19833 pm_array_node_close_set(array, &closing);
19836 case PM_TOKEN_REGEXP_BEGIN: {
19838 parser_lex(parser);
19840 if (match1(parser, PM_TOKEN_REGEXP_END)) {
19845 .type = PM_TOKEN_STRING_CONTENT,
19850 parser_lex(parser);
19852 pm_node_t *node = UP(pm_regular_expression_node_create(parser, &opening, &content, &parser->
previous));
19853 pm_node_flag_set(node, PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING);
19858 pm_interpolated_regular_expression_node_t *interpolated;
19860 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19868 parser_lex(parser);
19873 if (accept1(parser, PM_TOKEN_REGEXP_END)) {
19874 pm_regular_expression_node_t *node = (pm_regular_expression_node_t *) pm_regular_expression_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped);
19880 if (!match1(parser, PM_TOKEN_EQUAL_TILDE)) {
19881 parse_regular_expression_errors(parser, node);
19884 pm_node_flag_set(UP(node), parse_and_validate_regular_expression_encoding(parser, &unescaped, ascii_only, FL(node)));
19890 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
19894 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, &opening, &parser->
previous, &closing, &unescaped));
19900 pm_node_flag_set(part, PM_STRING_FLAGS_FORCED_BINARY_ENCODING);
19903 pm_interpolated_regular_expression_node_append(interpolated, part);
19908 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
19914 while (!match2(parser, PM_TOKEN_REGEXP_END, PM_TOKEN_EOF)) {
19915 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
19916 pm_interpolated_regular_expression_node_append(interpolated, part);
19921 if (match1(parser, PM_TOKEN_EOF)) {
19922 pm_parser_err_token(parser, &opening, PM_ERR_REGEXP_TERM);
19925 expect1(parser, PM_TOKEN_REGEXP_END, PM_ERR_REGEXP_TERM);
19928 pm_interpolated_regular_expression_node_closing_set(parser, interpolated, &closing);
19929 return UP(interpolated);
19931 case PM_TOKEN_BACKTICK:
19932 case PM_TOKEN_PERCENT_LOWER_X: {
19933 parser_lex(parser);
19940 if (match1(parser, PM_TOKEN_STRING_END)) {
19945 .type = PM_TOKEN_STRING_CONTENT,
19950 parser_lex(parser);
19951 return UP(pm_xstring_node_create(parser, &opening, &content, &parser->
previous));
19954 pm_interpolated_x_string_node_t *node;
19956 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19963 parser_lex(parser);
19965 if (match1(parser, PM_TOKEN_STRING_END)) {
19966 pm_node_t *node = UP(pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped));
19967 pm_node_flag_set(node, parse_unescaped_encoding(parser));
19968 parser_lex(parser);
19974 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
19979 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, &opening, &parser->
previous, &closing, &unescaped));
19980 pm_node_flag_set(part, parse_unescaped_encoding(parser));
19982 pm_interpolated_xstring_node_append(node, part);
19987 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
19991 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19992 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
19993 pm_interpolated_xstring_node_append(node, part);
19998 if (match1(parser, PM_TOKEN_EOF)) {
19999 pm_parser_err_token(parser, &opening, PM_ERR_XSTRING_TERM);
20002 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_XSTRING_TERM);
20004 pm_interpolated_xstring_node_closing_set(node, &closing);
20008 case PM_TOKEN_USTAR: {
20009 parser_lex(parser);
20014 if (binding_power != PM_BINDING_POWER_STATEMENT) {
20015 pm_parser_err_prefix(parser, diag_id);
20020 pm_node_t *name = NULL;
20022 if (token_begins_expression_p(parser->
current.type)) {
20023 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
20026 pm_node_t *splat = UP(pm_splat_node_create(parser, &
operator, name));
20028 if (match1(parser, PM_TOKEN_COMMA)) {
20029 return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
20031 return parse_target_validate(parser, splat,
true);
20034 case PM_TOKEN_BANG: {
20035 if (binding_power > PM_BINDING_POWER_UNARY) {
20036 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20039 parser_lex(parser);
20042 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));
20043 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"!");
20045 pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
20048 case PM_TOKEN_TILDE: {
20049 if (binding_power > PM_BINDING_POWER_UNARY) {
20050 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20052 parser_lex(parser);
20055 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20056 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"~");
20060 case PM_TOKEN_UMINUS: {
20061 if (binding_power > PM_BINDING_POWER_UNARY) {
20062 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20064 parser_lex(parser);
20067 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20068 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"-@");
20072 case PM_TOKEN_UMINUS_NUM: {
20073 parser_lex(parser);
20076 pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20078 if (accept1(parser, PM_TOKEN_STAR_STAR)) {
20080 pm_node_t *exponent = parse_expression(parser, pm_binding_powers[exponent_operator.
type].right,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
20081 node = UP(pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0));
20082 node = UP(pm_call_node_unary_create(parser, &
operator, node,
"-@"));
20084 switch (PM_NODE_TYPE(node)) {
20085 case PM_INTEGER_NODE:
20086 case PM_FLOAT_NODE:
20087 case PM_RATIONAL_NODE:
20088 case PM_IMAGINARY_NODE:
20089 parse_negative_numeric(node);
20092 node = UP(pm_call_node_unary_create(parser, &
operator, node,
"-@"));
20099 case PM_TOKEN_MINUS_GREATER: {
20103 size_t opening_newline_index = token_newline_index(parser);
20104 pm_accepts_block_stack_push(parser,
true);
20105 parser_lex(parser);
20108 pm_parser_scope_push(parser,
false);
20110 pm_block_parameters_node_t *block_parameters;
20112 switch (parser->
current.type) {
20113 case PM_TOKEN_PARENTHESIS_LEFT: {
20115 parser_lex(parser);
20117 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
20118 block_parameters = pm_block_parameters_node_create(parser, NULL, &opening);
20120 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
true, (uint16_t) (depth + 1));
20123 accept1(parser, PM_TOKEN_NEWLINE);
20124 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
20126 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
20129 case PM_CASE_PARAMETER: {
20130 pm_accepts_block_stack_push(parser,
false);
20132 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
false, (uint16_t) (depth + 1));
20133 pm_accepts_block_stack_pop(parser);
20137 block_parameters = NULL;
20143 pm_node_t *body = NULL;
20146 if (accept1(parser, PM_TOKEN_LAMBDA_BEGIN)) {
20149 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
20153 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20154 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE, &opening);
20156 expect1(parser, PM_TOKEN_KEYWORD_DO, PM_ERR_LAMBDA_OPEN);
20159 if (!match3(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20160 pm_accepts_block_stack_push(parser,
true);
20162 pm_accepts_block_stack_pop(parser);
20165 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20166 assert(body == NULL || PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE));
20167 body = UP(parse_rescues_implicit_begin(parser, opening_newline_index, &
operator, opening.
start, (pm_statements_node_t *) body, PM_RESCUES_LAMBDA, (uint16_t) (depth + 1)));
20169 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20172 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END, &
operator);
20176 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
20177 pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &
operator, &parser->
previous);
20179 pm_parser_scope_pop(parser);
20180 pm_accepts_block_stack_pop(parser);
20182 return UP(pm_lambda_node_create(parser, &locals, &
operator, &opening, &parser->
previous, parameters, body));
20184 case PM_TOKEN_UPLUS: {
20185 if (binding_power > PM_BINDING_POWER_UNARY) {
20186 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20188 parser_lex(parser);
20191 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20192 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"+@");
20196 case PM_TOKEN_STRING_BEGIN:
20197 return parse_strings(parser, NULL, accepts_label, (uint16_t) (depth + 1));
20198 case PM_TOKEN_SYMBOL_BEGIN: {
20200 parser_lex(parser);
20202 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_END, (uint16_t) (depth + 1));
20213 if (diag_id != PM_ERR_CANNOT_PARSE_EXPRESSION) {
20214 pm_parser_err_prefix(parser, diag_id);
20220 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT,
pm_token_type_human(parser->
current.type), context_human(recoverable));
20221 }
else if (diag_id == PM_ERR_CANNOT_PARSE_EXPRESSION) {
20227 pm_parser_err_prefix(parser, diag_id);
20245parse_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) {
20246 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));
20250 if (match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
20254 parser_lex(parser);
20256 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MATCH + 1,
false,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
20257 context_pop(parser);
20259 return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
20270parse_assignment_value_local(
pm_parser_t *parser,
const pm_node_t *node) {
20271 switch (PM_NODE_TYPE(node)) {
20272 case PM_BEGIN_NODE: {
20273 const pm_begin_node_t *cast = (
const pm_begin_node_t *) node;
20274 if (cast->
statements != NULL) parse_assignment_value_local(parser, (
const pm_node_t *) cast->
statements);
20277 case PM_LOCAL_VARIABLE_WRITE_NODE: {
20278 const pm_local_variable_write_node_t *cast = (
const pm_local_variable_write_node_t *) node;
20279 pm_locals_read(&pm_parser_scope_find(parser, cast->
depth)->locals, cast->
name);
20282 case PM_PARENTHESES_NODE: {
20283 const pm_parentheses_node_t *cast = (
const pm_parentheses_node_t *) node;
20284 if (cast->
body != NULL) parse_assignment_value_local(parser, cast->
body);
20287 case PM_STATEMENTS_NODE: {
20288 const pm_statements_node_t *cast = (
const pm_statements_node_t *) node;
20289 const pm_node_t *statement;
20292 parse_assignment_value_local(parser, statement);
20314parse_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) {
20315 bool permitted =
true;
20316 if (previous_binding_power != PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_USTAR)) permitted =
false;
20318 pm_node_t *value = parse_starred_expression(parser, binding_power, previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? accepts_command_call : previous_binding_power < PM_BINDING_POWER_MODIFIER, diag_id, (uint16_t) (depth + 1));
20319 if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE);
20321 parse_assignment_value_local(parser, value);
20322 bool single_value =
true;
20324 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && (PM_NODE_TYPE_P(value, PM_SPLAT_NODE) || match1(parser, PM_TOKEN_COMMA))) {
20325 single_value =
false;
20328 pm_array_node_t *array = pm_array_node_create(parser, &opening);
20330 pm_array_node_elements_append(array, value);
20333 while (accept1(parser, PM_TOKEN_COMMA)) {
20334 pm_node_t *element = parse_starred_expression(parser, binding_power,
false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1));
20336 pm_array_node_elements_append(array, element);
20337 if (PM_NODE_TYPE_P(element, PM_MISSING_NODE))
break;
20339 parse_assignment_value_local(parser, element);
20345 if ((single_value || (binding_power == (PM_BINDING_POWER_MULTI_ASSIGNMENT + 1))) && match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
20349 parser_lex(parser);
20351 bool accepts_command_call_inner =
false;
20355 if (PM_NODE_TYPE_P(value, PM_CALL_NODE)) {
20356 pm_call_node_t *call_node = (pm_call_node_t *) value;
20358 accepts_command_call_inner =
true;
20362 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MATCH + 1, accepts_command_call_inner,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
20363 context_pop(parser);
20365 return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
20379parse_call_operator_write(
pm_parser_t *parser, pm_call_node_t *call_node,
const pm_token_t *
operator) {
20381 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_ARGUMENTS);
20382 pm_node_unreference(parser, UP(call_node->
arguments));
20383 pm_node_destroy(parser, UP(call_node->
arguments));
20387 if (call_node->
block != NULL) {
20388 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_BLOCK);
20389 pm_node_unreference(parser, UP(call_node->
block));
20390 pm_node_destroy(parser, UP(call_node->
block));
20391 call_node->
block = NULL;
20420static inline const uint8_t *
20421pm_named_capture_escape_hex(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
20424 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
20425 uint8_t value = escape_hexadecimal_digit(*cursor);
20428 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
20429 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(*cursor));
20433 pm_buffer_append_byte(unescaped, value);
20435 pm_buffer_append_string(unescaped,
"\\x", 2);
20441static inline const uint8_t *
20442pm_named_capture_escape_octal(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
20443 uint8_t value = (uint8_t) (*cursor -
'0');
20446 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
20447 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
20450 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
20451 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
20456 pm_buffer_append_byte(unescaped, value);
20460static inline const uint8_t *
20462 const uint8_t *start = cursor - 1;
20465 if (cursor >= end) {
20466 pm_buffer_append_string(unescaped,
"\\u", 2);
20470 if (*cursor !=
'{') {
20471 size_t length = pm_strspn_hexadecimal_digit(cursor, MIN(end - cursor, 4));
20472 uint32_t value = escape_unicode(parser, cursor, length, error_location);
20474 if (!pm_buffer_append_unicode_codepoint(unescaped, value)) {
20475 pm_buffer_append_string(unescaped, (
const char *) start, (
size_t) ((cursor + length) - start));
20478 return cursor + length;
20483 while (cursor < end && *cursor ==
' ') cursor++;
20485 if (cursor >= end)
break;
20486 if (*cursor ==
'}') {
20491 size_t length = pm_strspn_hexadecimal_digit(cursor, end - cursor);
20495 uint32_t value = escape_unicode(parser, cursor, length, error_location);
20497 (void) pm_buffer_append_unicode_codepoint(unescaped, value);
20505pm_named_capture_escape(
pm_parser_t *parser,
pm_buffer_t *unescaped,
const uint8_t *source,
const size_t length,
const uint8_t *cursor,
const pm_location_t *error_location) {
20506 const uint8_t *end = source + length;
20507 pm_buffer_append_string(unescaped, (
const char *) source, (
size_t) (cursor - source));
20510 if (++cursor >= end) {
20511 pm_buffer_append_byte(unescaped,
'\\');
20517 cursor = pm_named_capture_escape_hex(unescaped, cursor, end);
20519 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
20520 cursor = pm_named_capture_escape_octal(unescaped, cursor, end);
20523 cursor = pm_named_capture_escape_unicode(parser, unescaped, cursor, end, error_location);
20526 pm_buffer_append_byte(unescaped,
'\\');
20530 const uint8_t *next_cursor = pm_memchr(cursor,
'\\', (
size_t) (end - cursor), parser->
encoding_changed, parser->
encoding);
20531 if (next_cursor == NULL)
break;
20533 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (next_cursor - cursor));
20534 cursor = next_cursor;
20537 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (end - cursor));
20545parse_regular_expression_named_capture(
const pm_string_t *capture,
void *data) {
20549 pm_call_node_t *call = callback_data->
call;
20552 const uint8_t *source = pm_string_source(capture);
20553 size_t length = pm_string_length(capture);
20566 pm_named_capture_escape(parser, &unescaped, source, length, cursor, callback_data->
shared ? NULL : &call->
receiver->
location);
20567 source = (
const uint8_t *) pm_buffer_value(&unescaped);
20568 length = pm_buffer_length(&unescaped);
20576 if (!pm_slice_is_valid_local(parser, source, source + length)) {
20577 pm_buffer_free(&unescaped);
20581 if (callback_data->
shared) {
20584 location = (
pm_location_t) { .start = source, .end = source + length };
20585 name = pm_parser_constant_id_location(parser, location.
start, location.
end);
20591 void *memory =
xmalloc(length);
20592 if (memory == NULL) abort();
20594 memcpy(memory, source, length);
20595 name = pm_parser_constant_id_owned(parser, (uint8_t *) memory, length);
20600 if (name != 0 && !pm_constant_id_list_includes(names, name)) {
20601 pm_constant_id_list_append(names, name);
20604 if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
20607 if (pm_local_is_keyword((
const char *) source, length)) {
20608 pm_buffer_free(&unescaped);
20614 pm_parser_local_add(parser, name, location.
start, location.
end, 0);
20619 if (callback_data->
match == NULL) {
20620 callback_data->
match = pm_match_write_node_create(parser, call);
20625 pm_node_t *target = UP(pm_local_variable_target_node_create(parser, &location, name, depth == -1 ? 0 : (uint32_t) depth));
20626 pm_node_list_append(&callback_data->
match->
targets, target);
20629 pm_buffer_free(&unescaped);
20637parse_regular_expression_named_captures(
pm_parser_t *parser,
const pm_string_t *content, pm_call_node_t *call,
bool extended_mode) {
20642 .shared = content->
type == PM_STRING_SHARED
20649 .shared = content->
type == PM_STRING_SHARED
20652 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);
20653 pm_constant_id_list_free(&callback_data.
names);
20655 if (callback_data.
match != NULL) {
20656 return UP(callback_data.
match);
20662static inline pm_node_t *
20663parse_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) {
20666 switch (token.type) {
20667 case PM_TOKEN_EQUAL: {
20668 switch (PM_NODE_TYPE(node)) {
20669 case PM_CALL_NODE: {
20674 pm_call_node_t *call_node = (pm_call_node_t *) node;
20675 if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
20680 case PM_CASE_WRITABLE: {
20684 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
20688 parser_lex(parser);
20689 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));
20691 if (PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) && previous_binding_power != PM_BINDING_POWER_STATEMENT) {
20692 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_MULTI_WRITE);
20695 return parse_write(parser, node, &token, value);
20697 case PM_SPLAT_NODE: {
20698 pm_multi_target_node_t *multi_target = pm_multi_target_node_create(parser);
20699 pm_multi_target_node_targets_append(parser, multi_target, node);
20701 parser_lex(parser);
20702 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));
20703 return parse_write(parser, UP(multi_target), &token, value);
20705 case PM_SOURCE_ENCODING_NODE:
20706 case PM_FALSE_NODE:
20707 case PM_SOURCE_FILE_NODE:
20708 case PM_SOURCE_LINE_NODE:
20711 case PM_TRUE_NODE: {
20714 parser_lex(parser);
20715 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));
20716 return parse_unwriteable_write(parser, node, &token, value);
20722 parser_lex(parser);
20723 pm_parser_err_token(parser, &token, PM_ERR_EXPRESSION_NOT_WRITABLE);
20727 case PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL: {
20728 switch (PM_NODE_TYPE(node)) {
20729 case PM_BACK_REFERENCE_READ_NODE:
20730 case PM_NUMBERED_REFERENCE_READ_NODE:
20731 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
20733 case PM_GLOBAL_VARIABLE_READ_NODE: {
20734 parser_lex(parser);
20736 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));
20737 pm_node_t *result = UP(pm_global_variable_and_write_node_create(parser, node, &token, value));
20739 pm_node_destroy(parser, node);
20742 case PM_CLASS_VARIABLE_READ_NODE: {
20743 parser_lex(parser);
20745 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));
20746 pm_node_t *result = UP(pm_class_variable_and_write_node_create(parser, (pm_class_variable_read_node_t *) node, &token, value));
20748 pm_node_destroy(parser, node);
20751 case PM_CONSTANT_PATH_NODE: {
20752 parser_lex(parser);
20754 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));
20755 pm_node_t *write = UP(pm_constant_path_and_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value));
20757 return parse_shareable_constant_write(parser, write);
20759 case PM_CONSTANT_READ_NODE: {
20760 parser_lex(parser);
20762 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));
20763 pm_node_t *write = UP(pm_constant_and_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value));
20765 pm_node_destroy(parser, node);
20766 return parse_shareable_constant_write(parser, write);
20768 case PM_INSTANCE_VARIABLE_READ_NODE: {
20769 parser_lex(parser);
20771 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20772 pm_node_t *result = UP(pm_instance_variable_and_write_node_create(parser, (pm_instance_variable_read_node_t *) node, &token, value));
20774 pm_node_destroy(parser, node);
20777 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
20779 parser_lex(parser);
20781 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));
20782 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &token, value, name, 0));
20784 pm_node_unreference(parser, node);
20785 pm_node_destroy(parser, node);
20788 case PM_LOCAL_VARIABLE_READ_NODE: {
20791 pm_node_unreference(parser, node);
20794 pm_local_variable_read_node_t *cast = (pm_local_variable_read_node_t *) node;
20795 parser_lex(parser);
20797 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));
20798 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
20800 pm_node_destroy(parser, node);
20803 case PM_CALL_NODE: {
20804 pm_call_node_t *cast = (pm_call_node_t *) node;
20809 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
20811 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
20814 parser_lex(parser);
20816 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));
20817 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
20819 pm_node_destroy(parser, UP(cast));
20825 parser_lex(parser);
20830 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
20831 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));
20832 return UP(pm_index_and_write_node_create(parser, cast, &token, value));
20836 if (pm_call_node_writable_p(parser, cast)) {
20837 parse_write_name(parser, &cast->
name);
20839 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
20842 parse_call_operator_write(parser, cast, &token);
20843 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));
20844 return UP(pm_call_and_write_node_create(parser, cast, &token, value));
20846 case PM_MULTI_WRITE_NODE: {
20847 parser_lex(parser);
20848 pm_parser_err_token(parser, &token, PM_ERR_AMPAMPEQ_MULTI_ASSIGN);
20852 parser_lex(parser);
20857 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
20861 case PM_TOKEN_PIPE_PIPE_EQUAL: {
20862 switch (PM_NODE_TYPE(node)) {
20863 case PM_BACK_REFERENCE_READ_NODE:
20864 case PM_NUMBERED_REFERENCE_READ_NODE:
20865 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
20867 case PM_GLOBAL_VARIABLE_READ_NODE: {
20868 parser_lex(parser);
20870 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));
20871 pm_node_t *result = UP(pm_global_variable_or_write_node_create(parser, node, &token, value));
20873 pm_node_destroy(parser, node);
20876 case PM_CLASS_VARIABLE_READ_NODE: {
20877 parser_lex(parser);
20879 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));
20880 pm_node_t *result = UP(pm_class_variable_or_write_node_create(parser, (pm_class_variable_read_node_t *) node, &token, value));
20882 pm_node_destroy(parser, node);
20885 case PM_CONSTANT_PATH_NODE: {
20886 parser_lex(parser);
20888 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));
20889 pm_node_t *write = UP(pm_constant_path_or_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value));
20891 return parse_shareable_constant_write(parser, write);
20893 case PM_CONSTANT_READ_NODE: {
20894 parser_lex(parser);
20896 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));
20897 pm_node_t *write = UP(pm_constant_or_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value));
20899 pm_node_destroy(parser, node);
20900 return parse_shareable_constant_write(parser, write);
20902 case PM_INSTANCE_VARIABLE_READ_NODE: {
20903 parser_lex(parser);
20905 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20906 pm_node_t *result = UP(pm_instance_variable_or_write_node_create(parser, (pm_instance_variable_read_node_t *) node, &token, value));
20908 pm_node_destroy(parser, node);
20911 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
20913 parser_lex(parser);
20915 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));
20916 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &token, value, name, 0));
20918 pm_node_unreference(parser, node);
20919 pm_node_destroy(parser, node);
20922 case PM_LOCAL_VARIABLE_READ_NODE: {
20925 pm_node_unreference(parser, node);
20928 pm_local_variable_read_node_t *cast = (pm_local_variable_read_node_t *) node;
20929 parser_lex(parser);
20931 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));
20932 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
20934 pm_node_destroy(parser, node);
20937 case PM_CALL_NODE: {
20938 pm_call_node_t *cast = (pm_call_node_t *) node;
20943 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
20945 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
20948 parser_lex(parser);
20950 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));
20951 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
20953 pm_node_destroy(parser, UP(cast));
20959 parser_lex(parser);
20964 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
20965 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));
20966 return UP(pm_index_or_write_node_create(parser, cast, &token, value));
20970 if (pm_call_node_writable_p(parser, cast)) {
20971 parse_write_name(parser, &cast->
name);
20973 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
20976 parse_call_operator_write(parser, cast, &token);
20977 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));
20978 return UP(pm_call_or_write_node_create(parser, cast, &token, value));
20980 case PM_MULTI_WRITE_NODE: {
20981 parser_lex(parser);
20982 pm_parser_err_token(parser, &token, PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN);
20986 parser_lex(parser);
20991 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
20995 case PM_TOKEN_AMPERSAND_EQUAL:
20996 case PM_TOKEN_CARET_EQUAL:
20997 case PM_TOKEN_GREATER_GREATER_EQUAL:
20998 case PM_TOKEN_LESS_LESS_EQUAL:
20999 case PM_TOKEN_MINUS_EQUAL:
21000 case PM_TOKEN_PERCENT_EQUAL:
21001 case PM_TOKEN_PIPE_EQUAL:
21002 case PM_TOKEN_PLUS_EQUAL:
21003 case PM_TOKEN_SLASH_EQUAL:
21004 case PM_TOKEN_STAR_EQUAL:
21005 case PM_TOKEN_STAR_STAR_EQUAL: {
21006 switch (PM_NODE_TYPE(node)) {
21007 case PM_BACK_REFERENCE_READ_NODE:
21008 case PM_NUMBERED_REFERENCE_READ_NODE:
21009 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21011 case PM_GLOBAL_VARIABLE_READ_NODE: {
21012 parser_lex(parser);
21014 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));
21015 pm_node_t *result = UP(pm_global_variable_operator_write_node_create(parser, node, &token, value));
21017 pm_node_destroy(parser, node);
21020 case PM_CLASS_VARIABLE_READ_NODE: {
21021 parser_lex(parser);
21023 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));
21024 pm_node_t *result = UP(pm_class_variable_operator_write_node_create(parser, (pm_class_variable_read_node_t *) node, &token, value));
21026 pm_node_destroy(parser, node);
21029 case PM_CONSTANT_PATH_NODE: {
21030 parser_lex(parser);
21032 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));
21033 pm_node_t *write = UP(pm_constant_path_operator_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value));
21035 return parse_shareable_constant_write(parser, write);
21037 case PM_CONSTANT_READ_NODE: {
21038 parser_lex(parser);
21040 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));
21041 pm_node_t *write = UP(pm_constant_operator_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value));
21043 pm_node_destroy(parser, node);
21044 return parse_shareable_constant_write(parser, write);
21046 case PM_INSTANCE_VARIABLE_READ_NODE: {
21047 parser_lex(parser);
21049 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));
21050 pm_node_t *result = UP(pm_instance_variable_operator_write_node_create(parser, (pm_instance_variable_read_node_t *) node, &token, value));
21052 pm_node_destroy(parser, node);
21055 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21057 parser_lex(parser);
21059 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));
21060 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &token, value, name, 0));
21062 pm_node_unreference(parser, node);
21063 pm_node_destroy(parser, node);
21066 case PM_LOCAL_VARIABLE_READ_NODE: {
21069 pm_node_unreference(parser, node);
21072 pm_local_variable_read_node_t *cast = (pm_local_variable_read_node_t *) node;
21073 parser_lex(parser);
21075 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));
21076 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
21078 pm_node_destroy(parser, node);
21081 case PM_CALL_NODE: {
21082 parser_lex(parser);
21083 pm_call_node_t *cast = (pm_call_node_t *) node;
21088 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21090 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21093 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));
21094 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
21096 pm_node_destroy(parser, UP(cast));
21103 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21104 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));
21105 return UP(pm_index_operator_write_node_create(parser, cast, &token, value));
21109 if (pm_call_node_writable_p(parser, cast)) {
21110 parse_write_name(parser, &cast->
name);
21112 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21115 parse_call_operator_write(parser, cast, &token);
21116 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));
21117 return UP(pm_call_operator_write_node_create(parser, cast, &token, value));
21119 case PM_MULTI_WRITE_NODE: {
21120 parser_lex(parser);
21121 pm_parser_err_token(parser, &token, PM_ERR_OPERATOR_MULTI_ASSIGN);
21125 parser_lex(parser);
21134 case PM_TOKEN_AMPERSAND_AMPERSAND:
21135 case PM_TOKEN_KEYWORD_AND: {
21136 parser_lex(parser);
21138 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));
21139 return UP(pm_and_node_create(parser, node, &token, right));
21141 case PM_TOKEN_KEYWORD_OR:
21142 case PM_TOKEN_PIPE_PIPE: {
21143 parser_lex(parser);
21145 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));
21146 return UP(pm_or_node_create(parser, node, &token, right));
21148 case PM_TOKEN_EQUAL_TILDE: {
21156 parser_lex(parser);
21157 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21160 pm_call_node_t *call = pm_call_node_binary_create(parser, node, &token, argument, 0);
21161 pm_node_t *result = UP(call);
21166 if (PM_NODE_TYPE_P(node, PM_INTERPOLATED_REGULAR_EXPRESSION_NODE)) {
21171 pm_node_list_t *parts = &((pm_interpolated_regular_expression_node_t *) node)->parts;
21173 bool interpolated =
false;
21174 size_t total_length = 0;
21178 if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
21179 total_length += pm_string_length(&((pm_string_node_t *) part)->unescaped);
21181 interpolated =
true;
21186 if (!interpolated && total_length > 0) {
21187 void *memory =
xmalloc(total_length);
21188 if (!memory) abort();
21190 uint8_t *cursor = memory;
21192 pm_string_t *unescaped = &((pm_string_node_t *) part)->unescaped;
21193 size_t length = pm_string_length(unescaped);
21195 memcpy(cursor, pm_string_source(unescaped), length);
21200 pm_string_owned_init(&owned, (uint8_t *) memory, total_length);
21202 result = parse_regular_expression_named_captures(parser, &owned, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
21203 pm_string_free(&owned);
21205 }
else if (PM_NODE_TYPE_P(node, PM_REGULAR_EXPRESSION_NODE)) {
21208 const pm_string_t *content = &((pm_regular_expression_node_t *) node)->unescaped;
21209 result = parse_regular_expression_named_captures(parser, content, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
21214 case PM_TOKEN_UAMPERSAND:
21215 case PM_TOKEN_USTAR:
21216 case PM_TOKEN_USTAR_STAR:
21219 case PM_TOKEN_BANG_EQUAL:
21220 case PM_TOKEN_BANG_TILDE:
21221 case PM_TOKEN_EQUAL_EQUAL:
21222 case PM_TOKEN_EQUAL_EQUAL_EQUAL:
21223 case PM_TOKEN_LESS_EQUAL_GREATER:
21224 case PM_TOKEN_CARET:
21225 case PM_TOKEN_PIPE:
21226 case PM_TOKEN_AMPERSAND:
21227 case PM_TOKEN_GREATER_GREATER:
21228 case PM_TOKEN_LESS_LESS:
21229 case PM_TOKEN_MINUS:
21230 case PM_TOKEN_PLUS:
21231 case PM_TOKEN_PERCENT:
21232 case PM_TOKEN_SLASH:
21233 case PM_TOKEN_STAR:
21234 case PM_TOKEN_STAR_STAR: {
21235 parser_lex(parser);
21237 switch (PM_NODE_TYPE(node)) {
21238 case PM_RESCUE_MODIFIER_NODE: {
21239 pm_rescue_modifier_node_t *cast = (pm_rescue_modifier_node_t *) node;
21241 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21245 case PM_AND_NODE: {
21246 pm_and_node_t *cast = (pm_and_node_t *) node;
21247 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21248 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21253 pm_or_node_t *cast = (pm_or_node_t *) node;
21254 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21255 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21263 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21264 return UP(pm_call_node_binary_create(parser, node, &token, argument, 0));
21266 case PM_TOKEN_GREATER:
21267 case PM_TOKEN_GREATER_EQUAL:
21268 case PM_TOKEN_LESS:
21269 case PM_TOKEN_LESS_EQUAL: {
21270 if (PM_NODE_TYPE_P(node, PM_CALL_NODE) && PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_COMPARISON)) {
21271 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_COMPARISON_AFTER_COMPARISON);
21274 parser_lex(parser);
21275 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21276 return UP(pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON));
21278 case PM_TOKEN_AMPERSAND_DOT:
21279 case PM_TOKEN_DOT: {
21280 parser_lex(parser);
21285 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
21286 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21287 return UP(pm_call_node_shorthand_create(parser, node, &
operator, &arguments));
21290 switch (PM_NODE_TYPE(node)) {
21291 case PM_RESCUE_MODIFIER_NODE: {
21292 pm_rescue_modifier_node_t *cast = (pm_rescue_modifier_node_t *) node;
21294 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21298 case PM_AND_NODE: {
21299 pm_and_node_t *cast = (pm_and_node_t *) node;
21300 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21301 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21306 pm_or_node_t *cast = (pm_or_node_t *) node;
21307 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21308 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21318 switch (parser->
current.type) {
21319 case PM_CASE_OPERATOR:
21320 case PM_CASE_KEYWORD:
21321 case PM_TOKEN_CONSTANT:
21322 case PM_TOKEN_IDENTIFIER:
21323 case PM_TOKEN_METHOD_NAME: {
21324 parser_lex(parser);
21334 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21335 pm_call_node_t *call = pm_call_node_call_create(parser, node, &
operator, &message, &arguments);
21338 (previous_binding_power == PM_BINDING_POWER_STATEMENT) &&
21341 match1(parser, PM_TOKEN_COMMA)
21343 return parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21348 case PM_TOKEN_DOT_DOT:
21349 case PM_TOKEN_DOT_DOT_DOT: {
21350 parser_lex(parser);
21352 pm_node_t *right = NULL;
21353 if (token_begins_expression_p(parser->
current.type)) {
21354 right = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21357 return UP(pm_range_node_create(parser, node, &token, right));
21359 case PM_TOKEN_KEYWORD_IF_MODIFIER: {
21361 parser_lex(parser);
21363 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
21364 return UP(pm_if_node_modifier_create(parser, node, &keyword, predicate));
21366 case PM_TOKEN_KEYWORD_UNLESS_MODIFIER: {
21368 parser_lex(parser);
21370 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
21371 return UP(pm_unless_node_modifier_create(parser, node, &keyword, predicate));
21373 case PM_TOKEN_KEYWORD_UNTIL_MODIFIER: {
21374 parser_lex(parser);
21375 pm_statements_node_t *statements = pm_statements_node_create(parser);
21376 pm_statements_node_body_append(parser, statements, node,
true);
21378 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
21379 return UP(pm_until_node_modifier_create(parser, &token, predicate, statements, PM_NODE_TYPE_P(node, PM_BEGIN_NODE) ? PM_LOOP_FLAGS_BEGIN_MODIFIER : 0));
21381 case PM_TOKEN_KEYWORD_WHILE_MODIFIER: {
21382 parser_lex(parser);
21383 pm_statements_node_t *statements = pm_statements_node_create(parser);
21384 pm_statements_node_body_append(parser, statements, node,
true);
21386 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
21387 return UP(pm_while_node_modifier_create(parser, &token, predicate, statements, PM_NODE_TYPE_P(node, PM_BEGIN_NODE) ? PM_LOOP_FLAGS_BEGIN_MODIFIER : 0));
21389 case PM_TOKEN_QUESTION_MARK: {
21391 pm_node_list_t current_block_exits = { 0 };
21392 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
21395 parser_lex(parser);
21397 pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_TRUE, (uint16_t) (depth + 1));
21407 pm_node_t *false_expression = UP(pm_missing_node_create(parser, colon.
start, colon.
end));
21409 context_pop(parser);
21410 pop_block_exits(parser, previous_block_exits);
21411 pm_node_list_free(¤t_block_exits);
21413 return UP(pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression));
21416 accept1(parser, PM_TOKEN_NEWLINE);
21417 expect1(parser, PM_TOKEN_COLON, PM_ERR_TERNARY_COLON);
21420 pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_FALSE, (uint16_t) (depth + 1));
21422 context_pop(parser);
21423 pop_block_exits(parser, previous_block_exits);
21424 pm_node_list_free(¤t_block_exits);
21426 return UP(pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression));
21428 case PM_TOKEN_COLON_COLON: {
21429 parser_lex(parser);
21432 switch (parser->
current.type) {
21433 case PM_TOKEN_CONSTANT: {
21434 parser_lex(parser);
21438 (parser->
current.type == PM_TOKEN_PARENTHESIS_LEFT) ||
21439 (accepts_command_call && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)))
21450 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21451 path = UP(pm_call_node_call_create(parser, node, &delimiter, &message, &arguments));
21454 path = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous));
21458 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
21459 return parse_targets_validate(parser, path, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21464 case PM_CASE_OPERATOR:
21465 case PM_CASE_KEYWORD:
21466 case PM_TOKEN_IDENTIFIER:
21467 case PM_TOKEN_METHOD_NAME: {
21468 parser_lex(parser);
21474 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21475 pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
21478 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
21479 return parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21484 case PM_TOKEN_PARENTHESIS_LEFT: {
21488 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21490 return UP(pm_call_node_shorthand_create(parser, node, &delimiter, &arguments));
21493 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
21494 return UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous));
21498 case PM_TOKEN_KEYWORD_RESCUE_MODIFIER: {
21500 parser_lex(parser);
21501 accept1(parser, PM_TOKEN_NEWLINE);
21503 pm_node_t *value = parse_expression(parser, binding_power,
true,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
21504 context_pop(parser);
21506 return UP(pm_rescue_modifier_node_create(parser, node, &token, value));
21508 case PM_TOKEN_BRACKET_LEFT: {
21509 parser_lex(parser);
21514 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
21515 pm_accepts_block_stack_push(parser,
true);
21516 parse_arguments(parser, &arguments,
false, PM_TOKEN_BRACKET_RIGHT, (uint16_t) (depth + 1));
21517 pm_accepts_block_stack_pop(parser);
21518 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_EXPECT_RBRACKET);
21525 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
21526 pm_call_node_t *aref = pm_call_node_aref_create(parser, node, &arguments);
21527 return parse_targets_validate(parser, UP(aref), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21533 pm_block_node_t *block = NULL;
21534 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
21535 block = parse_block(parser, (uint16_t) (depth + 1));
21536 pm_arguments_validate_block(parser, &arguments, block);
21537 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
21538 block = parse_block(parser, (uint16_t) (depth + 1));
21541 if (block != NULL) {
21542 if (arguments.
block != NULL) {
21543 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_AFTER_BLOCK);
21545 arguments.
arguments = pm_arguments_node_create(parser);
21547 pm_arguments_node_arguments_append(arguments.
arguments, arguments.
block);
21550 arguments.
block = UP(block);
21553 return UP(pm_call_node_aref_create(parser, node, &arguments));
21555 case PM_TOKEN_KEYWORD_IN: {
21561 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
21562 parser_lex(parser);
21565 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));
21568 pm_constant_id_list_free(&captures);
21570 return UP(pm_match_predicate_node_create(parser, node, pattern, &
operator));
21572 case PM_TOKEN_EQUAL_GREATER: {
21578 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
21579 parser_lex(parser);
21582 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));
21585 pm_constant_id_list_free(&captures);
21587 return UP(pm_match_required_node_create(parser, node, pattern, &
operator));
21590 assert(
false &&
"unreachable");
21595#undef PM_PARSE_PATTERN_SINGLE
21596#undef PM_PARSE_PATTERN_TOP
21597#undef PM_PARSE_PATTERN_MULTI
21604pm_call_node_command_p(
const pm_call_node_t *node) {
21607 (node->
block == NULL || PM_NODE_TYPE_P(node->
block, PM_BLOCK_ARGUMENT_NODE)) &&
21621parse_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) {
21623 pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
21624 return UP(pm_missing_node_create(parser, parser->
current.start, parser->
current.end));
21627 pm_node_t *node = parse_expression_prefix(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
21629 switch (PM_NODE_TYPE(node)) {
21630 case PM_MISSING_NODE:
21634 case PM_PRE_EXECUTION_NODE:
21635 case PM_POST_EXECUTION_NODE:
21636 case PM_ALIAS_GLOBAL_VARIABLE_NODE:
21637 case PM_ALIAS_METHOD_NODE:
21638 case PM_MULTI_WRITE_NODE:
21639 case PM_UNDEF_NODE:
21642 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21652 if ((pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_COMPOSITION) && pm_call_node_command_p((pm_call_node_t *) node)) {
21656 case PM_SYMBOL_NODE:
21660 if (pm_symbol_node_label_p(node)) {
21671 pm_token_type_t current_token_type;
21674 current_token_type = parser->
current.type,
21675 current_binding_powers = pm_binding_powers[current_token_type],
21676 binding_power <= current_binding_powers.
left &&
21677 current_binding_powers.
binary
21679 node = parse_expression_infix(parser, node, binding_power, current_binding_powers.
right, accepts_command_call, (uint16_t) (depth + 1));
21681 switch (PM_NODE_TYPE(node)) {
21682 case PM_MULTI_WRITE_NODE:
21685 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21689 case PM_CLASS_VARIABLE_WRITE_NODE:
21690 case PM_CONSTANT_PATH_WRITE_NODE:
21691 case PM_CONSTANT_WRITE_NODE:
21692 case PM_GLOBAL_VARIABLE_WRITE_NODE:
21693 case PM_INSTANCE_VARIABLE_WRITE_NODE:
21694 case PM_LOCAL_VARIABLE_WRITE_NODE:
21697 if (PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21705 if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21715 if (current_binding_powers.
nonassoc) {
21718 if (match1(parser, current_token_type)) {
21730 if (PM_NODE_TYPE_P(node, PM_RANGE_NODE) && ((pm_range_node_t *) node)->right == NULL) {
21731 if (match4(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_DOT, PM_TOKEN_AMPERSAND_DOT)) {
21736 if (PM_BINDING_POWER_TERM <= pm_binding_powers[parser->
current.type].left) {
21739 }
else if (current_binding_powers.
left <= pm_binding_powers[parser->
current.type].left) {
21744 if (accepts_command_call) {
21753 switch (node->
type) {
21754 case PM_CALL_NODE: {
21755 pm_call_node_t *cast = (pm_call_node_t *)node;
21768 cast->
block == NULL &&
21778 cast->
block != NULL && PM_NODE_TYPE_P(cast->
block, PM_BLOCK_NODE)
21781 accepts_command_call =
false;
21786 case PM_CONSTANT_PATH_NODE:
21789 accepts_command_call =
false;
21797 !next_binding_powers.
binary ||
21798 binding_power > next_binding_powers.
left ||
21799 (PM_NODE_TYPE_P(node, PM_CALL_NODE) && pm_call_node_command_p((pm_call_node_t *) node))
21813static pm_statements_node_t *
21814wrap_statements(
pm_parser_t *parser, pm_statements_node_t *statements) {
21815 if (PM_PARSER_COMMAND_LINE_OPTION_P(parser)) {
21816 if (statements == NULL) {
21817 statements = pm_statements_node_create(parser);
21820 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
21821 pm_arguments_node_arguments_append(
21823 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2)))
21826 pm_statements_node_body_append(parser, statements, UP(pm_call_node_fcall_synthesized_create(
21829 pm_parser_constant_id_constant(parser,
"print", 5)
21833 if (PM_PARSER_COMMAND_LINE_OPTION_N(parser)) {
21834 if (PM_PARSER_COMMAND_LINE_OPTION_A(parser)) {
21835 if (statements == NULL) {
21836 statements = pm_statements_node_create(parser);
21839 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
21840 pm_arguments_node_arguments_append(
21842 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$;", 2)))
21845 pm_global_variable_read_node_t *receiver = pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2));
21846 pm_call_node_t *call = pm_call_node_call_synthesized_create(parser, UP(receiver),
"split", arguments);
21848 pm_global_variable_write_node_t *write = pm_global_variable_write_node_synthesized_create(
21850 pm_parser_constant_id_constant(parser,
"$F", 2),
21854 pm_statements_node_body_prepend(statements, UP(write));
21857 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
21858 pm_arguments_node_arguments_append(
21860 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$/", 2)))
21863 if (PM_PARSER_COMMAND_LINE_OPTION_L(parser)) {
21864 pm_keyword_hash_node_t *keywords = pm_keyword_hash_node_create(parser);
21865 pm_keyword_hash_node_elements_append(keywords, UP(pm_assoc_node_create(
21867 UP(pm_symbol_node_synthesized_create(parser,
"chomp")),
21868 &(
pm_token_t) { .type = PM_TOKEN_NOT_PROVIDED, .start = parser->
start, .end = parser->
start },
21869 UP(pm_true_node_synthesized_create(parser))
21872 pm_arguments_node_arguments_append(arguments, UP(keywords));
21873 pm_node_flag_set(UP(arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS);
21876 pm_statements_node_t *wrapped_statements = pm_statements_node_create(parser);
21877 pm_statements_node_body_append(parser, wrapped_statements, UP(pm_while_node_synthesized_create(
21879 UP(pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser,
"gets", 4))),
21883 statements = wrapped_statements;
21898 pm_parser_scope_push(parser,
true);
21901 pm_node_list_t current_block_exits = { 0 };
21902 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
21904 parser_lex(parser);
21905 pm_statements_node_t *statements = parse_statements(parser,
PM_CONTEXT_MAIN, 0);
21911 assert(statements->
body.
size > 0);
21912 pm_void_statement_check(parser, statements->
body.
nodes[statements->
body.
size - 1]);
21917 pm_parser_scope_pop(parser);
21922 statements = wrap_statements(parser, statements);
21924 flush_block_exits(parser, previous_block_exits);
21927 pm_node_list_free(¤t_block_exits);
21932 if (statements == NULL) {
21933 statements = pm_statements_node_create(parser);
21934 pm_statements_node_location_set(statements, parser->
start, parser->
start);
21937 return UP(pm_program_node_create(parser, &locals, statements));
21954pm_strnstr(
const char *big,
const char *little,
size_t big_length) {
21955 size_t little_length = strlen(little);
21957 for (
const char *max = big + big_length - little_length; big <= max; big++) {
21958 if (*big == *little && memcmp(big, little, little_length) == 0)
return big;
21965#define pm_parser_warn_shebang_carriage_return(parser, start, length) ((void) 0)
21973pm_parser_warn_shebang_carriage_return(
pm_parser_t *parser,
const uint8_t *start,
size_t length) {
21974 if (length > 2 && start[length - 2] ==
'\r' && start[length - 1] ==
'\n') {
21975 pm_parser_warn(parser, start, start + length, PM_WARN_SHEBANG_CARRIAGE_RETURN);
21986 const char *switches = pm_strnstr(engine,
" -", length);
21987 if (switches == NULL)
return;
21992 (
const uint8_t *) (switches + 1),
21993 length - ((
size_t) (switches - engine)) - 1,
21997 size_t encoding_length;
21998 if ((encoding_length = pm_string_length(&next_options.
encoding)) > 0) {
21999 const uint8_t *encoding_source = pm_string_source(&next_options.
encoding);
22000 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22012 assert(source != NULL);
22016 .lex_state = PM_LEX_STATE_BEG,
22017 .enclosure_nesting = 0,
22018 .lambda_enclosure_nesting = -1,
22019 .brace_nesting = 0,
22020 .do_loop_stack = 0,
22021 .accepts_block_stack = 0,
22024 .stack = {{ .mode = PM_LEX_DEFAULT }},
22028 .end = source + size,
22029 .previous = { .type = PM_TOKEN_EOF, .start = source, .end = source },
22030 .current = { .type = PM_TOKEN_EOF, .start = source, .end = source },
22031 .next_start = NULL,
22032 .heredoc_end = NULL,
22033 .data_loc = { .start = NULL, .end = NULL },
22034 .comment_list = { 0 },
22035 .magic_comment_list = { 0 },
22036 .warning_list = { 0 },
22037 .error_list = { 0 },
22038 .current_scope = NULL,
22039 .current_context = NULL,
22041 .encoding_changed_callback = NULL,
22042 .encoding_comment_start = source,
22043 .lex_callback = NULL,
22045 .constant_pool = { 0 },
22046 .newline_list = { 0 },
22050 .explicit_encoding = NULL,
22052 .parsing_eval =
false,
22053 .partial_script =
false,
22054 .command_start =
true,
22055 .recovering =
false,
22056 .encoding_locked =
false,
22057 .encoding_changed =
false,
22058 .pattern_matching_newlines =
false,
22059 .in_keyword_arg =
false,
22060 .current_block_exits = NULL,
22061 .semantic_token_seen =
false,
22063 .current_regular_expression_ascii_only =
false,
22064 .warn_mismatched_indentation =
true
22081 uint32_t constant_size = ((uint32_t) size) / 95;
22082 pm_constant_pool_init(&parser->
constant_pool, constant_size < 4 ? 4 : constant_size);
22087 size_t newline_size = size / 22;
22088 pm_newline_list_init(&parser->
newline_list, source, newline_size < 4 ? 4 : newline_size);
22091 if (options != NULL) {
22099 size_t encoding_length = pm_string_length(&options->
encoding);
22100 if (encoding_length > 0) {
22101 const uint8_t *encoding_source = pm_string_source(&options->
encoding);
22102 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22124 for (
size_t scope_index = 0; scope_index < options->
scopes_count; scope_index++) {
22126 pm_parser_scope_push(parser, scope_index == 0);
22132 for (
size_t local_index = 0; local_index < scope->
locals_count; local_index++) {
22133 const pm_string_t *local = pm_options_scope_local_get(scope, local_index);
22135 const uint8_t *source = pm_string_source(local);
22136 size_t length = pm_string_length(local);
22138 void *allocated =
xmalloc(length);
22139 if (allocated == NULL)
continue;
22141 memcpy(allocated, source, length);
22142 pm_parser_local_add_owned(parser, (uint8_t *) allocated, length);
22153 pm_accepts_block_stack_push(parser,
true);
22156 if (size >= 3 && source[0] == 0xef && source[1] == 0xbb && source[2] == 0xbf) {
22169 bool search_shebang = PM_PARSER_COMMAND_LINE_OPTION_X(parser);
22186 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
22187 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - parser->
current.end);
22189 if (length > 2 && parser->
current.end[0] ==
'#' && parser->
current.end[1] ==
'!') {
22190 const char *engine;
22192 if ((engine = pm_strnstr((
const char *) parser->
start,
"ruby", length)) != NULL) {
22193 if (newline != NULL) {
22197 pm_parser_warn_shebang_carriage_return(parser, parser->
start, length + 1);
22202 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) parser->
start)));
22205 search_shebang =
false;
22207 search_shebang =
true;
22213 if (search_shebang) {
22216 bool found_shebang =
false;
22220 const uint8_t *cursor = parser->
start;
22224 const uint8_t *newline = next_newline(cursor, parser->
end - cursor);
22226 while (newline != NULL) {
22227 pm_newline_list_append(&parser->
newline_list, newline);
22229 cursor = newline + 1;
22230 newline = next_newline(cursor, parser->
end - cursor);
22232 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - cursor);
22233 if (length > 2 && cursor[0] ==
'#' && cursor[1] ==
'!') {
22234 const char *engine;
22235 if ((engine = pm_strnstr((
const char *) cursor,
"ruby", length)) != NULL) {
22236 found_shebang =
true;
22238 if (newline != NULL) {
22239 pm_parser_warn_shebang_carriage_return(parser, cursor, length + 1);
22244 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) cursor)));
22252 if (found_shebang) {
22253 parser->
previous = (
pm_token_t) { .type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
22254 parser->
current = (
pm_token_t) { .type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
22256 pm_parser_err(parser, parser->
start, parser->
start, PM_ERR_SCRIPT_NOT_FOUND);
22283 for (node = list->
head; node != NULL; node = next) {
22295pm_magic_comment_list_free(
pm_list_t *list) {
22298 for (node = list->
head; node != NULL; node = next) {
22311 pm_string_free(&parser->
filepath);
22312 pm_diagnostic_list_free(&parser->
error_list);
22324 pm_parser_scope_pop(parser);
22328 lex_mode_pop(parser);
22337 return parse_program(parser);
22347#define LINE_SIZE 4096
22348 char line[LINE_SIZE];
22350 while (memset(line,
'\n', LINE_SIZE), stream_fgets(line, LINE_SIZE, stream) != NULL) {
22351 size_t length = LINE_SIZE;
22352 while (length > 0 && line[length - 1] ==
'\n') length--;
22354 if (length == LINE_SIZE) {
22359 pm_buffer_append_string(buffer, line, length);
22365 pm_buffer_append_string(buffer, line, length);
22373 if (strncmp(line,
"__END__", 7) == 0)
return false;
22376 if (strncmp(line,
"__END__\n", 8) == 0)
return false;
22379 if (strncmp(line,
"__END__\r\n", 9) == 0)
return false;
22385 if (stream_feof(stream)) {
22404pm_parse_stream_unterminated_heredoc_p(
pm_parser_t *parser) {
22407 for (; diagnostic != NULL; diagnostic = (
pm_diagnostic_t *) diagnostic->node.next) {
22408 if (diagnostic->diag_id == PM_ERR_HEREDOC_TERM) {
22424 pm_buffer_init(buffer);
22426 bool eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof);
22428 pm_parser_init(parser, (
const uint8_t *) pm_buffer_value(buffer), pm_buffer_length(buffer), options);
22429 pm_node_t *node =
pm_parse(parser);
22432 pm_node_destroy(parser, node);
22433 eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof);
22436 pm_parser_init(parser, (
const uint8_t *) pm_buffer_value(buffer), pm_buffer_length(buffer), options);
22447pm_parse_success_p(
const uint8_t *source,
size_t size,
const char *data) {
22449 pm_options_read(&options, data);
22452 pm_parser_init(&parser, source, size, &options);
22454 pm_node_t *node = pm_parse(&parser);
22455 pm_node_destroy(&parser, node);
22458 pm_parser_free(&parser);
22459 pm_options_free(&options);
22464#undef PM_CASE_KEYWORD
22465#undef PM_CASE_OPERATOR
22466#undef PM_CASE_WRITABLE
22467#undef PM_STRING_EMPTY
22472#ifndef PRISM_EXCLUDE_SERIALIZATION
22476 pm_buffer_append_string(buffer,
"PRISM", 5);
22480 pm_buffer_append_byte(buffer, PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS ? 1 : 0);
22488 pm_serialize_header(buffer);
22490 pm_buffer_append_byte(buffer,
'\0');
22498pm_serialize_parse(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
22500 pm_options_read(&options, data);
22503 pm_parser_init(&parser, source, size, &options);
22505 pm_node_t *node = pm_parse(&parser);
22507 pm_serialize_header(buffer);
22509 pm_buffer_append_byte(buffer,
'\0');
22511 pm_node_destroy(&parser, node);
22512 pm_parser_free(&parser);
22513 pm_options_free(&options);
22524 pm_options_read(&options, data);
22527 pm_node_t *node = pm_parse_stream(&parser, &parser_buffer, stream, stream_fgets, stream_feof, &options);
22528 pm_serialize_header(buffer);
22530 pm_buffer_append_byte(buffer,
'\0');
22532 pm_node_destroy(&parser, node);
22533 pm_buffer_free(&parser_buffer);
22534 pm_parser_free(&parser);
22535 pm_options_free(&options);
22542pm_serialize_parse_comments(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
22544 pm_options_read(&options, data);
22547 pm_parser_init(&parser, source, size, &options);
22549 pm_node_t *node = pm_parse(&parser);
22550 pm_serialize_header(buffer);
22552 pm_buffer_append_varsint(buffer, parser.
start_line);
22555 pm_node_destroy(&parser, node);
22556 pm_parser_free(&parser);
22557 pm_options_free(&options);
22569 PM_SLICE_TYPE_ERROR = -1,
22572 PM_SLICE_TYPE_NONE,
22575 PM_SLICE_TYPE_LOCAL,
22578 PM_SLICE_TYPE_CONSTANT,
22581 PM_SLICE_TYPE_METHOD_NAME
22588pm_slice_type(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22590 const pm_encoding_t *encoding = pm_encoding_find((
const uint8_t *) encoding_name, (
const uint8_t *) (encoding_name + strlen(encoding_name)));
22591 if (encoding == NULL)
return PM_SLICE_TYPE_ERROR;
22594 if (length == 0)
return PM_SLICE_TYPE_NONE;
22597 if ((width = encoding->
alpha_char(source, (ptrdiff_t) length)) != 0) {
22599 }
else if (*source ==
'_') {
22602 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, (ptrdiff_t) length)) > 0)) {
22606 return PM_SLICE_TYPE_NONE;
22610 const uint8_t *end = source + length;
22611 pm_slice_type_t result = encoding->
isupper_char(source, end - source) ? PM_SLICE_TYPE_CONSTANT : PM_SLICE_TYPE_LOCAL;
22617 while (source < end) {
22618 if ((width = encoding->
alnum_char(source, end - source)) != 0) {
22621 }
else if (*source ==
'_') {
22624 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, end - source)) > 0)) {
22634 if (*source ==
'!' || *source ==
'?' || *source ==
'=') {
22636 result = PM_SLICE_TYPE_METHOD_NAME;
22640 return source == end ? result : PM_SLICE_TYPE_NONE;
22647pm_string_query_local(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22648 switch (pm_slice_type(source, length, encoding_name)) {
22649 case PM_SLICE_TYPE_ERROR:
22651 case PM_SLICE_TYPE_NONE:
22652 case PM_SLICE_TYPE_CONSTANT:
22653 case PM_SLICE_TYPE_METHOD_NAME:
22655 case PM_SLICE_TYPE_LOCAL:
22659 assert(
false &&
"unreachable");
22667pm_string_query_constant(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22668 switch (pm_slice_type(source, length, encoding_name)) {
22669 case PM_SLICE_TYPE_ERROR:
22671 case PM_SLICE_TYPE_NONE:
22672 case PM_SLICE_TYPE_LOCAL:
22673 case PM_SLICE_TYPE_METHOD_NAME:
22675 case PM_SLICE_TYPE_CONSTANT:
22679 assert(
false &&
"unreachable");
22687pm_string_query_method_name(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22688#define B(p) ((p) ? PM_STRING_QUERY_TRUE : PM_STRING_QUERY_FALSE)
22689#define C1(c) (*source == c)
22690#define C2(s) (memcmp(source, s, 2) == 0)
22691#define C3(s) (memcmp(source, s, 3) == 0)
22693 switch (pm_slice_type(source, length, encoding_name)) {
22694 case PM_SLICE_TYPE_ERROR:
22696 case PM_SLICE_TYPE_NONE:
22698 case PM_SLICE_TYPE_LOCAL:
22700 return B((length != 2) || (source[0] !=
'_') || (source[1] ==
'0') || !pm_char_is_decimal_digit(source[1]));
22701 case PM_SLICE_TYPE_CONSTANT:
22703 case PM_SLICE_TYPE_METHOD_NAME:
22710 return B(C1(
'&') || C1(
'`') || C1(
'!') || C1(
'^') || C1(
'>') || C1(
'<') || C1(
'-') || C1(
'%') || C1(
'|') || C1(
'+') || C1(
'/') || C1(
'*') || C1(
'~'));
22712 return B(C2(
"!=") || C2(
"!~") || C2(
"[]") || C2(
"==") || C2(
"=~") || C2(
">=") || C2(
">>") || C2(
"<=") || C2(
"<<") || C2(
"**"));
22714 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_4_0
The vendored version of prism in CRuby 4.0.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_BLOCK_PARAMETERS
expressions in block parameters foo do |...| end
@ PM_CONTEXT_DEF_ENSURE
an ensure statement within a method definition
@ PM_CONTEXT_SCLASS_RESCUE
a rescue statement with a singleton class
@ PM_CONTEXT_PREEXE
a BEGIN block
@ PM_CONTEXT_DEFINED
a defined?
@ 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 equal_loc
CallNode::equal_loc.
pm_location_t call_operator_loc
CallNode::call_operator_loc.
pm_location_t message_loc
CallNode::message_loc.
struct pm_arguments_node * arguments
CallNode::arguments.
struct pm_node * block
CallNode::block.
struct pm_node_list conditions
CaseMatchNode::conditions.
struct pm_node_list conditions
CaseNode::conditions.
size_t size
The number of constant ids in the list.
A constant in the pool which effectively stores a string.
size_t length
The length of the string.
const uint8_t * start
A pointer to the start of the string.
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_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.