From bb56d3b8632a9941d83a1eef91a2e04531687634 Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Thu, 14 Sep 2023 20:03:29 +0200 Subject: [PATCH 1/2] Import ruby/yarp@40b516f2188d8e08ec05900dc00052f4fb173a4c --- src/main/c/yarp/.gitignore | 1 - src/main/c/yarp/include/yarp/ast.h | 789 ++-- src/main/c/yarp/include/yarp/diagnostic.h | 204 +- .../c/yarp/include/yarp/enc/yp_encoding.h | 2 +- src/main/c/yarp/include/yarp/node.h | 4 - src/main/c/yarp/include/yarp/parser.h | 60 +- src/main/c/yarp/include/yarp/unescape.h | 6 +- src/main/c/yarp/include/yarp/util/yp_char.h | 28 +- .../yarp/include/yarp/util/yp_constant_pool.h | 23 +- src/main/c/yarp/include/yarp/version.h | 4 +- src/main/c/yarp/src/diagnostic.c | 261 +- src/main/c/yarp/src/enc/yp_unicode.c | 10 +- src/main/c/yarp/src/node.c | 1960 ++++---- src/main/c/yarp/src/prettyprint.c | 638 ++- src/main/c/yarp/src/serialize.c | 901 ++-- src/main/c/yarp/src/unescape.c | 63 +- src/main/c/yarp/src/util/yp_char.c | 75 +- src/main/c/yarp/src/util/yp_constant_pool.c | 121 +- src/main/c/yarp/src/yarp.c | 4080 +++++++++------- .../java/org/yarp/AbstractNodeVisitor.java | 38 +- src/yarp/java/org/yarp/Loader.java | 402 +- src/yarp/java/org/yarp/Nodes.java | 4120 ++++++++++++++--- 22 files changed, 9076 insertions(+), 4714 deletions(-) diff --git a/src/main/c/yarp/.gitignore b/src/main/c/yarp/.gitignore index 3c059f27c105..af3c4d0e4543 100644 --- a/src/main/c/yarp/.gitignore +++ b/src/main/c/yarp/.gitignore @@ -6,7 +6,6 @@ /doc/ /pkg/ /spec/reports/ -/test/serialized/ /top-100-gems/ /tmp/ /vendor/bundle diff --git a/src/main/c/yarp/include/yarp/ast.h b/src/main/c/yarp/include/yarp/ast.h index 934c69bca8b0..237f64dbc320 100644 --- a/src/main/c/yarp/include/yarp/ast.h +++ b/src/main/c/yarp/include/yarp/ast.h @@ -199,12 +199,6 @@ typedef struct { const uint8_t *end; } yp_location_t; -typedef struct { - yp_location_t *locations; - size_t size; - size_t capacity; -} yp_location_list_t; - struct yp_node; typedef struct yp_node_list { @@ -214,141 +208,148 @@ typedef struct yp_node_list { } yp_node_list_t; enum yp_node_type { - YP_NODE_ALIAS_NODE = 1, - YP_NODE_ALTERNATION_PATTERN_NODE = 2, - YP_NODE_AND_NODE = 3, - YP_NODE_ARGUMENTS_NODE = 4, - YP_NODE_ARRAY_NODE = 5, - YP_NODE_ARRAY_PATTERN_NODE = 6, - YP_NODE_ASSOC_NODE = 7, - YP_NODE_ASSOC_SPLAT_NODE = 8, - YP_NODE_BACK_REFERENCE_READ_NODE = 9, - YP_NODE_BEGIN_NODE = 10, - YP_NODE_BLOCK_ARGUMENT_NODE = 11, - YP_NODE_BLOCK_NODE = 12, - YP_NODE_BLOCK_PARAMETER_NODE = 13, - YP_NODE_BLOCK_PARAMETERS_NODE = 14, - YP_NODE_BREAK_NODE = 15, - YP_NODE_CALL_NODE = 16, - YP_NODE_CALL_OPERATOR_AND_WRITE_NODE = 17, - YP_NODE_CALL_OPERATOR_OR_WRITE_NODE = 18, - YP_NODE_CALL_OPERATOR_WRITE_NODE = 19, - YP_NODE_CAPTURE_PATTERN_NODE = 20, - YP_NODE_CASE_NODE = 21, - YP_NODE_CLASS_NODE = 22, - YP_NODE_CLASS_VARIABLE_AND_WRITE_NODE = 23, - YP_NODE_CLASS_VARIABLE_OPERATOR_WRITE_NODE = 24, - YP_NODE_CLASS_VARIABLE_OR_WRITE_NODE = 25, - YP_NODE_CLASS_VARIABLE_READ_NODE = 26, - YP_NODE_CLASS_VARIABLE_TARGET_NODE = 27, - YP_NODE_CLASS_VARIABLE_WRITE_NODE = 28, - YP_NODE_CONSTANT_AND_WRITE_NODE = 29, - YP_NODE_CONSTANT_OPERATOR_WRITE_NODE = 30, - YP_NODE_CONSTANT_OR_WRITE_NODE = 31, - YP_NODE_CONSTANT_PATH_AND_WRITE_NODE = 32, - YP_NODE_CONSTANT_PATH_NODE = 33, - YP_NODE_CONSTANT_PATH_OPERATOR_WRITE_NODE = 34, - YP_NODE_CONSTANT_PATH_OR_WRITE_NODE = 35, - YP_NODE_CONSTANT_PATH_TARGET_NODE = 36, - YP_NODE_CONSTANT_PATH_WRITE_NODE = 37, - YP_NODE_CONSTANT_READ_NODE = 38, - YP_NODE_CONSTANT_TARGET_NODE = 39, - YP_NODE_CONSTANT_WRITE_NODE = 40, - YP_NODE_DEF_NODE = 41, - YP_NODE_DEFINED_NODE = 42, - YP_NODE_ELSE_NODE = 43, - YP_NODE_EMBEDDED_STATEMENTS_NODE = 44, - YP_NODE_EMBEDDED_VARIABLE_NODE = 45, - YP_NODE_ENSURE_NODE = 46, - YP_NODE_FALSE_NODE = 47, - YP_NODE_FIND_PATTERN_NODE = 48, - YP_NODE_FLIP_FLOP_NODE = 49, - YP_NODE_FLOAT_NODE = 50, - YP_NODE_FOR_NODE = 51, - YP_NODE_FORWARDING_ARGUMENTS_NODE = 52, - YP_NODE_FORWARDING_PARAMETER_NODE = 53, - YP_NODE_FORWARDING_SUPER_NODE = 54, - YP_NODE_GLOBAL_VARIABLE_AND_WRITE_NODE = 55, - YP_NODE_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE = 56, - YP_NODE_GLOBAL_VARIABLE_OR_WRITE_NODE = 57, - YP_NODE_GLOBAL_VARIABLE_READ_NODE = 58, - YP_NODE_GLOBAL_VARIABLE_TARGET_NODE = 59, - YP_NODE_GLOBAL_VARIABLE_WRITE_NODE = 60, - YP_NODE_HASH_NODE = 61, - YP_NODE_HASH_PATTERN_NODE = 62, - YP_NODE_IF_NODE = 63, - YP_NODE_IMAGINARY_NODE = 64, - YP_NODE_IN_NODE = 65, - YP_NODE_INSTANCE_VARIABLE_AND_WRITE_NODE = 66, - YP_NODE_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE = 67, - YP_NODE_INSTANCE_VARIABLE_OR_WRITE_NODE = 68, - YP_NODE_INSTANCE_VARIABLE_READ_NODE = 69, - YP_NODE_INSTANCE_VARIABLE_TARGET_NODE = 70, - YP_NODE_INSTANCE_VARIABLE_WRITE_NODE = 71, - YP_NODE_INTEGER_NODE = 72, - YP_NODE_INTERPOLATED_REGULAR_EXPRESSION_NODE = 73, - YP_NODE_INTERPOLATED_STRING_NODE = 74, - YP_NODE_INTERPOLATED_SYMBOL_NODE = 75, - YP_NODE_INTERPOLATED_X_STRING_NODE = 76, - YP_NODE_KEYWORD_HASH_NODE = 77, - YP_NODE_KEYWORD_PARAMETER_NODE = 78, - YP_NODE_KEYWORD_REST_PARAMETER_NODE = 79, - YP_NODE_LAMBDA_NODE = 80, - YP_NODE_LOCAL_VARIABLE_AND_WRITE_NODE = 81, - YP_NODE_LOCAL_VARIABLE_OPERATOR_WRITE_NODE = 82, - YP_NODE_LOCAL_VARIABLE_OR_WRITE_NODE = 83, - YP_NODE_LOCAL_VARIABLE_READ_NODE = 84, - YP_NODE_LOCAL_VARIABLE_TARGET_NODE = 85, - YP_NODE_LOCAL_VARIABLE_WRITE_NODE = 86, - YP_NODE_MATCH_PREDICATE_NODE = 87, - YP_NODE_MATCH_REQUIRED_NODE = 88, - YP_NODE_MISSING_NODE = 89, - YP_NODE_MODULE_NODE = 90, - YP_NODE_MULTI_WRITE_NODE = 91, - YP_NODE_NEXT_NODE = 92, - YP_NODE_NIL_NODE = 93, - YP_NODE_NO_KEYWORDS_PARAMETER_NODE = 94, - YP_NODE_NUMBERED_REFERENCE_READ_NODE = 95, - YP_NODE_OPTIONAL_PARAMETER_NODE = 96, - YP_NODE_OR_NODE = 97, - YP_NODE_PARAMETERS_NODE = 98, - YP_NODE_PARENTHESES_NODE = 99, - YP_NODE_PINNED_EXPRESSION_NODE = 100, - YP_NODE_PINNED_VARIABLE_NODE = 101, - YP_NODE_POST_EXECUTION_NODE = 102, - YP_NODE_PRE_EXECUTION_NODE = 103, - YP_NODE_PROGRAM_NODE = 104, - YP_NODE_RANGE_NODE = 105, - YP_NODE_RATIONAL_NODE = 106, - YP_NODE_REDO_NODE = 107, - YP_NODE_REGULAR_EXPRESSION_NODE = 108, - YP_NODE_REQUIRED_DESTRUCTURED_PARAMETER_NODE = 109, - YP_NODE_REQUIRED_PARAMETER_NODE = 110, - YP_NODE_RESCUE_MODIFIER_NODE = 111, - YP_NODE_RESCUE_NODE = 112, - YP_NODE_REST_PARAMETER_NODE = 113, - YP_NODE_RETRY_NODE = 114, - YP_NODE_RETURN_NODE = 115, - YP_NODE_SELF_NODE = 116, - YP_NODE_SINGLETON_CLASS_NODE = 117, - YP_NODE_SOURCE_ENCODING_NODE = 118, - YP_NODE_SOURCE_FILE_NODE = 119, - YP_NODE_SOURCE_LINE_NODE = 120, - YP_NODE_SPLAT_NODE = 121, - YP_NODE_STATEMENTS_NODE = 122, - YP_NODE_STRING_CONCAT_NODE = 123, - YP_NODE_STRING_NODE = 124, - YP_NODE_SUPER_NODE = 125, - YP_NODE_SYMBOL_NODE = 126, - YP_NODE_TRUE_NODE = 127, - YP_NODE_UNDEF_NODE = 128, - YP_NODE_UNLESS_NODE = 129, - YP_NODE_UNTIL_NODE = 130, - YP_NODE_WHEN_NODE = 131, - YP_NODE_WHILE_NODE = 132, - YP_NODE_X_STRING_NODE = 133, - YP_NODE_YIELD_NODE = 134, - YP_NODE_SCOPE_NODE + YP_ALIAS_GLOBAL_VARIABLE_NODE = 1, + YP_ALIAS_METHOD_NODE = 2, + YP_ALTERNATION_PATTERN_NODE = 3, + YP_AND_NODE = 4, + YP_ARGUMENTS_NODE = 5, + YP_ARRAY_NODE = 6, + YP_ARRAY_PATTERN_NODE = 7, + YP_ASSOC_NODE = 8, + YP_ASSOC_SPLAT_NODE = 9, + YP_BACK_REFERENCE_READ_NODE = 10, + YP_BEGIN_NODE = 11, + YP_BLOCK_ARGUMENT_NODE = 12, + YP_BLOCK_LOCAL_VARIABLE_NODE = 13, + YP_BLOCK_NODE = 14, + YP_BLOCK_PARAMETER_NODE = 15, + YP_BLOCK_PARAMETERS_NODE = 16, + YP_BREAK_NODE = 17, + YP_CALL_AND_WRITE_NODE = 18, + YP_CALL_NODE = 19, + YP_CALL_OPERATOR_WRITE_NODE = 20, + YP_CALL_OR_WRITE_NODE = 21, + YP_CAPTURE_PATTERN_NODE = 22, + YP_CASE_NODE = 23, + YP_CLASS_NODE = 24, + YP_CLASS_VARIABLE_AND_WRITE_NODE = 25, + YP_CLASS_VARIABLE_OPERATOR_WRITE_NODE = 26, + YP_CLASS_VARIABLE_OR_WRITE_NODE = 27, + YP_CLASS_VARIABLE_READ_NODE = 28, + YP_CLASS_VARIABLE_TARGET_NODE = 29, + YP_CLASS_VARIABLE_WRITE_NODE = 30, + YP_CONSTANT_AND_WRITE_NODE = 31, + YP_CONSTANT_OPERATOR_WRITE_NODE = 32, + YP_CONSTANT_OR_WRITE_NODE = 33, + YP_CONSTANT_PATH_AND_WRITE_NODE = 34, + YP_CONSTANT_PATH_NODE = 35, + YP_CONSTANT_PATH_OPERATOR_WRITE_NODE = 36, + YP_CONSTANT_PATH_OR_WRITE_NODE = 37, + YP_CONSTANT_PATH_TARGET_NODE = 38, + YP_CONSTANT_PATH_WRITE_NODE = 39, + YP_CONSTANT_READ_NODE = 40, + YP_CONSTANT_TARGET_NODE = 41, + YP_CONSTANT_WRITE_NODE = 42, + YP_DEF_NODE = 43, + YP_DEFINED_NODE = 44, + YP_ELSE_NODE = 45, + YP_EMBEDDED_STATEMENTS_NODE = 46, + YP_EMBEDDED_VARIABLE_NODE = 47, + YP_ENSURE_NODE = 48, + YP_FALSE_NODE = 49, + YP_FIND_PATTERN_NODE = 50, + YP_FLIP_FLOP_NODE = 51, + YP_FLOAT_NODE = 52, + YP_FOR_NODE = 53, + YP_FORWARDING_ARGUMENTS_NODE = 54, + YP_FORWARDING_PARAMETER_NODE = 55, + YP_FORWARDING_SUPER_NODE = 56, + YP_GLOBAL_VARIABLE_AND_WRITE_NODE = 57, + YP_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE = 58, + YP_GLOBAL_VARIABLE_OR_WRITE_NODE = 59, + YP_GLOBAL_VARIABLE_READ_NODE = 60, + YP_GLOBAL_VARIABLE_TARGET_NODE = 61, + YP_GLOBAL_VARIABLE_WRITE_NODE = 62, + YP_HASH_NODE = 63, + YP_HASH_PATTERN_NODE = 64, + YP_IF_NODE = 65, + YP_IMAGINARY_NODE = 66, + YP_IMPLICIT_NODE = 67, + YP_IN_NODE = 68, + YP_INSTANCE_VARIABLE_AND_WRITE_NODE = 69, + YP_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE = 70, + YP_INSTANCE_VARIABLE_OR_WRITE_NODE = 71, + YP_INSTANCE_VARIABLE_READ_NODE = 72, + YP_INSTANCE_VARIABLE_TARGET_NODE = 73, + YP_INSTANCE_VARIABLE_WRITE_NODE = 74, + YP_INTEGER_NODE = 75, + YP_INTERPOLATED_MATCH_LAST_LINE_NODE = 76, + YP_INTERPOLATED_REGULAR_EXPRESSION_NODE = 77, + YP_INTERPOLATED_STRING_NODE = 78, + YP_INTERPOLATED_SYMBOL_NODE = 79, + YP_INTERPOLATED_X_STRING_NODE = 80, + YP_KEYWORD_HASH_NODE = 81, + YP_KEYWORD_PARAMETER_NODE = 82, + YP_KEYWORD_REST_PARAMETER_NODE = 83, + YP_LAMBDA_NODE = 84, + YP_LOCAL_VARIABLE_AND_WRITE_NODE = 85, + YP_LOCAL_VARIABLE_OPERATOR_WRITE_NODE = 86, + YP_LOCAL_VARIABLE_OR_WRITE_NODE = 87, + YP_LOCAL_VARIABLE_READ_NODE = 88, + YP_LOCAL_VARIABLE_TARGET_NODE = 89, + YP_LOCAL_VARIABLE_WRITE_NODE = 90, + YP_MATCH_LAST_LINE_NODE = 91, + YP_MATCH_PREDICATE_NODE = 92, + YP_MATCH_REQUIRED_NODE = 93, + YP_MATCH_WRITE_NODE = 94, + YP_MISSING_NODE = 95, + YP_MODULE_NODE = 96, + YP_MULTI_TARGET_NODE = 97, + YP_MULTI_WRITE_NODE = 98, + YP_NEXT_NODE = 99, + YP_NIL_NODE = 100, + YP_NO_KEYWORDS_PARAMETER_NODE = 101, + YP_NUMBERED_REFERENCE_READ_NODE = 102, + YP_OPTIONAL_PARAMETER_NODE = 103, + YP_OR_NODE = 104, + YP_PARAMETERS_NODE = 105, + YP_PARENTHESES_NODE = 106, + YP_PINNED_EXPRESSION_NODE = 107, + YP_PINNED_VARIABLE_NODE = 108, + YP_POST_EXECUTION_NODE = 109, + YP_PRE_EXECUTION_NODE = 110, + YP_PROGRAM_NODE = 111, + YP_RANGE_NODE = 112, + YP_RATIONAL_NODE = 113, + YP_REDO_NODE = 114, + YP_REGULAR_EXPRESSION_NODE = 115, + YP_REQUIRED_DESTRUCTURED_PARAMETER_NODE = 116, + YP_REQUIRED_PARAMETER_NODE = 117, + YP_RESCUE_MODIFIER_NODE = 118, + YP_RESCUE_NODE = 119, + YP_REST_PARAMETER_NODE = 120, + YP_RETRY_NODE = 121, + YP_RETURN_NODE = 122, + YP_SELF_NODE = 123, + YP_SINGLETON_CLASS_NODE = 124, + YP_SOURCE_ENCODING_NODE = 125, + YP_SOURCE_FILE_NODE = 126, + YP_SOURCE_LINE_NODE = 127, + YP_SPLAT_NODE = 128, + YP_STATEMENTS_NODE = 129, + YP_STRING_CONCAT_NODE = 130, + YP_STRING_NODE = 131, + YP_SUPER_NODE = 132, + YP_SYMBOL_NODE = 133, + YP_TRUE_NODE = 134, + YP_UNDEF_NODE = 135, + YP_UNLESS_NODE = 136, + YP_UNTIL_NODE = 137, + YP_WHEN_NODE = 138, + YP_WHILE_NODE = 139, + YP_X_STRING_NODE = 140, + YP_YIELD_NODE = 141, + YP_SCOPE_NODE }; typedef uint16_t yp_node_type_t; @@ -357,6 +358,7 @@ typedef uint16_t yp_node_flags_t; // We store the flags enum in every node in the tree. Some flags are common to // all nodes (the ones listed below). Others are specific to certain node types. static const yp_node_flags_t YP_NODE_FLAG_NEWLINE = 0x1; +static const yp_node_flags_t YP_NODE_FLAG_STATIC_LITERAL = 0x2; // For easy access, we define some macros to check node type #define YP_NODE_TYPE(node) ((enum yp_node_type)node->type) @@ -376,19 +378,29 @@ typedef struct yp_node { yp_location_t location; } yp_node_t; -// AliasNode +// AliasGlobalVariableNode +// +// Type: YP_ALIAS_GLOBAL_VARIABLE_NODE +typedef struct yp_alias_global_variable_node { + yp_node_t base; + struct yp_node *new_name; + struct yp_node *old_name; + yp_location_t keyword_loc; +} yp_alias_global_variable_node_t; + +// AliasMethodNode // -// Type: YP_NODE_ALIAS_NODE -typedef struct yp_alias_node { +// Type: YP_ALIAS_METHOD_NODE +typedef struct yp_alias_method_node { yp_node_t base; struct yp_node *new_name; struct yp_node *old_name; yp_location_t keyword_loc; -} yp_alias_node_t; +} yp_alias_method_node_t; // AlternationPatternNode // -// Type: YP_NODE_ALTERNATION_PATTERN_NODE +// Type: YP_ALTERNATION_PATTERN_NODE typedef struct yp_alternation_pattern_node { yp_node_t base; struct yp_node *left; @@ -398,7 +410,7 @@ typedef struct yp_alternation_pattern_node { // AndNode // -// Type: YP_NODE_AND_NODE +// Type: YP_AND_NODE typedef struct yp_and_node { yp_node_t base; struct yp_node *left; @@ -408,7 +420,7 @@ typedef struct yp_and_node { // ArgumentsNode // -// Type: YP_NODE_ARGUMENTS_NODE +// Type: YP_ARGUMENTS_NODE typedef struct yp_arguments_node { yp_node_t base; struct yp_node_list arguments; @@ -416,7 +428,7 @@ typedef struct yp_arguments_node { // ArrayNode // -// Type: YP_NODE_ARRAY_NODE +// Type: YP_ARRAY_NODE typedef struct yp_array_node { yp_node_t base; struct yp_node_list elements; @@ -426,7 +438,7 @@ typedef struct yp_array_node { // ArrayPatternNode // -// Type: YP_NODE_ARRAY_PATTERN_NODE +// Type: YP_ARRAY_PATTERN_NODE typedef struct yp_array_pattern_node { yp_node_t base; struct yp_node *constant; @@ -439,7 +451,7 @@ typedef struct yp_array_pattern_node { // AssocNode // -// Type: YP_NODE_ASSOC_NODE +// Type: YP_ASSOC_NODE typedef struct yp_assoc_node { yp_node_t base; struct yp_node *key; @@ -449,7 +461,7 @@ typedef struct yp_assoc_node { // AssocSplatNode // -// Type: YP_NODE_ASSOC_SPLAT_NODE +// Type: YP_ASSOC_SPLAT_NODE typedef struct yp_assoc_splat_node { yp_node_t base; struct yp_node *value; @@ -458,14 +470,14 @@ typedef struct yp_assoc_splat_node { // BackReferenceReadNode // -// Type: YP_NODE_BACK_REFERENCE_READ_NODE +// Type: YP_BACK_REFERENCE_READ_NODE typedef struct yp_back_reference_read_node { yp_node_t base; } yp_back_reference_read_node_t; // BeginNode // -// Type: YP_NODE_BEGIN_NODE +// Type: YP_BEGIN_NODE typedef struct yp_begin_node { yp_node_t base; yp_location_t begin_keyword_loc; @@ -478,16 +490,24 @@ typedef struct yp_begin_node { // BlockArgumentNode // -// Type: YP_NODE_BLOCK_ARGUMENT_NODE +// Type: YP_BLOCK_ARGUMENT_NODE typedef struct yp_block_argument_node { yp_node_t base; struct yp_node *expression; yp_location_t operator_loc; } yp_block_argument_node_t; +// BlockLocalVariableNode +// +// Type: YP_BLOCK_LOCAL_VARIABLE_NODE +typedef struct yp_block_local_variable_node { + yp_node_t base; + yp_constant_id_t name; +} yp_block_local_variable_node_t; + // BlockNode // -// Type: YP_NODE_BLOCK_NODE +// Type: YP_BLOCK_NODE typedef struct yp_block_node { yp_node_t base; yp_constant_id_list_t locals; @@ -499,85 +519,116 @@ typedef struct yp_block_node { // BlockParameterNode // -// Type: YP_NODE_BLOCK_PARAMETER_NODE +// Type: YP_BLOCK_PARAMETER_NODE typedef struct yp_block_parameter_node { yp_node_t base; + yp_constant_id_t name; yp_location_t name_loc; yp_location_t operator_loc; } yp_block_parameter_node_t; // BlockParametersNode // -// Type: YP_NODE_BLOCK_PARAMETERS_NODE +// Type: YP_BLOCK_PARAMETERS_NODE typedef struct yp_block_parameters_node { yp_node_t base; struct yp_parameters_node *parameters; - yp_location_list_t locals; + struct yp_node_list locals; yp_location_t opening_loc; yp_location_t closing_loc; } yp_block_parameters_node_t; // BreakNode // -// Type: YP_NODE_BREAK_NODE +// Type: YP_BREAK_NODE typedef struct yp_break_node { yp_node_t base; struct yp_arguments_node *arguments; yp_location_t keyword_loc; } yp_break_node_t; +// CallAndWriteNode +// +// Type: YP_CALL_AND_WRITE_NODE +// Flags: +// YP_CALL_NODE_FLAGS_SAFE_NAVIGATION +// YP_CALL_NODE_FLAGS_VARIABLE_CALL +typedef struct yp_call_and_write_node { + yp_node_t base; + struct yp_node *receiver; + yp_location_t call_operator_loc; + yp_location_t message_loc; + yp_location_t opening_loc; + struct yp_arguments_node *arguments; + yp_location_t closing_loc; + yp_string_t read_name; + yp_string_t write_name; + yp_location_t operator_loc; + struct yp_node *value; +} yp_call_and_write_node_t; + // CallNode // -// Type: YP_NODE_CALL_NODE +// Type: YP_CALL_NODE // Flags: // YP_CALL_NODE_FLAGS_SAFE_NAVIGATION // YP_CALL_NODE_FLAGS_VARIABLE_CALL typedef struct yp_call_node { yp_node_t base; struct yp_node *receiver; - yp_location_t operator_loc; + yp_location_t call_operator_loc; yp_location_t message_loc; yp_location_t opening_loc; struct yp_arguments_node *arguments; yp_location_t closing_loc; - struct yp_block_node *block; + struct yp_node *block; yp_string_t name; } yp_call_node_t; -// CallOperatorAndWriteNode +// CallOperatorWriteNode // -// Type: YP_NODE_CALL_OPERATOR_AND_WRITE_NODE -typedef struct yp_call_operator_and_write_node { +// Type: YP_CALL_OPERATOR_WRITE_NODE +// Flags: +// YP_CALL_NODE_FLAGS_SAFE_NAVIGATION +// YP_CALL_NODE_FLAGS_VARIABLE_CALL +typedef struct yp_call_operator_write_node { yp_node_t base; - struct yp_call_node *target; + struct yp_node *receiver; + yp_location_t call_operator_loc; + yp_location_t message_loc; + yp_location_t opening_loc; + struct yp_arguments_node *arguments; + yp_location_t closing_loc; + yp_string_t read_name; + yp_string_t write_name; + yp_constant_id_t operator; yp_location_t operator_loc; struct yp_node *value; -} yp_call_operator_and_write_node_t; - -// CallOperatorOrWriteNode -// -// Type: YP_NODE_CALL_OPERATOR_OR_WRITE_NODE -typedef struct yp_call_operator_or_write_node { - yp_node_t base; - struct yp_call_node *target; - struct yp_node *value; - yp_location_t operator_loc; -} yp_call_operator_or_write_node_t; +} yp_call_operator_write_node_t; -// CallOperatorWriteNode +// CallOrWriteNode // -// Type: YP_NODE_CALL_OPERATOR_WRITE_NODE -typedef struct yp_call_operator_write_node { +// Type: YP_CALL_OR_WRITE_NODE +// Flags: +// YP_CALL_NODE_FLAGS_SAFE_NAVIGATION +// YP_CALL_NODE_FLAGS_VARIABLE_CALL +typedef struct yp_call_or_write_node { yp_node_t base; - struct yp_call_node *target; + struct yp_node *receiver; + yp_location_t call_operator_loc; + yp_location_t message_loc; + yp_location_t opening_loc; + struct yp_arguments_node *arguments; + yp_location_t closing_loc; + yp_string_t read_name; + yp_string_t write_name; yp_location_t operator_loc; struct yp_node *value; - yp_constant_id_t operator; -} yp_call_operator_write_node_t; +} yp_call_or_write_node_t; // CapturePatternNode // -// Type: YP_NODE_CAPTURE_PATTERN_NODE +// Type: YP_CAPTURE_PATTERN_NODE typedef struct yp_capture_pattern_node { yp_node_t base; struct yp_node *value; @@ -587,7 +638,7 @@ typedef struct yp_capture_pattern_node { // CaseNode // -// Type: YP_NODE_CASE_NODE +// Type: YP_CASE_NODE typedef struct yp_case_node { yp_node_t base; struct yp_node *predicate; @@ -599,7 +650,7 @@ typedef struct yp_case_node { // ClassNode // -// Type: YP_NODE_CLASS_NODE +// Type: YP_CLASS_NODE typedef struct yp_class_node { yp_node_t base; yp_constant_id_list_t locals; @@ -609,12 +660,12 @@ typedef struct yp_class_node { struct yp_node *superclass; struct yp_node *body; yp_location_t end_keyword_loc; - yp_string_t name; + yp_constant_id_t name; } yp_class_node_t; // ClassVariableAndWriteNode // -// Type: YP_NODE_CLASS_VARIABLE_AND_WRITE_NODE +// Type: YP_CLASS_VARIABLE_AND_WRITE_NODE typedef struct yp_class_variable_and_write_node { yp_node_t base; yp_constant_id_t name; @@ -625,7 +676,7 @@ typedef struct yp_class_variable_and_write_node { // ClassVariableOperatorWriteNode // -// Type: YP_NODE_CLASS_VARIABLE_OPERATOR_WRITE_NODE +// Type: YP_CLASS_VARIABLE_OPERATOR_WRITE_NODE typedef struct yp_class_variable_operator_write_node { yp_node_t base; yp_constant_id_t name; @@ -637,7 +688,7 @@ typedef struct yp_class_variable_operator_write_node { // ClassVariableOrWriteNode // -// Type: YP_NODE_CLASS_VARIABLE_OR_WRITE_NODE +// Type: YP_CLASS_VARIABLE_OR_WRITE_NODE typedef struct yp_class_variable_or_write_node { yp_node_t base; yp_constant_id_t name; @@ -648,7 +699,7 @@ typedef struct yp_class_variable_or_write_node { // ClassVariableReadNode // -// Type: YP_NODE_CLASS_VARIABLE_READ_NODE +// Type: YP_CLASS_VARIABLE_READ_NODE typedef struct yp_class_variable_read_node { yp_node_t base; yp_constant_id_t name; @@ -656,7 +707,7 @@ typedef struct yp_class_variable_read_node { // ClassVariableTargetNode // -// Type: YP_NODE_CLASS_VARIABLE_TARGET_NODE +// Type: YP_CLASS_VARIABLE_TARGET_NODE typedef struct yp_class_variable_target_node { yp_node_t base; yp_constant_id_t name; @@ -664,7 +715,7 @@ typedef struct yp_class_variable_target_node { // ClassVariableWriteNode // -// Type: YP_NODE_CLASS_VARIABLE_WRITE_NODE +// Type: YP_CLASS_VARIABLE_WRITE_NODE typedef struct yp_class_variable_write_node { yp_node_t base; yp_constant_id_t name; @@ -675,9 +726,10 @@ typedef struct yp_class_variable_write_node { // ConstantAndWriteNode // -// Type: YP_NODE_CONSTANT_AND_WRITE_NODE +// Type: YP_CONSTANT_AND_WRITE_NODE typedef struct yp_constant_and_write_node { yp_node_t base; + yp_constant_id_t name; yp_location_t name_loc; yp_location_t operator_loc; struct yp_node *value; @@ -685,9 +737,10 @@ typedef struct yp_constant_and_write_node { // ConstantOperatorWriteNode // -// Type: YP_NODE_CONSTANT_OPERATOR_WRITE_NODE +// Type: YP_CONSTANT_OPERATOR_WRITE_NODE typedef struct yp_constant_operator_write_node { yp_node_t base; + yp_constant_id_t name; yp_location_t name_loc; yp_location_t operator_loc; struct yp_node *value; @@ -696,9 +749,10 @@ typedef struct yp_constant_operator_write_node { // ConstantOrWriteNode // -// Type: YP_NODE_CONSTANT_OR_WRITE_NODE +// Type: YP_CONSTANT_OR_WRITE_NODE typedef struct yp_constant_or_write_node { yp_node_t base; + yp_constant_id_t name; yp_location_t name_loc; yp_location_t operator_loc; struct yp_node *value; @@ -706,7 +760,7 @@ typedef struct yp_constant_or_write_node { // ConstantPathAndWriteNode // -// Type: YP_NODE_CONSTANT_PATH_AND_WRITE_NODE +// Type: YP_CONSTANT_PATH_AND_WRITE_NODE typedef struct yp_constant_path_and_write_node { yp_node_t base; struct yp_constant_path_node *target; @@ -716,7 +770,7 @@ typedef struct yp_constant_path_and_write_node { // ConstantPathNode // -// Type: YP_NODE_CONSTANT_PATH_NODE +// Type: YP_CONSTANT_PATH_NODE typedef struct yp_constant_path_node { yp_node_t base; struct yp_node *parent; @@ -726,7 +780,7 @@ typedef struct yp_constant_path_node { // ConstantPathOperatorWriteNode // -// Type: YP_NODE_CONSTANT_PATH_OPERATOR_WRITE_NODE +// Type: YP_CONSTANT_PATH_OPERATOR_WRITE_NODE typedef struct yp_constant_path_operator_write_node { yp_node_t base; struct yp_constant_path_node *target; @@ -737,7 +791,7 @@ typedef struct yp_constant_path_operator_write_node { // ConstantPathOrWriteNode // -// Type: YP_NODE_CONSTANT_PATH_OR_WRITE_NODE +// Type: YP_CONSTANT_PATH_OR_WRITE_NODE typedef struct yp_constant_path_or_write_node { yp_node_t base; struct yp_constant_path_node *target; @@ -747,7 +801,7 @@ typedef struct yp_constant_path_or_write_node { // ConstantPathTargetNode // -// Type: YP_NODE_CONSTANT_PATH_TARGET_NODE +// Type: YP_CONSTANT_PATH_TARGET_NODE typedef struct yp_constant_path_target_node { yp_node_t base; struct yp_node *parent; @@ -757,7 +811,7 @@ typedef struct yp_constant_path_target_node { // ConstantPathWriteNode // -// Type: YP_NODE_CONSTANT_PATH_WRITE_NODE +// Type: YP_CONSTANT_PATH_WRITE_NODE typedef struct yp_constant_path_write_node { yp_node_t base; struct yp_constant_path_node *target; @@ -767,23 +821,26 @@ typedef struct yp_constant_path_write_node { // ConstantReadNode // -// Type: YP_NODE_CONSTANT_READ_NODE +// Type: YP_CONSTANT_READ_NODE typedef struct yp_constant_read_node { yp_node_t base; + yp_constant_id_t name; } yp_constant_read_node_t; // ConstantTargetNode // -// Type: YP_NODE_CONSTANT_TARGET_NODE +// Type: YP_CONSTANT_TARGET_NODE typedef struct yp_constant_target_node { yp_node_t base; + yp_constant_id_t name; } yp_constant_target_node_t; // ConstantWriteNode // -// Type: YP_NODE_CONSTANT_WRITE_NODE +// Type: YP_CONSTANT_WRITE_NODE typedef struct yp_constant_write_node { yp_node_t base; + yp_constant_id_t name; yp_location_t name_loc; struct yp_node *value; yp_location_t operator_loc; @@ -791,9 +848,10 @@ typedef struct yp_constant_write_node { // DefNode // -// Type: YP_NODE_DEF_NODE +// Type: YP_DEF_NODE typedef struct yp_def_node { yp_node_t base; + yp_constant_id_t name; yp_location_t name_loc; struct yp_node *receiver; struct yp_parameters_node *parameters; @@ -809,7 +867,7 @@ typedef struct yp_def_node { // DefinedNode // -// Type: YP_NODE_DEFINED_NODE +// Type: YP_DEFINED_NODE typedef struct yp_defined_node { yp_node_t base; yp_location_t lparen_loc; @@ -820,7 +878,7 @@ typedef struct yp_defined_node { // ElseNode // -// Type: YP_NODE_ELSE_NODE +// Type: YP_ELSE_NODE typedef struct yp_else_node { yp_node_t base; yp_location_t else_keyword_loc; @@ -830,7 +888,7 @@ typedef struct yp_else_node { // EmbeddedStatementsNode // -// Type: YP_NODE_EMBEDDED_STATEMENTS_NODE +// Type: YP_EMBEDDED_STATEMENTS_NODE typedef struct yp_embedded_statements_node { yp_node_t base; yp_location_t opening_loc; @@ -840,7 +898,7 @@ typedef struct yp_embedded_statements_node { // EmbeddedVariableNode // -// Type: YP_NODE_EMBEDDED_VARIABLE_NODE +// Type: YP_EMBEDDED_VARIABLE_NODE typedef struct yp_embedded_variable_node { yp_node_t base; yp_location_t operator_loc; @@ -849,7 +907,7 @@ typedef struct yp_embedded_variable_node { // EnsureNode // -// Type: YP_NODE_ENSURE_NODE +// Type: YP_ENSURE_NODE typedef struct yp_ensure_node { yp_node_t base; yp_location_t ensure_keyword_loc; @@ -859,14 +917,14 @@ typedef struct yp_ensure_node { // FalseNode // -// Type: YP_NODE_FALSE_NODE +// Type: YP_FALSE_NODE typedef struct yp_false_node { yp_node_t base; } yp_false_node_t; // FindPatternNode // -// Type: YP_NODE_FIND_PATTERN_NODE +// Type: YP_FIND_PATTERN_NODE typedef struct yp_find_pattern_node { yp_node_t base; struct yp_node *constant; @@ -879,7 +937,7 @@ typedef struct yp_find_pattern_node { // FlipFlopNode // -// Type: YP_NODE_FLIP_FLOP_NODE +// Type: YP_FLIP_FLOP_NODE // Flags: // YP_RANGE_FLAGS_EXCLUDE_END typedef struct yp_flip_flop_node { @@ -891,14 +949,14 @@ typedef struct yp_flip_flop_node { // FloatNode // -// Type: YP_NODE_FLOAT_NODE +// Type: YP_FLOAT_NODE typedef struct yp_float_node { yp_node_t base; } yp_float_node_t; // ForNode // -// Type: YP_NODE_FOR_NODE +// Type: YP_FOR_NODE typedef struct yp_for_node { yp_node_t base; struct yp_node *index; @@ -912,21 +970,21 @@ typedef struct yp_for_node { // ForwardingArgumentsNode // -// Type: YP_NODE_FORWARDING_ARGUMENTS_NODE +// Type: YP_FORWARDING_ARGUMENTS_NODE typedef struct yp_forwarding_arguments_node { yp_node_t base; } yp_forwarding_arguments_node_t; // ForwardingParameterNode // -// Type: YP_NODE_FORWARDING_PARAMETER_NODE +// Type: YP_FORWARDING_PARAMETER_NODE typedef struct yp_forwarding_parameter_node { yp_node_t base; } yp_forwarding_parameter_node_t; // ForwardingSuperNode // -// Type: YP_NODE_FORWARDING_SUPER_NODE +// Type: YP_FORWARDING_SUPER_NODE typedef struct yp_forwarding_super_node { yp_node_t base; struct yp_block_node *block; @@ -934,7 +992,7 @@ typedef struct yp_forwarding_super_node { // GlobalVariableAndWriteNode // -// Type: YP_NODE_GLOBAL_VARIABLE_AND_WRITE_NODE +// Type: YP_GLOBAL_VARIABLE_AND_WRITE_NODE typedef struct yp_global_variable_and_write_node { yp_node_t base; yp_constant_id_t name; @@ -945,7 +1003,7 @@ typedef struct yp_global_variable_and_write_node { // GlobalVariableOperatorWriteNode // -// Type: YP_NODE_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE +// Type: YP_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE typedef struct yp_global_variable_operator_write_node { yp_node_t base; yp_constant_id_t name; @@ -957,7 +1015,7 @@ typedef struct yp_global_variable_operator_write_node { // GlobalVariableOrWriteNode // -// Type: YP_NODE_GLOBAL_VARIABLE_OR_WRITE_NODE +// Type: YP_GLOBAL_VARIABLE_OR_WRITE_NODE typedef struct yp_global_variable_or_write_node { yp_node_t base; yp_constant_id_t name; @@ -968,7 +1026,7 @@ typedef struct yp_global_variable_or_write_node { // GlobalVariableReadNode // -// Type: YP_NODE_GLOBAL_VARIABLE_READ_NODE +// Type: YP_GLOBAL_VARIABLE_READ_NODE typedef struct yp_global_variable_read_node { yp_node_t base; yp_constant_id_t name; @@ -976,7 +1034,7 @@ typedef struct yp_global_variable_read_node { // GlobalVariableTargetNode // -// Type: YP_NODE_GLOBAL_VARIABLE_TARGET_NODE +// Type: YP_GLOBAL_VARIABLE_TARGET_NODE typedef struct yp_global_variable_target_node { yp_node_t base; yp_constant_id_t name; @@ -984,7 +1042,7 @@ typedef struct yp_global_variable_target_node { // GlobalVariableWriteNode // -// Type: YP_NODE_GLOBAL_VARIABLE_WRITE_NODE +// Type: YP_GLOBAL_VARIABLE_WRITE_NODE typedef struct yp_global_variable_write_node { yp_node_t base; yp_constant_id_t name; @@ -995,7 +1053,7 @@ typedef struct yp_global_variable_write_node { // HashNode // -// Type: YP_NODE_HASH_NODE +// Type: YP_HASH_NODE typedef struct yp_hash_node { yp_node_t base; yp_location_t opening_loc; @@ -1005,7 +1063,7 @@ typedef struct yp_hash_node { // HashPatternNode // -// Type: YP_NODE_HASH_PATTERN_NODE +// Type: YP_HASH_PATTERN_NODE typedef struct yp_hash_pattern_node { yp_node_t base; struct yp_node *constant; @@ -1017,7 +1075,7 @@ typedef struct yp_hash_pattern_node { // IfNode // -// Type: YP_NODE_IF_NODE +// Type: YP_IF_NODE typedef struct yp_if_node { yp_node_t base; yp_location_t if_keyword_loc; @@ -1029,15 +1087,23 @@ typedef struct yp_if_node { // ImaginaryNode // -// Type: YP_NODE_IMAGINARY_NODE +// Type: YP_IMAGINARY_NODE typedef struct yp_imaginary_node { yp_node_t base; struct yp_node *numeric; } yp_imaginary_node_t; +// ImplicitNode +// +// Type: YP_IMPLICIT_NODE +typedef struct yp_implicit_node { + yp_node_t base; + struct yp_node *value; +} yp_implicit_node_t; + // InNode // -// Type: YP_NODE_IN_NODE +// Type: YP_IN_NODE typedef struct yp_in_node { yp_node_t base; struct yp_node *pattern; @@ -1048,7 +1114,7 @@ typedef struct yp_in_node { // InstanceVariableAndWriteNode // -// Type: YP_NODE_INSTANCE_VARIABLE_AND_WRITE_NODE +// Type: YP_INSTANCE_VARIABLE_AND_WRITE_NODE typedef struct yp_instance_variable_and_write_node { yp_node_t base; yp_constant_id_t name; @@ -1059,7 +1125,7 @@ typedef struct yp_instance_variable_and_write_node { // InstanceVariableOperatorWriteNode // -// Type: YP_NODE_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE +// Type: YP_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE typedef struct yp_instance_variable_operator_write_node { yp_node_t base; yp_constant_id_t name; @@ -1071,7 +1137,7 @@ typedef struct yp_instance_variable_operator_write_node { // InstanceVariableOrWriteNode // -// Type: YP_NODE_INSTANCE_VARIABLE_OR_WRITE_NODE +// Type: YP_INSTANCE_VARIABLE_OR_WRITE_NODE typedef struct yp_instance_variable_or_write_node { yp_node_t base; yp_constant_id_t name; @@ -1082,7 +1148,7 @@ typedef struct yp_instance_variable_or_write_node { // InstanceVariableReadNode // -// Type: YP_NODE_INSTANCE_VARIABLE_READ_NODE +// Type: YP_INSTANCE_VARIABLE_READ_NODE typedef struct yp_instance_variable_read_node { yp_node_t base; yp_constant_id_t name; @@ -1090,7 +1156,7 @@ typedef struct yp_instance_variable_read_node { // InstanceVariableTargetNode // -// Type: YP_NODE_INSTANCE_VARIABLE_TARGET_NODE +// Type: YP_INSTANCE_VARIABLE_TARGET_NODE typedef struct yp_instance_variable_target_node { yp_node_t base; yp_constant_id_t name; @@ -1098,7 +1164,7 @@ typedef struct yp_instance_variable_target_node { // InstanceVariableWriteNode // -// Type: YP_NODE_INSTANCE_VARIABLE_WRITE_NODE +// Type: YP_INSTANCE_VARIABLE_WRITE_NODE typedef struct yp_instance_variable_write_node { yp_node_t base; yp_constant_id_t name; @@ -1109,18 +1175,42 @@ typedef struct yp_instance_variable_write_node { // IntegerNode // -// Type: YP_NODE_INTEGER_NODE +// Type: YP_INTEGER_NODE +// Flags: +// YP_INTEGER_BASE_FLAGS_BINARY +// YP_INTEGER_BASE_FLAGS_OCTAL +// YP_INTEGER_BASE_FLAGS_DECIMAL +// YP_INTEGER_BASE_FLAGS_HEXADECIMAL typedef struct yp_integer_node { yp_node_t base; } yp_integer_node_t; -// InterpolatedRegularExpressionNode +// InterpolatedMatchLastLineNode // -// Type: YP_NODE_INTERPOLATED_REGULAR_EXPRESSION_NODE +// Type: YP_INTERPOLATED_MATCH_LAST_LINE_NODE // Flags: // YP_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE +// YP_REGULAR_EXPRESSION_FLAGS_EXTENDED // YP_REGULAR_EXPRESSION_FLAGS_MULTI_LINE +// YP_REGULAR_EXPRESSION_FLAGS_EUC_JP +// YP_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT +// YP_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J +// YP_REGULAR_EXPRESSION_FLAGS_UTF_8 +// YP_REGULAR_EXPRESSION_FLAGS_ONCE +typedef struct yp_interpolated_match_last_line_node { + yp_node_t base; + yp_location_t opening_loc; + struct yp_node_list parts; + yp_location_t closing_loc; +} yp_interpolated_match_last_line_node_t; + +// InterpolatedRegularExpressionNode +// +// Type: YP_INTERPOLATED_REGULAR_EXPRESSION_NODE +// Flags: +// YP_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE // YP_REGULAR_EXPRESSION_FLAGS_EXTENDED +// YP_REGULAR_EXPRESSION_FLAGS_MULTI_LINE // YP_REGULAR_EXPRESSION_FLAGS_EUC_JP // YP_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT // YP_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J @@ -1135,7 +1225,7 @@ typedef struct yp_interpolated_regular_expression_node { // InterpolatedStringNode // -// Type: YP_NODE_INTERPOLATED_STRING_NODE +// Type: YP_INTERPOLATED_STRING_NODE typedef struct yp_interpolated_string_node { yp_node_t base; yp_location_t opening_loc; @@ -1145,7 +1235,7 @@ typedef struct yp_interpolated_string_node { // InterpolatedSymbolNode // -// Type: YP_NODE_INTERPOLATED_SYMBOL_NODE +// Type: YP_INTERPOLATED_SYMBOL_NODE typedef struct yp_interpolated_symbol_node { yp_node_t base; yp_location_t opening_loc; @@ -1155,7 +1245,7 @@ typedef struct yp_interpolated_symbol_node { // InterpolatedXStringNode // -// Type: YP_NODE_INTERPOLATED_X_STRING_NODE +// Type: YP_INTERPOLATED_X_STRING_NODE typedef struct yp_interpolated_x_string_node { yp_node_t base; yp_location_t opening_loc; @@ -1165,7 +1255,7 @@ typedef struct yp_interpolated_x_string_node { // KeywordHashNode // -// Type: YP_NODE_KEYWORD_HASH_NODE +// Type: YP_KEYWORD_HASH_NODE typedef struct yp_keyword_hash_node { yp_node_t base; struct yp_node_list elements; @@ -1173,25 +1263,27 @@ typedef struct yp_keyword_hash_node { // KeywordParameterNode // -// Type: YP_NODE_KEYWORD_PARAMETER_NODE +// Type: YP_KEYWORD_PARAMETER_NODE typedef struct yp_keyword_parameter_node { yp_node_t base; + yp_constant_id_t name; yp_location_t name_loc; struct yp_node *value; } yp_keyword_parameter_node_t; // KeywordRestParameterNode // -// Type: YP_NODE_KEYWORD_REST_PARAMETER_NODE +// Type: YP_KEYWORD_REST_PARAMETER_NODE typedef struct yp_keyword_rest_parameter_node { yp_node_t base; - yp_location_t operator_loc; + yp_constant_id_t name; yp_location_t name_loc; + yp_location_t operator_loc; } yp_keyword_rest_parameter_node_t; // LambdaNode // -// Type: YP_NODE_LAMBDA_NODE +// Type: YP_LAMBDA_NODE typedef struct yp_lambda_node { yp_node_t base; yp_constant_id_list_t locals; @@ -1204,7 +1296,7 @@ typedef struct yp_lambda_node { // LocalVariableAndWriteNode // -// Type: YP_NODE_LOCAL_VARIABLE_AND_WRITE_NODE +// Type: YP_LOCAL_VARIABLE_AND_WRITE_NODE typedef struct yp_local_variable_and_write_node { yp_node_t base; yp_location_t name_loc; @@ -1216,7 +1308,7 @@ typedef struct yp_local_variable_and_write_node { // LocalVariableOperatorWriteNode // -// Type: YP_NODE_LOCAL_VARIABLE_OPERATOR_WRITE_NODE +// Type: YP_LOCAL_VARIABLE_OPERATOR_WRITE_NODE typedef struct yp_local_variable_operator_write_node { yp_node_t base; yp_location_t name_loc; @@ -1229,7 +1321,7 @@ typedef struct yp_local_variable_operator_write_node { // LocalVariableOrWriteNode // -// Type: YP_NODE_LOCAL_VARIABLE_OR_WRITE_NODE +// Type: YP_LOCAL_VARIABLE_OR_WRITE_NODE typedef struct yp_local_variable_or_write_node { yp_node_t base; yp_location_t name_loc; @@ -1241,7 +1333,7 @@ typedef struct yp_local_variable_or_write_node { // LocalVariableReadNode // -// Type: YP_NODE_LOCAL_VARIABLE_READ_NODE +// Type: YP_LOCAL_VARIABLE_READ_NODE typedef struct yp_local_variable_read_node { yp_node_t base; yp_constant_id_t name; @@ -1250,7 +1342,7 @@ typedef struct yp_local_variable_read_node { // LocalVariableTargetNode // -// Type: YP_NODE_LOCAL_VARIABLE_TARGET_NODE +// Type: YP_LOCAL_VARIABLE_TARGET_NODE typedef struct yp_local_variable_target_node { yp_node_t base; yp_constant_id_t name; @@ -1259,7 +1351,7 @@ typedef struct yp_local_variable_target_node { // LocalVariableWriteNode // -// Type: YP_NODE_LOCAL_VARIABLE_WRITE_NODE +// Type: YP_LOCAL_VARIABLE_WRITE_NODE typedef struct yp_local_variable_write_node { yp_node_t base; yp_constant_id_t name; @@ -1269,9 +1361,29 @@ typedef struct yp_local_variable_write_node { yp_location_t operator_loc; } yp_local_variable_write_node_t; +// MatchLastLineNode +// +// Type: YP_MATCH_LAST_LINE_NODE +// Flags: +// YP_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE +// YP_REGULAR_EXPRESSION_FLAGS_EXTENDED +// YP_REGULAR_EXPRESSION_FLAGS_MULTI_LINE +// YP_REGULAR_EXPRESSION_FLAGS_EUC_JP +// YP_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT +// YP_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J +// YP_REGULAR_EXPRESSION_FLAGS_UTF_8 +// YP_REGULAR_EXPRESSION_FLAGS_ONCE +typedef struct yp_match_last_line_node { + yp_node_t base; + yp_location_t opening_loc; + yp_location_t content_loc; + yp_location_t closing_loc; + yp_string_t unescaped; +} yp_match_last_line_node_t; + // MatchPredicateNode // -// Type: YP_NODE_MATCH_PREDICATE_NODE +// Type: YP_MATCH_PREDICATE_NODE typedef struct yp_match_predicate_node { yp_node_t base; struct yp_node *value; @@ -1281,7 +1393,7 @@ typedef struct yp_match_predicate_node { // MatchRequiredNode // -// Type: YP_NODE_MATCH_REQUIRED_NODE +// Type: YP_MATCH_REQUIRED_NODE typedef struct yp_match_required_node { yp_node_t base; struct yp_node *value; @@ -1289,16 +1401,25 @@ typedef struct yp_match_required_node { yp_location_t operator_loc; } yp_match_required_node_t; +// MatchWriteNode +// +// Type: YP_MATCH_WRITE_NODE +typedef struct yp_match_write_node { + yp_node_t base; + struct yp_call_node *call; + yp_constant_id_list_t locals; +} yp_match_write_node_t; + // MissingNode // -// Type: YP_NODE_MISSING_NODE +// Type: YP_MISSING_NODE typedef struct yp_missing_node { yp_node_t base; } yp_missing_node_t; // ModuleNode // -// Type: YP_NODE_MODULE_NODE +// Type: YP_MODULE_NODE typedef struct yp_module_node { yp_node_t base; yp_constant_id_list_t locals; @@ -1306,24 +1427,34 @@ typedef struct yp_module_node { struct yp_node *constant_path; struct yp_node *body; yp_location_t end_keyword_loc; - yp_string_t name; + yp_constant_id_t name; } yp_module_node_t; +// MultiTargetNode +// +// Type: YP_MULTI_TARGET_NODE +typedef struct yp_multi_target_node { + yp_node_t base; + struct yp_node_list targets; + yp_location_t lparen_loc; + yp_location_t rparen_loc; +} yp_multi_target_node_t; + // MultiWriteNode // -// Type: YP_NODE_MULTI_WRITE_NODE +// Type: YP_MULTI_WRITE_NODE typedef struct yp_multi_write_node { yp_node_t base; struct yp_node_list targets; - yp_location_t operator_loc; - struct yp_node *value; yp_location_t lparen_loc; yp_location_t rparen_loc; + yp_location_t operator_loc; + struct yp_node *value; } yp_multi_write_node_t; // NextNode // -// Type: YP_NODE_NEXT_NODE +// Type: YP_NEXT_NODE typedef struct yp_next_node { yp_node_t base; struct yp_arguments_node *arguments; @@ -1332,14 +1463,14 @@ typedef struct yp_next_node { // NilNode // -// Type: YP_NODE_NIL_NODE +// Type: YP_NIL_NODE typedef struct yp_nil_node { yp_node_t base; } yp_nil_node_t; // NoKeywordsParameterNode // -// Type: YP_NODE_NO_KEYWORDS_PARAMETER_NODE +// Type: YP_NO_KEYWORDS_PARAMETER_NODE typedef struct yp_no_keywords_parameter_node { yp_node_t base; yp_location_t operator_loc; @@ -1348,7 +1479,7 @@ typedef struct yp_no_keywords_parameter_node { // NumberedReferenceReadNode // -// Type: YP_NODE_NUMBERED_REFERENCE_READ_NODE +// Type: YP_NUMBERED_REFERENCE_READ_NODE typedef struct yp_numbered_reference_read_node { yp_node_t base; uint32_t number; @@ -1356,7 +1487,7 @@ typedef struct yp_numbered_reference_read_node { // OptionalParameterNode // -// Type: YP_NODE_OPTIONAL_PARAMETER_NODE +// Type: YP_OPTIONAL_PARAMETER_NODE typedef struct yp_optional_parameter_node { yp_node_t base; yp_constant_id_t name; @@ -1367,7 +1498,7 @@ typedef struct yp_optional_parameter_node { // OrNode // -// Type: YP_NODE_OR_NODE +// Type: YP_OR_NODE typedef struct yp_or_node { yp_node_t base; struct yp_node *left; @@ -1377,13 +1508,13 @@ typedef struct yp_or_node { // ParametersNode // -// Type: YP_NODE_PARAMETERS_NODE +// Type: YP_PARAMETERS_NODE typedef struct yp_parameters_node { yp_node_t base; struct yp_node_list requireds; struct yp_node_list optionals; - struct yp_node_list posts; struct yp_rest_parameter_node *rest; + struct yp_node_list posts; struct yp_node_list keywords; struct yp_node *keyword_rest; struct yp_block_parameter_node *block; @@ -1391,7 +1522,7 @@ typedef struct yp_parameters_node { // ParenthesesNode // -// Type: YP_NODE_PARENTHESES_NODE +// Type: YP_PARENTHESES_NODE typedef struct yp_parentheses_node { yp_node_t base; struct yp_node *body; @@ -1401,7 +1532,7 @@ typedef struct yp_parentheses_node { // PinnedExpressionNode // -// Type: YP_NODE_PINNED_EXPRESSION_NODE +// Type: YP_PINNED_EXPRESSION_NODE typedef struct yp_pinned_expression_node { yp_node_t base; struct yp_node *expression; @@ -1412,7 +1543,7 @@ typedef struct yp_pinned_expression_node { // PinnedVariableNode // -// Type: YP_NODE_PINNED_VARIABLE_NODE +// Type: YP_PINNED_VARIABLE_NODE typedef struct yp_pinned_variable_node { yp_node_t base; struct yp_node *variable; @@ -1421,7 +1552,7 @@ typedef struct yp_pinned_variable_node { // PostExecutionNode // -// Type: YP_NODE_POST_EXECUTION_NODE +// Type: YP_POST_EXECUTION_NODE typedef struct yp_post_execution_node { yp_node_t base; struct yp_statements_node *statements; @@ -1432,7 +1563,7 @@ typedef struct yp_post_execution_node { // PreExecutionNode // -// Type: YP_NODE_PRE_EXECUTION_NODE +// Type: YP_PRE_EXECUTION_NODE typedef struct yp_pre_execution_node { yp_node_t base; struct yp_statements_node *statements; @@ -1443,7 +1574,7 @@ typedef struct yp_pre_execution_node { // ProgramNode // -// Type: YP_NODE_PROGRAM_NODE +// Type: YP_PROGRAM_NODE typedef struct yp_program_node { yp_node_t base; yp_constant_id_list_t locals; @@ -1452,7 +1583,7 @@ typedef struct yp_program_node { // RangeNode // -// Type: YP_NODE_RANGE_NODE +// Type: YP_RANGE_NODE // Flags: // YP_RANGE_FLAGS_EXCLUDE_END typedef struct yp_range_node { @@ -1464,7 +1595,7 @@ typedef struct yp_range_node { // RationalNode // -// Type: YP_NODE_RATIONAL_NODE +// Type: YP_RATIONAL_NODE typedef struct yp_rational_node { yp_node_t base; struct yp_node *numeric; @@ -1472,18 +1603,18 @@ typedef struct yp_rational_node { // RedoNode // -// Type: YP_NODE_REDO_NODE +// Type: YP_REDO_NODE typedef struct yp_redo_node { yp_node_t base; } yp_redo_node_t; // RegularExpressionNode // -// Type: YP_NODE_REGULAR_EXPRESSION_NODE +// Type: YP_REGULAR_EXPRESSION_NODE // Flags: // YP_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE -// YP_REGULAR_EXPRESSION_FLAGS_MULTI_LINE // YP_REGULAR_EXPRESSION_FLAGS_EXTENDED +// YP_REGULAR_EXPRESSION_FLAGS_MULTI_LINE // YP_REGULAR_EXPRESSION_FLAGS_EUC_JP // YP_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT // YP_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J @@ -1499,7 +1630,7 @@ typedef struct yp_regular_expression_node { // RequiredDestructuredParameterNode // -// Type: YP_NODE_REQUIRED_DESTRUCTURED_PARAMETER_NODE +// Type: YP_REQUIRED_DESTRUCTURED_PARAMETER_NODE typedef struct yp_required_destructured_parameter_node { yp_node_t base; struct yp_node_list parameters; @@ -1509,7 +1640,7 @@ typedef struct yp_required_destructured_parameter_node { // RequiredParameterNode // -// Type: YP_NODE_REQUIRED_PARAMETER_NODE +// Type: YP_REQUIRED_PARAMETER_NODE typedef struct yp_required_parameter_node { yp_node_t base; yp_constant_id_t name; @@ -1517,7 +1648,7 @@ typedef struct yp_required_parameter_node { // RescueModifierNode // -// Type: YP_NODE_RESCUE_MODIFIER_NODE +// Type: YP_RESCUE_MODIFIER_NODE typedef struct yp_rescue_modifier_node { yp_node_t base; struct yp_node *expression; @@ -1527,7 +1658,7 @@ typedef struct yp_rescue_modifier_node { // RescueNode // -// Type: YP_NODE_RESCUE_NODE +// Type: YP_RESCUE_NODE typedef struct yp_rescue_node { yp_node_t base; yp_location_t keyword_loc; @@ -1540,23 +1671,24 @@ typedef struct yp_rescue_node { // RestParameterNode // -// Type: YP_NODE_REST_PARAMETER_NODE +// Type: YP_REST_PARAMETER_NODE typedef struct yp_rest_parameter_node { yp_node_t base; - yp_location_t operator_loc; + yp_constant_id_t name; yp_location_t name_loc; + yp_location_t operator_loc; } yp_rest_parameter_node_t; // RetryNode // -// Type: YP_NODE_RETRY_NODE +// Type: YP_RETRY_NODE typedef struct yp_retry_node { yp_node_t base; } yp_retry_node_t; // ReturnNode // -// Type: YP_NODE_RETURN_NODE +// Type: YP_RETURN_NODE typedef struct yp_return_node { yp_node_t base; yp_location_t keyword_loc; @@ -1565,14 +1697,14 @@ typedef struct yp_return_node { // SelfNode // -// Type: YP_NODE_SELF_NODE +// Type: YP_SELF_NODE typedef struct yp_self_node { yp_node_t base; } yp_self_node_t; // SingletonClassNode // -// Type: YP_NODE_SINGLETON_CLASS_NODE +// Type: YP_SINGLETON_CLASS_NODE typedef struct yp_singleton_class_node { yp_node_t base; yp_constant_id_list_t locals; @@ -1585,14 +1717,14 @@ typedef struct yp_singleton_class_node { // SourceEncodingNode // -// Type: YP_NODE_SOURCE_ENCODING_NODE +// Type: YP_SOURCE_ENCODING_NODE typedef struct yp_source_encoding_node { yp_node_t base; } yp_source_encoding_node_t; // SourceFileNode // -// Type: YP_NODE_SOURCE_FILE_NODE +// Type: YP_SOURCE_FILE_NODE typedef struct yp_source_file_node { yp_node_t base; yp_string_t filepath; @@ -1600,14 +1732,14 @@ typedef struct yp_source_file_node { // SourceLineNode // -// Type: YP_NODE_SOURCE_LINE_NODE +// Type: YP_SOURCE_LINE_NODE typedef struct yp_source_line_node { yp_node_t base; } yp_source_line_node_t; // SplatNode // -// Type: YP_NODE_SPLAT_NODE +// Type: YP_SPLAT_NODE typedef struct yp_splat_node { yp_node_t base; yp_location_t operator_loc; @@ -1616,7 +1748,7 @@ typedef struct yp_splat_node { // StatementsNode // -// Type: YP_NODE_STATEMENTS_NODE +// Type: YP_STATEMENTS_NODE typedef struct yp_statements_node { yp_node_t base; struct yp_node_list body; @@ -1624,7 +1756,7 @@ typedef struct yp_statements_node { // StringConcatNode // -// Type: YP_NODE_STRING_CONCAT_NODE +// Type: YP_STRING_CONCAT_NODE typedef struct yp_string_concat_node { yp_node_t base; struct yp_node *left; @@ -1633,7 +1765,9 @@ typedef struct yp_string_concat_node { // StringNode // -// Type: YP_NODE_STRING_NODE +// Type: YP_STRING_NODE +// Flags: +// YP_STRING_FLAGS_FROZEN typedef struct yp_string_node { yp_node_t base; yp_location_t opening_loc; @@ -1644,19 +1778,19 @@ typedef struct yp_string_node { // SuperNode // -// Type: YP_NODE_SUPER_NODE +// Type: YP_SUPER_NODE typedef struct yp_super_node { yp_node_t base; yp_location_t keyword_loc; yp_location_t lparen_loc; struct yp_arguments_node *arguments; yp_location_t rparen_loc; - struct yp_block_node *block; + struct yp_node *block; } yp_super_node_t; // SymbolNode // -// Type: YP_NODE_SYMBOL_NODE +// Type: YP_SYMBOL_NODE typedef struct yp_symbol_node { yp_node_t base; yp_location_t opening_loc; @@ -1667,14 +1801,14 @@ typedef struct yp_symbol_node { // TrueNode // -// Type: YP_NODE_TRUE_NODE +// Type: YP_TRUE_NODE typedef struct yp_true_node { yp_node_t base; } yp_true_node_t; // UndefNode // -// Type: YP_NODE_UNDEF_NODE +// Type: YP_UNDEF_NODE typedef struct yp_undef_node { yp_node_t base; struct yp_node_list names; @@ -1683,7 +1817,7 @@ typedef struct yp_undef_node { // UnlessNode // -// Type: YP_NODE_UNLESS_NODE +// Type: YP_UNLESS_NODE typedef struct yp_unless_node { yp_node_t base; yp_location_t keyword_loc; @@ -1695,7 +1829,7 @@ typedef struct yp_unless_node { // UntilNode // -// Type: YP_NODE_UNTIL_NODE +// Type: YP_UNTIL_NODE // Flags: // YP_LOOP_FLAGS_BEGIN_MODIFIER typedef struct yp_until_node { @@ -1708,7 +1842,7 @@ typedef struct yp_until_node { // WhenNode // -// Type: YP_NODE_WHEN_NODE +// Type: YP_WHEN_NODE typedef struct yp_when_node { yp_node_t base; yp_location_t keyword_loc; @@ -1718,7 +1852,7 @@ typedef struct yp_when_node { // WhileNode // -// Type: YP_NODE_WHILE_NODE +// Type: YP_WHILE_NODE // Flags: // YP_LOOP_FLAGS_BEGIN_MODIFIER typedef struct yp_while_node { @@ -1731,7 +1865,7 @@ typedef struct yp_while_node { // XStringNode // -// Type: YP_NODE_X_STRING_NODE +// Type: YP_X_STRING_NODE typedef struct yp_x_string_node { yp_node_t base; yp_location_t opening_loc; @@ -1742,7 +1876,7 @@ typedef struct yp_x_string_node { // YieldNode // -// Type: YP_NODE_YIELD_NODE +// Type: YP_YIELD_NODE typedef struct yp_yield_node { yp_node_t base; yp_location_t keyword_loc; @@ -1753,30 +1887,45 @@ typedef struct yp_yield_node { // CallNodeFlags typedef enum { - YP_CALL_NODE_FLAGS_SAFE_NAVIGATION = 1 << 1, - YP_CALL_NODE_FLAGS_VARIABLE_CALL = 1 << 2, + YP_CALL_NODE_FLAGS_SAFE_NAVIGATION = 1 << 2, + YP_CALL_NODE_FLAGS_VARIABLE_CALL = 1 << 3, } yp_call_node_flags_t; +// IntegerBaseFlags +typedef enum { + YP_INTEGER_BASE_FLAGS_BINARY = 1 << 2, + YP_INTEGER_BASE_FLAGS_OCTAL = 1 << 3, + YP_INTEGER_BASE_FLAGS_DECIMAL = 1 << 4, + YP_INTEGER_BASE_FLAGS_HEXADECIMAL = 1 << 5, +} yp_integer_base_flags_t; + // LoopFlags typedef enum { - YP_LOOP_FLAGS_BEGIN_MODIFIER = 1 << 1, + YP_LOOP_FLAGS_BEGIN_MODIFIER = 1 << 2, } yp_loop_flags_t; // RangeFlags typedef enum { - YP_RANGE_FLAGS_EXCLUDE_END = 1 << 1, + YP_RANGE_FLAGS_EXCLUDE_END = 1 << 2, } yp_range_flags_t; // RegularExpressionFlags typedef enum { - YP_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE = 1 << 1, - YP_REGULAR_EXPRESSION_FLAGS_MULTI_LINE = 1 << 2, + YP_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE = 1 << 2, YP_REGULAR_EXPRESSION_FLAGS_EXTENDED = 1 << 3, - YP_REGULAR_EXPRESSION_FLAGS_EUC_JP = 1 << 4, - YP_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT = 1 << 5, - YP_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J = 1 << 6, - YP_REGULAR_EXPRESSION_FLAGS_UTF_8 = 1 << 7, - YP_REGULAR_EXPRESSION_FLAGS_ONCE = 1 << 8, + YP_REGULAR_EXPRESSION_FLAGS_MULTI_LINE = 1 << 4, + YP_REGULAR_EXPRESSION_FLAGS_EUC_JP = 1 << 5, + YP_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT = 1 << 6, + YP_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J = 1 << 7, + YP_REGULAR_EXPRESSION_FLAGS_UTF_8 = 1 << 8, + YP_REGULAR_EXPRESSION_FLAGS_ONCE = 1 << 9, } yp_regular_expression_flags_t; +// StringFlags +typedef enum { + YP_STRING_FLAGS_FROZEN = 1 << 2, +} yp_string_flags_t; + +#define YP_SERIALIZE_ONLY_SEMANTICS_FIELDS 1 + #endif // YARP_AST_H diff --git a/src/main/c/yarp/include/yarp/diagnostic.h b/src/main/c/yarp/include/yarp/diagnostic.h index 58228d8493ad..b8d9fe010090 100644 --- a/src/main/c/yarp/include/yarp/diagnostic.h +++ b/src/main/c/yarp/include/yarp/diagnostic.h @@ -6,6 +6,7 @@ #include #include +#include // This struct represents a diagnostic found during parsing. typedef struct { @@ -15,8 +16,209 @@ typedef struct { const char *message; } yp_diagnostic_t; +typedef enum { + YP_ERR_ALIAS_ARGUMENT, + YP_ERR_AMPAMPEQ_MULTI_ASSIGN, + YP_ERR_ARGUMENT_AFTER_BLOCK, + YP_ERR_ARGUMENT_BARE_HASH, + YP_ERR_ARGUMENT_BLOCK_MULTI, + YP_ERR_ARGUMENT_FORMAL_CLASS, + YP_ERR_ARGUMENT_FORMAL_CONSTANT, + YP_ERR_ARGUMENT_FORMAL_GLOBAL, + YP_ERR_ARGUMENT_FORMAL_IVAR, + YP_ERR_ARGUMENT_NO_FORWARDING_AMP, + YP_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES, + YP_ERR_ARGUMENT_NO_FORWARDING_STAR, + YP_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT, + YP_ERR_ARGUMENT_SPLAT_AFTER_SPLAT, + YP_ERR_ARGUMENT_TERM_PAREN, + YP_ERR_ARGUMENT_UNEXPECTED_BLOCK, + YP_ERR_ARRAY_ELEMENT, + YP_ERR_ARRAY_EXPRESSION, + YP_ERR_ARRAY_EXPRESSION_AFTER_STAR, + YP_ERR_ARRAY_SEPARATOR, + YP_ERR_ARRAY_TERM, + YP_ERR_BEGIN_LONELY_ELSE, + YP_ERR_BEGIN_TERM, + YP_ERR_BEGIN_UPCASE_BRACE, + YP_ERR_BEGIN_UPCASE_TERM, + YP_ERR_BLOCK_PARAM_LOCAL_VARIABLE, + YP_ERR_BLOCK_PARAM_PIPE_TERM, + YP_ERR_BLOCK_TERM_BRACE, + YP_ERR_BLOCK_TERM_END, + YP_ERR_CANNOT_PARSE_EXPRESSION, + YP_ERR_CANNOT_PARSE_STRING_PART, + YP_ERR_CASE_EXPRESSION_AFTER_CASE, + YP_ERR_CASE_EXPRESSION_AFTER_WHEN, + YP_ERR_CASE_MISSING_CONDITIONS, + YP_ERR_CASE_TERM, + YP_ERR_CLASS_IN_METHOD, + YP_ERR_CLASS_NAME, + YP_ERR_CLASS_SUPERCLASS, + YP_ERR_CLASS_TERM, + YP_ERR_CONDITIONAL_ELSIF_PREDICATE, + YP_ERR_CONDITIONAL_IF_PREDICATE, + YP_ERR_CONDITIONAL_TERM, + YP_ERR_CONDITIONAL_TERM_ELSE, + YP_ERR_CONDITIONAL_UNLESS_PREDICATE, + YP_ERR_CONDITIONAL_UNTIL_PREDICATE, + YP_ERR_CONDITIONAL_WHILE_PREDICATE, + YP_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT, + YP_ERR_DEF_ENDLESS, + YP_ERR_DEF_ENDLESS_SETTER, + YP_ERR_DEF_NAME, + YP_ERR_DEF_NAME_AFTER_RECEIVER, + YP_ERR_DEF_PARAMS_TERM, + YP_ERR_DEF_PARAMS_TERM_PAREN, + YP_ERR_DEF_RECEIVER, + YP_ERR_DEF_RECEIVER_TERM, + YP_ERR_DEF_TERM, + YP_ERR_DEFINED_EXPRESSION, + YP_ERR_EMBDOC_TERM, + YP_ERR_EMBEXPR_END, + YP_ERR_EMBVAR_INVALID, + YP_ERR_END_UPCASE_BRACE, + YP_ERR_END_UPCASE_TERM, + YP_ERR_ESCAPE_INVALID_CONTROL, + YP_ERR_ESCAPE_INVALID_CONTROL_REPEAT, + YP_ERR_ESCAPE_INVALID_HEXADECIMAL, + YP_ERR_ESCAPE_INVALID_META, + YP_ERR_ESCAPE_INVALID_META_REPEAT, + YP_ERR_ESCAPE_INVALID_UNICODE, + YP_ERR_ESCAPE_INVALID_UNICODE_CM_FLAGS, + YP_ERR_ESCAPE_INVALID_UNICODE_LITERAL, + YP_ERR_ESCAPE_INVALID_UNICODE_LONG, + YP_ERR_ESCAPE_INVALID_UNICODE_TERM, + YP_ERR_EXPECT_ARGUMENT, + YP_ERR_EXPECT_EOL_AFTER_STATEMENT, + YP_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, + YP_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, + YP_ERR_EXPECT_EXPRESSION_AFTER_COMMA, + YP_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, + YP_ERR_EXPECT_EXPRESSION_AFTER_LESS_LESS, + YP_ERR_EXPECT_EXPRESSION_AFTER_LPAREN, + YP_ERR_EXPECT_EXPRESSION_AFTER_QUESTION, + YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, + YP_ERR_EXPECT_EXPRESSION_AFTER_SPLAT, + YP_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, + YP_ERR_EXPECT_EXPRESSION_AFTER_STAR, + YP_ERR_EXPECT_IDENT_REQ_PARAMETER, + YP_ERR_EXPECT_LPAREN_REQ_PARAMETER, + YP_ERR_EXPECT_RBRACKET, + YP_ERR_EXPECT_RPAREN, + YP_ERR_EXPECT_RPAREN_AFTER_MULTI, + YP_ERR_EXPECT_RPAREN_REQ_PARAMETER, + YP_ERR_EXPECT_STRING_CONTENT, + YP_ERR_EXPECT_WHEN_DELIMITER, + YP_ERR_EXPRESSION_BARE_HASH, + YP_ERR_FOR_COLLECTION, + YP_ERR_FOR_IN, + YP_ERR_FOR_INDEX, + YP_ERR_FOR_TERM, + YP_ERR_HASH_EXPRESSION_AFTER_LABEL, + YP_ERR_HASH_KEY, + YP_ERR_HASH_ROCKET, + YP_ERR_HASH_TERM, + YP_ERR_HASH_VALUE, + YP_ERR_HEREDOC_TERM, + YP_ERR_INCOMPLETE_QUESTION_MARK, + YP_ERR_INCOMPLETE_VARIABLE_CLASS, + YP_ERR_INCOMPLETE_VARIABLE_INSTANCE, + YP_ERR_INVALID_ENCODING_MAGIC_COMMENT, + YP_ERR_INVALID_FLOAT_EXPONENT, + YP_ERR_INVALID_NUMBER_BINARY, + YP_ERR_INVALID_NUMBER_DECIMAL, + YP_ERR_INVALID_NUMBER_HEXADECIMAL, + YP_ERR_INVALID_NUMBER_OCTAL, + YP_ERR_INVALID_NUMBER_UNDERSCORE, + YP_ERR_INVALID_PERCENT, + YP_ERR_INVALID_TOKEN, + YP_ERR_INVALID_VARIABLE_GLOBAL, + YP_ERR_LAMBDA_OPEN, + YP_ERR_LAMBDA_TERM_BRACE, + YP_ERR_LAMBDA_TERM_END, + YP_ERR_LIST_I_LOWER_ELEMENT, + YP_ERR_LIST_I_LOWER_TERM, + YP_ERR_LIST_I_UPPER_ELEMENT, + YP_ERR_LIST_I_UPPER_TERM, + YP_ERR_LIST_W_LOWER_ELEMENT, + YP_ERR_LIST_W_LOWER_TERM, + YP_ERR_LIST_W_UPPER_ELEMENT, + YP_ERR_LIST_W_UPPER_TERM, + YP_ERR_MALLOC_FAILED, + YP_ERR_MODULE_IN_METHOD, + YP_ERR_MODULE_NAME, + YP_ERR_MODULE_TERM, + YP_ERR_MULTI_ASSIGN_MULTI_SPLATS, + YP_ERR_NOT_EXPRESSION, + YP_ERR_NUMBER_LITERAL_UNDERSCORE, + YP_ERR_NUMBERED_PARAMETER_NOT_ALLOWED, + YP_ERR_NUMBERED_PARAMETER_OUTER_SCOPE, + YP_ERR_OPERATOR_MULTI_ASSIGN, + YP_ERR_OPERATOR_WRITE_BLOCK, + YP_ERR_PARAMETER_ASSOC_SPLAT_MULTI, + YP_ERR_PARAMETER_BLOCK_MULTI, + YP_ERR_PARAMETER_NAME_REPEAT, + YP_ERR_PARAMETER_NO_DEFAULT, + YP_ERR_PARAMETER_NO_DEFAULT_KW, + YP_ERR_PARAMETER_NUMBERED_RESERVED, + YP_ERR_PARAMETER_ORDER, + YP_ERR_PARAMETER_SPLAT_MULTI, + YP_ERR_PARAMETER_STAR, + YP_ERR_PARAMETER_WILD_LOOSE_COMMA, + YP_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, + YP_ERR_PATTERN_EXPRESSION_AFTER_HROCKET, + YP_ERR_PATTERN_EXPRESSION_AFTER_COMMA, + YP_ERR_PATTERN_EXPRESSION_AFTER_IN, + YP_ERR_PATTERN_EXPRESSION_AFTER_KEY, + YP_ERR_PATTERN_EXPRESSION_AFTER_PAREN, + YP_ERR_PATTERN_EXPRESSION_AFTER_PIN, + YP_ERR_PATTERN_EXPRESSION_AFTER_PIPE, + YP_ERR_PATTERN_EXPRESSION_AFTER_RANGE, + YP_ERR_PATTERN_HASH_KEY, + YP_ERR_PATTERN_HASH_KEY_LABEL, + YP_ERR_PATTERN_IDENT_AFTER_HROCKET, + YP_ERR_PATTERN_LABEL_AFTER_COMMA, + YP_ERR_PATTERN_REST, + YP_ERR_PATTERN_TERM_BRACE, + YP_ERR_PATTERN_TERM_BRACKET, + YP_ERR_PATTERN_TERM_PAREN, + YP_ERR_PIPEPIPEEQ_MULTI_ASSIGN, + YP_ERR_REGEXP_TERM, + YP_ERR_RESCUE_EXPRESSION, + YP_ERR_RESCUE_MODIFIER_VALUE, + YP_ERR_RESCUE_TERM, + YP_ERR_RESCUE_VARIABLE, + YP_ERR_RETURN_INVALID, + YP_ERR_STRING_CONCATENATION, + YP_ERR_STRING_INTERPOLATED_TERM, + YP_ERR_STRING_LITERAL_TERM, + YP_ERR_SYMBOL_INVALID, + YP_ERR_SYMBOL_TERM_DYNAMIC, + YP_ERR_SYMBOL_TERM_INTERPOLATED, + YP_ERR_TERNARY_COLON, + YP_ERR_TERNARY_EXPRESSION_FALSE, + YP_ERR_TERNARY_EXPRESSION_TRUE, + YP_ERR_UNARY_RECEIVER_BANG, + YP_ERR_UNARY_RECEIVER_MINUS, + YP_ERR_UNARY_RECEIVER_PLUS, + YP_ERR_UNARY_RECEIVER_TILDE, + YP_ERR_UNDEF_ARGUMENT, + YP_ERR_UNTIL_TERM, + YP_ERR_WHILE_TERM, + YP_ERR_WRITE_TARGET_READONLY, + YP_ERR_WRITE_TARGET_UNEXPECTED, + YP_ERR_XSTRING_TERM, + YP_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS, + YP_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS, + YP_WARN_AMBIGUOUS_PREFIX_STAR, + YP_WARN_AMBIGUOUS_SLASH, + /* This must be the last member. */ + YP_DIAGNOSTIC_ID_LEN, +} yp_diagnostic_id_t; + // Append a diagnostic to the given list of diagnostics. -bool yp_diagnostic_list_append(yp_list_t *list, const uint8_t *start, const uint8_t *end, const char *message); +bool yp_diagnostic_list_append(yp_list_t *list, const uint8_t *start, const uint8_t *end, yp_diagnostic_id_t diag_id); // Deallocate the internal state of the given diagnostic list. void yp_diagnostic_list_free(yp_list_t *list); diff --git a/src/main/c/yarp/include/yarp/enc/yp_encoding.h b/src/main/c/yarp/include/yarp/enc/yp_encoding.h index 9e8e7e01f60d..d8563bd54a0a 100644 --- a/src/main/c/yarp/include/yarp/enc/yp_encoding.h +++ b/src/main/c/yarp/include/yarp/enc/yp_encoding.h @@ -60,7 +60,7 @@ size_t yp_encoding_utf_8_alnum_char(const uint8_t *b, ptrdiff_t n); // This lookup table is referenced in both the UTF-8 encoding file and the // parser directly in order to speed up the default encoding processing. -extern uint8_t yp_encoding_unicode_table[256]; +extern const uint8_t yp_encoding_unicode_table[256]; // These are the encodings that are supported by the parser. They are defined in // their own files in the src/enc directory. diff --git a/src/main/c/yarp/include/yarp/node.h b/src/main/c/yarp/include/yarp/node.h index f2d5be8bf22e..1b546f086f00 100644 --- a/src/main/c/yarp/include/yarp/node.h +++ b/src/main/c/yarp/include/yarp/node.h @@ -4,9 +4,6 @@ #include "yarp/defines.h" #include "yarp/parser.h" -// Append a token to the given list. -void yp_location_list_append(yp_location_list_t *list, const yp_token_t *token); - // Append a new node onto the end of the node list. void yp_node_list_append(yp_node_list_t *list, yp_node_t *node); @@ -31,7 +28,6 @@ YP_EXPORTED_FUNCTION void yp_node_memsize(yp_node_t *node, yp_memsize_t *memsize YP_EXPORTED_FUNCTION const char * yp_node_type_to_str(yp_node_type_t node_type); #define YP_EMPTY_NODE_LIST ((yp_node_list_t) { .nodes = NULL, .size = 0, .capacity = 0 }) -#define YP_EMPTY_LOCATION_LIST ((yp_location_list_t) { .locations = NULL, .size = 0, .capacity = 0 }) #endif // YARP_NODE_H diff --git a/src/main/c/yarp/include/yarp/parser.h b/src/main/c/yarp/include/yarp/parser.h index 0ae01f78da6e..89b0f2744bb6 100644 --- a/src/main/c/yarp/include/yarp/parser.h +++ b/src/main/c/yarp/include/yarp/parser.h @@ -277,12 +277,22 @@ typedef struct yp_scope { // The IDs of the locals in the given scope. yp_constant_id_list_t locals; + // A pointer to the previous scope in the linked list. + struct yp_scope *previous; + // A boolean indicating whether or not this scope can see into its parent. // If closed is true, then the scope cannot see into its parent. bool closed; - // A pointer to the previous scope in the linked list. - struct yp_scope *previous; + // A boolean indicating whether or not this scope has explicit parameters. + // This is necessary to determine whether or not numbered parameters are + // allowed. + bool explicit_params; + + // A boolean indicating whether or not this scope has numbered parameters. + // This is necessary to determine if child blocks are allowed to use + // numbered parameters. + bool numbered_params; } yp_scope_t; // This struct represents the overall parser. It contains a reference to the @@ -291,7 +301,6 @@ typedef struct yp_scope { // it's considering. struct yp_parser { yp_lex_state_t lex_state; // the current state of the lexer - bool command_start; // whether or not we're at the beginning of a command int enclosure_nesting; // tracks the current nesting of (), [], and {} // Used to temporarily track the nesting of enclosures to determine if a { @@ -338,17 +347,11 @@ struct yp_parser { yp_scope_t *current_scope; // the current local scope yp_context_node_t *current_context; // the current parsing context - bool recovering; // whether or not we're currently recovering from a syntax error // The encoding functions for the current file is attached to the parser as // it's parsing so that it can change with a magic comment. yp_encoding_t encoding; - // Whether or not the encoding has been changed by a magic comment. We use - // this to provide a fast path for the lexer instead of going through the - // function pointer. - bool encoding_changed; - // When the encoding that is being used to parse the source is changed by // YARP, we provide the ability here to call out to a user-defined function. yp_encoding_changed_callback_t encoding_changed_callback; @@ -367,13 +370,6 @@ struct yp_parser { // be called whenever a new token is lexed by the parser. yp_lex_callback_t *lex_callback; - // This flag indicates that we are currently parsing a pattern matching - // expression and impacts that calculation of newlines. - bool pattern_matching_newlines; - - // This flag indicates that we are currently parsing a keyword argument. - bool in_keyword_arg; - // This is the path of the file being parsed // We use the filepath when constructing SourceFileNodes yp_string_t filepath_string; @@ -384,6 +380,38 @@ struct yp_parser { // This is the list of newline offsets in the source file. yp_newline_list_t newline_list; + + // We want to add a flag to integer nodes that indicates their base. We only + // want to parse these once, but we don't have space on the token itself to + // communicate this information. So we store it here and pass it through + // when we find tokens that we need it for. + yp_node_flags_t integer_base; + + // Whether or not we're at the beginning of a command + bool command_start; + + // Whether or not we're currently recovering from a syntax error + bool recovering; + + // Whether or not the encoding has been changed by a magic comment. We use + // this to provide a fast path for the lexer instead of going through the + // function pointer. + bool encoding_changed; + + // This flag indicates that we are currently parsing a pattern matching + // expression and impacts that calculation of newlines. + bool pattern_matching_newlines; + + // This flag indicates that we are currently parsing a keyword argument. + bool in_keyword_arg; + + // Whether or not the parser has seen a token that has semantic meaning + // (i.e., a token that is not a comment or whitespace). + bool semantic_token_seen; + + // Whether or not we have found a frozen_string_literal magic comment with + // a true value. + bool frozen_string_literal; }; #endif // YARP_PARSER_H diff --git a/src/main/c/yarp/include/yarp/unescape.h b/src/main/c/yarp/include/yarp/unescape.h index fb0df9fcb081..bb0ef315a9d6 100644 --- a/src/main/c/yarp/include/yarp/unescape.h +++ b/src/main/c/yarp/include/yarp/unescape.h @@ -24,9 +24,13 @@ typedef enum { // single quotes and backslashes. YP_UNESCAPE_MINIMAL, + // When we're unescaping a string list, in addition to MINIMAL, we need to + // unescape whitespace. + YP_UNESCAPE_WHITESPACE, + // When we're unescaping a double-quoted string, we need to unescape all // escapes. - YP_UNESCAPE_ALL + YP_UNESCAPE_ALL, } yp_unescape_type_t; // Unescape the contents of the given token into the given string using the given unescape mode. diff --git a/src/main/c/yarp/include/yarp/util/yp_char.h b/src/main/c/yarp/include/yarp/util/yp_char.h index 67ba31d34d68..f08d6a8c9dc5 100644 --- a/src/main/c/yarp/include/yarp/util/yp_char.h +++ b/src/main/c/yarp/include/yarp/util/yp_char.h @@ -15,7 +15,7 @@ size_t yp_strspn_whitespace(const uint8_t *string, ptrdiff_t length); // whitespace while also tracking the location of each newline. Disallows // searching past the given maximum number of characters. size_t -yp_strspn_whitespace_newlines(const uint8_t *string, ptrdiff_t length, yp_newline_list_t *newline_list, bool stop_at_newline); +yp_strspn_whitespace_newlines(const uint8_t *string, ptrdiff_t length, yp_newline_list_t *newline_list); // Returns the number of characters at the start of the string that are inline // whitespace. Disallows searching past the given maximum number of characters. @@ -31,19 +31,31 @@ size_t yp_strspn_decimal_digit(const uint8_t *string, ptrdiff_t length); size_t yp_strspn_hexadecimal_digit(const uint8_t *string, ptrdiff_t length); // Returns the number of characters at the start of the string that are octal -// digits or underscores. Disallows searching past the given maximum number of +// digits or underscores. Disallows searching past the given maximum number of // characters. -size_t yp_strspn_octal_number(const uint8_t *string, ptrdiff_t length); +// +// If multiple underscores are found in a row or if an underscore is +// found at the end of the number, then the invalid pointer is set to the index +// of the first invalid underscore. +size_t yp_strspn_octal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid); // Returns the number of characters at the start of the string that are decimal // digits or underscores. Disallows searching past the given maximum number of // characters. -size_t yp_strspn_decimal_number(const uint8_t *string, ptrdiff_t length); +// +// If multiple underscores are found in a row or if an underscore is +// found at the end of the number, then the invalid pointer is set to the index +// of the first invalid underscore. +size_t yp_strspn_decimal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid); // Returns the number of characters at the start of the string that are // hexadecimal digits or underscores. Disallows searching past the given maximum // number of characters. -size_t yp_strspn_hexadecimal_number(const uint8_t *string, ptrdiff_t length); +// +// If multiple underscores are found in a row or if an underscore is +// found at the end of the number, then the invalid pointer is set to the index +// of the first invalid underscore. +size_t yp_strspn_hexadecimal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid); // Returns the number of characters at the start of the string that are regexp // options. Disallows searching past the given maximum number of characters. @@ -52,7 +64,11 @@ size_t yp_strspn_regexp_option(const uint8_t *string, ptrdiff_t length); // Returns the number of characters at the start of the string that are binary // digits or underscores. Disallows searching past the given maximum number of // characters. -size_t yp_strspn_binary_number(const uint8_t *string, ptrdiff_t length); +// +// If multiple underscores are found in a row or if an underscore is +// found at the end of the number, then the invalid pointer is set to the index +// of the first invalid underscore. +size_t yp_strspn_binary_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid); // Returns true if the given character is a whitespace character. bool yp_char_is_whitespace(const uint8_t b); diff --git a/src/main/c/yarp/include/yarp/util/yp_constant_pool.h b/src/main/c/yarp/include/yarp/util/yp_constant_pool.h index 1ac23cf88bbf..c07cd0b7d8c4 100644 --- a/src/main/c/yarp/include/yarp/util/yp_constant_pool.h +++ b/src/main/c/yarp/include/yarp/util/yp_constant_pool.h @@ -8,6 +8,7 @@ #include "yarp/defines.h" +#include #include #include #include @@ -39,27 +40,33 @@ size_t yp_constant_id_list_memsize(yp_constant_id_list_t *list); void yp_constant_id_list_free(yp_constant_id_list_t *list); typedef struct { - yp_constant_id_t id; + unsigned int id: 31; + bool owned: 1; const uint8_t *start; size_t length; - size_t hash; + uint32_t hash; } yp_constant_t; typedef struct { yp_constant_t *constants; - size_t size; - size_t capacity; + uint32_t size; + uint32_t capacity; } yp_constant_pool_t; // Define an empty constant pool. #define YP_CONSTANT_POOL_EMPTY ((yp_constant_pool_t) { .constants = NULL, .size = 0, .capacity = 0 }) // Initialize a new constant pool with a given capacity. -bool yp_constant_pool_init(yp_constant_pool_t *pool, size_t capacity); +bool yp_constant_pool_init(yp_constant_pool_t *pool, uint32_t capacity); + +// Insert a constant into a constant pool that is a slice of a source string. +// Returns the id of the constant, or 0 if any potential calls to resize fail. +yp_constant_id_t yp_constant_pool_insert_shared(yp_constant_pool_t *pool, const uint8_t *start, size_t length); -// Insert a constant into a constant pool. Returns the id of the constant, or 0 -// if any potential calls to resize fail. -yp_constant_id_t yp_constant_pool_insert(yp_constant_pool_t *pool, const uint8_t *start, size_t length); +// Insert a constant into a constant pool from memory that is now owned by the +// constant pool. Returns the id of the constant, or 0 if any potential calls to +// resize fail. +yp_constant_id_t yp_constant_pool_insert_owned(yp_constant_pool_t *pool, const uint8_t *start, size_t length); // Free the memory associated with a constant pool. void yp_constant_pool_free(yp_constant_pool_t *pool); diff --git a/src/main/c/yarp/include/yarp/version.h b/src/main/c/yarp/include/yarp/version.h index 60fd830ca7c1..6dc8efd1c7d2 100644 --- a/src/main/c/yarp/include/yarp/version.h +++ b/src/main/c/yarp/include/yarp/version.h @@ -1,4 +1,4 @@ #define YP_VERSION_MAJOR 0 -#define YP_VERSION_MINOR 10 +#define YP_VERSION_MINOR 12 #define YP_VERSION_PATCH 0 -#define YP_VERSION "0.10.0" +#define YP_VERSION "0.12.0" diff --git a/src/main/c/yarp/src/diagnostic.c b/src/main/c/yarp/src/diagnostic.c index b216d96a3309..34da3f97a5d9 100644 --- a/src/main/c/yarp/src/diagnostic.c +++ b/src/main/c/yarp/src/diagnostic.c @@ -1,12 +1,269 @@ #include "yarp/diagnostic.h" +/* + ## Message composition + + When composing an error message, use sentence fragments. + + Try describing the property of the code that caused the error, rather than the rule that is being + violated. It may help to use a fragment that completes a sentence beginning, "The parser + encountered (a) ...". If appropriate, add a description of the rule violation (or other helpful + context) after a semicolon. + + For example:, instead of "Control escape sequence cannot be doubled", prefer: + + > "Invalid control escape sequence; control cannot be repeated" + + In some cases, where the failure is more general or syntax expectations are violated, it may make + more sense to use a fragment that completes a sentence beginning, "The parser ...". + + For example: + + > "Expected an expression after `(`" + > "Cannot parse the expression" + + + ## Message style guide + + - Use articles like "a", "an", and "the" when appropriate. + - e.g., prefer "Cannot parse the expression" to "Cannot parse expression". + - Use the common name for tokens and nodes. + - e.g., prefer "keyword splat" to "assoc splat" + - e.g., prefer "embedded document" to "embdoc" + - Capitalize the initial word of the message. + - Use back ticks around token literals + - e.g., "Expected a `=>` between the hash key and value" + - Do not use `.` or other punctuation at the end of the message. + - Do not use contractions like "can't". Prefer "cannot" to "can not". + - For tokens that can have multiple meanings, reference the token and its meaning. + - e.g., "`*` splat argument" is clearer and more complete than "splat argument" or "`*` argument" + + + ## Error names (YP_ERR_*) + + - When appropriate, prefer node name to token name. + - e.g., prefer "SPLAT" to "STAR" in the context of argument parsing. + - Prefer token name to common name. + - e.g., prefer "STAR" to "ASTERISK". + - Try to order the words in the name from more general to more specific, + - e.g., "INVALID_NUMBER_DECIMAL" is better than "DECIMAL_INVALID_NUMBER". + - When in doubt, look for similar patterns and name them so that they are grouped when lexically + sorted. See YP_ERR_ARGUMENT_NO_FORWARDING_* for an example. +*/ + +static const char* const diagnostic_messages[YP_DIAGNOSTIC_ID_LEN] = { + [YP_ERR_ALIAS_ARGUMENT] = "Invalid argument being passed to `alias`; expected a bare word, symbol, constant, or global variable", + [YP_ERR_AMPAMPEQ_MULTI_ASSIGN] = "Unexpected `&&=` in a multiple assignment", + [YP_ERR_ARGUMENT_AFTER_BLOCK] = "Unexpected argument after a block argument", + [YP_ERR_ARGUMENT_BARE_HASH] = "Unexpected bare hash argument", + [YP_ERR_ARGUMENT_BLOCK_MULTI] = "Multiple block arguments; only one block is allowed", + [YP_ERR_ARGUMENT_FORMAL_CLASS] = "Invalid formal argument; formal argument cannot be a class variable", + [YP_ERR_ARGUMENT_FORMAL_CONSTANT] = "Invalid formal argument; formal argument cannot be a constant", + [YP_ERR_ARGUMENT_FORMAL_GLOBAL] = "Invalid formal argument; formal argument cannot be a global variable", + [YP_ERR_ARGUMENT_FORMAL_IVAR] = "Invalid formal argument; formal argument cannot be an instance variable", + [YP_ERR_ARGUMENT_NO_FORWARDING_AMP] = "Unexpected `&` when the parent method is not forwarding", + [YP_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES] = "Unexpected `...` when the parent method is not forwarding", + [YP_ERR_ARGUMENT_NO_FORWARDING_STAR] = "Unexpected `*` when the parent method is not forwarding", + [YP_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT] = "Unexpected `*` splat argument after a `**` keyword splat argument", + [YP_ERR_ARGUMENT_SPLAT_AFTER_SPLAT] = "Unexpected `*` splat argument after a `*` splat argument", + [YP_ERR_ARGUMENT_TERM_PAREN] = "Expected a `)` to close the arguments", + [YP_ERR_ARGUMENT_UNEXPECTED_BLOCK] = "Unexpected `{` after a method call without parenthesis", + [YP_ERR_ARRAY_ELEMENT] = "Expected an element for the array", + [YP_ERR_ARRAY_EXPRESSION] = "Expected an expression for the array element", + [YP_ERR_ARRAY_EXPRESSION_AFTER_STAR] = "Expected an expression after `*` in the array", + [YP_ERR_ARRAY_SEPARATOR] = "Expected a `,` separator for the array elements", + [YP_ERR_ARRAY_TERM] = "Expected a `]` to close the array", + [YP_ERR_BEGIN_LONELY_ELSE] = "Unexpected `else` in `begin` block; a `rescue` clause must precede `else`", + [YP_ERR_BEGIN_TERM] = "Expected an `end` to close the `begin` statement", + [YP_ERR_BEGIN_UPCASE_BRACE] = "Expected a `{` after `BEGIN`", + [YP_ERR_BEGIN_UPCASE_TERM] = "Expected a `}` to close the `BEGIN` statement", + [YP_ERR_BLOCK_PARAM_LOCAL_VARIABLE] = "Expected a local variable name in the block parameters", + [YP_ERR_BLOCK_PARAM_PIPE_TERM] = "Expected the block parameters to end with `|`", + [YP_ERR_BLOCK_TERM_BRACE] = "Expected a block beginning with `{` to end with `}`", + [YP_ERR_BLOCK_TERM_END] = "Expected a block beginning with `do` to end with `end`", + [YP_ERR_CANNOT_PARSE_EXPRESSION] = "Cannot parse the expression", + [YP_ERR_CANNOT_PARSE_STRING_PART] = "Cannot parse the string part", + [YP_ERR_CASE_EXPRESSION_AFTER_CASE] = "Expected an expression after `case`", + [YP_ERR_CASE_EXPRESSION_AFTER_WHEN] = "Expected an expression after `when`", + [YP_ERR_CASE_MISSING_CONDITIONS] = "Expected a `when` or `in` clause after `case`", + [YP_ERR_CASE_TERM] = "Expected an `end` to close the `case` statement", + [YP_ERR_CLASS_IN_METHOD] = "Unexpected class definition in a method body", + [YP_ERR_CLASS_NAME] = "Expected a constant name after `class`", + [YP_ERR_CLASS_SUPERCLASS] = "Expected a superclass after `<`", + [YP_ERR_CLASS_TERM] = "Expected an `end` to close the `class` statement", + [YP_ERR_CONDITIONAL_ELSIF_PREDICATE] = "Expected a predicate expression for the `elsif` statement", + [YP_ERR_CONDITIONAL_IF_PREDICATE] = "Expected a predicate expression for the `if` statement", + [YP_ERR_CONDITIONAL_TERM] = "Expected an `end` to close the conditional clause", + [YP_ERR_CONDITIONAL_TERM_ELSE] = "Expected an `end` to close the `else` clause", + [YP_ERR_CONDITIONAL_UNLESS_PREDICATE] = "Expected a predicate expression for the `unless` statement", + [YP_ERR_CONDITIONAL_UNTIL_PREDICATE] = "Expected a predicate expression for the `until` statement", + [YP_ERR_CONDITIONAL_WHILE_PREDICATE] = "Expected a predicate expression for the `while` statement", + [YP_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT] = "Expected a constant after the `::` operator", + [YP_ERR_DEF_ENDLESS] = "Could not parse the endless method body", + [YP_ERR_DEF_ENDLESS_SETTER] = "Invalid method name; a setter method cannot be defined in an endless method definition", + [YP_ERR_DEF_NAME] = "Expected a method name", + [YP_ERR_DEF_NAME_AFTER_RECEIVER] = "Expected a method name after the receiver", + [YP_ERR_DEF_PARAMS_TERM] = "Expected a delimiter to close the parameters", + [YP_ERR_DEF_PARAMS_TERM_PAREN] = "Expected a `)` to close the parameters", + [YP_ERR_DEF_RECEIVER] = "Expected a receiver for the method definition", + [YP_ERR_DEF_RECEIVER_TERM] = "Expected a `.` or `::` after the receiver in a method definition", + [YP_ERR_DEF_TERM] = "Expected an `end` to close the `def` statement", + [YP_ERR_DEFINED_EXPRESSION] = "Expected an expression after `defined?`", + [YP_ERR_EMBDOC_TERM] = "Could not find a terminator for the embedded document", + [YP_ERR_EMBEXPR_END] = "Expected a `}` to close the embedded expression", + [YP_ERR_EMBVAR_INVALID] = "Invalid embedded variable", + [YP_ERR_END_UPCASE_BRACE] = "Expected a `{` after `END`", + [YP_ERR_END_UPCASE_TERM] = "Expected a `}` to close the `END` statement", + [YP_ERR_ESCAPE_INVALID_CONTROL] = "Invalid control escape sequence", + [YP_ERR_ESCAPE_INVALID_CONTROL_REPEAT] = "Invalid control escape sequence; control cannot be repeated", + [YP_ERR_ESCAPE_INVALID_HEXADECIMAL] = "Invalid hexadecimal escape sequence", + [YP_ERR_ESCAPE_INVALID_META] = "Invalid meta escape sequence", + [YP_ERR_ESCAPE_INVALID_META_REPEAT] = "Invalid meta escape sequence; meta cannot be repeated", + [YP_ERR_ESCAPE_INVALID_UNICODE] = "Invalid Unicode escape sequence", + [YP_ERR_ESCAPE_INVALID_UNICODE_CM_FLAGS] = "Invalid Unicode escape sequence; Unicode cannot be combined with control or meta flags", + [YP_ERR_ESCAPE_INVALID_UNICODE_LITERAL] = "Invalid Unicode escape sequence; multiple codepoints are not allowed in a character literal", + [YP_ERR_ESCAPE_INVALID_UNICODE_LONG] = "Invalid Unicode escape sequence; maximum length is 6 digits", + [YP_ERR_ESCAPE_INVALID_UNICODE_TERM] = "Invalid Unicode escape sequence; needs closing `}`", + [YP_ERR_EXPECT_ARGUMENT] = "Expected an argument", + [YP_ERR_EXPECT_EOL_AFTER_STATEMENT] = "Expected a newline or semicolon after the statement", + [YP_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ] = "Expected an expression after `&&=`", + [YP_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ] = "Expected an expression after `||=`", + [YP_ERR_EXPECT_EXPRESSION_AFTER_COMMA] = "Expected an expression after `,`", + [YP_ERR_EXPECT_EXPRESSION_AFTER_EQUAL] = "Expected an expression after `=`", + [YP_ERR_EXPECT_EXPRESSION_AFTER_LESS_LESS] = "Expected an expression after `<<`", + [YP_ERR_EXPECT_EXPRESSION_AFTER_LPAREN] = "Expected an expression after `(`", + [YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR] = "Expected an expression after the operator", + [YP_ERR_EXPECT_EXPRESSION_AFTER_SPLAT] = "Expected an expression after `*` splat in an argument", + [YP_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH] = "Expected an expression after `**` in a hash", + [YP_ERR_EXPECT_EXPRESSION_AFTER_STAR] = "Expected an expression after `*`", + [YP_ERR_EXPECT_IDENT_REQ_PARAMETER] = "Expected an identifier for the required parameter", + [YP_ERR_EXPECT_LPAREN_REQ_PARAMETER] = "Expected a `(` to start a required parameter", + [YP_ERR_EXPECT_RBRACKET] = "Expected a matching `]`", + [YP_ERR_EXPECT_RPAREN] = "Expected a matching `)`", + [YP_ERR_EXPECT_RPAREN_AFTER_MULTI] = "Expected a `)` after multiple assignment", + [YP_ERR_EXPECT_RPAREN_REQ_PARAMETER] = "Expected a `)` to end a required parameter", + [YP_ERR_EXPECT_STRING_CONTENT] = "Expected string content after opening string delimiter", + [YP_ERR_EXPECT_WHEN_DELIMITER] = "Expected a delimiter after the predicates of a `when` clause", + [YP_ERR_EXPRESSION_BARE_HASH] = "Unexpected bare hash in expression", + [YP_ERR_FOR_COLLECTION] = "Expected a collection after the `in` in a `for` statement", + [YP_ERR_FOR_INDEX] = "Expected an index after `for`", + [YP_ERR_FOR_IN] = "Expected an `in` after the index in a `for` statement", + [YP_ERR_FOR_TERM] = "Expected an `end` to close the `for` loop", + [YP_ERR_HASH_EXPRESSION_AFTER_LABEL] = "Expected an expression after the label in a hash", + [YP_ERR_HASH_KEY] = "Expected a key in the hash literal", + [YP_ERR_HASH_ROCKET] = "Expected a `=>` between the hash key and value", + [YP_ERR_HASH_TERM] = "Expected a `}` to close the hash literal", + [YP_ERR_HASH_VALUE] = "Expected a value in the hash literal", + [YP_ERR_HEREDOC_TERM] = "Could not find a terminator for the heredoc", + [YP_ERR_INCOMPLETE_QUESTION_MARK] = "Incomplete expression at `?`", + [YP_ERR_INCOMPLETE_VARIABLE_CLASS] = "Incomplete class variable", + [YP_ERR_INCOMPLETE_VARIABLE_INSTANCE] = "Incomplete instance variable", + [YP_ERR_INVALID_ENCODING_MAGIC_COMMENT] = "Unknown or invalid encoding in the magic comment", + [YP_ERR_INVALID_FLOAT_EXPONENT] = "Invalid exponent", + [YP_ERR_INVALID_NUMBER_BINARY] = "Invalid binary number", + [YP_ERR_INVALID_NUMBER_DECIMAL] = "Invalid decimal number", + [YP_ERR_INVALID_NUMBER_HEXADECIMAL] = "Invalid hexadecimal number", + [YP_ERR_INVALID_NUMBER_OCTAL] = "Invalid octal number", + [YP_ERR_INVALID_NUMBER_UNDERSCORE] = "Invalid underscore placement in number", + [YP_ERR_INVALID_PERCENT] = "Invalid `%` token", // TODO WHAT? + [YP_ERR_INVALID_TOKEN] = "Invalid token", // TODO WHAT? + [YP_ERR_INVALID_VARIABLE_GLOBAL] = "Invalid global variable", + [YP_ERR_LAMBDA_OPEN] = "Expected a `do` keyword or a `{` to open the lambda block", + [YP_ERR_LAMBDA_TERM_BRACE] = "Expected a lambda block beginning with `{` to end with `}`", + [YP_ERR_LAMBDA_TERM_END] = "Expected a lambda block beginning with `do` to end with `end`", + [YP_ERR_LIST_I_LOWER_ELEMENT] = "Expected a symbol in a `%i` list", + [YP_ERR_LIST_I_LOWER_TERM] = "Expected a closing delimiter for the `%i` list", + [YP_ERR_LIST_I_UPPER_ELEMENT] = "Expected a symbol in a `%I` list", + [YP_ERR_LIST_I_UPPER_TERM] = "Expected a closing delimiter for the `%I` list", + [YP_ERR_LIST_W_LOWER_ELEMENT] = "Expected a string in a `%w` list", + [YP_ERR_LIST_W_LOWER_TERM] = "Expected a closing delimiter for the `%w` list", + [YP_ERR_LIST_W_UPPER_ELEMENT] = "Expected a string in a `%W` list", + [YP_ERR_LIST_W_UPPER_TERM] = "Expected a closing delimiter for the `%W` list", + [YP_ERR_MALLOC_FAILED] = "Failed to allocate memory", + [YP_ERR_MODULE_IN_METHOD] = "Unexpected module definition in a method body", + [YP_ERR_MODULE_NAME] = "Expected a constant name after `module`", + [YP_ERR_MODULE_TERM] = "Expected an `end` to close the `module` statement", + [YP_ERR_MULTI_ASSIGN_MULTI_SPLATS] = "Multiple splats in multiple assignment", + [YP_ERR_NOT_EXPRESSION] = "Expected an expression after `not`", + [YP_ERR_NUMBER_LITERAL_UNDERSCORE] = "Number literal ending with a `_`", + [YP_ERR_NUMBERED_PARAMETER_NOT_ALLOWED] = "Numbered parameters are not allowed alongside explicit parameters", + [YP_ERR_NUMBERED_PARAMETER_OUTER_SCOPE] = "Numbered parameter is already used in outer scope", + [YP_ERR_OPERATOR_MULTI_ASSIGN] = "Unexpected operator for a multiple assignment", + [YP_ERR_OPERATOR_WRITE_BLOCK] = "Unexpected operator after a call with a block", + [YP_ERR_PARAMETER_ASSOC_SPLAT_MULTI] = "Unexpected multiple `**` splat parameters", + [YP_ERR_PARAMETER_BLOCK_MULTI] = "Multiple block parameters; only one block is allowed", + [YP_ERR_PARAMETER_NAME_REPEAT] = "Repeated parameter name", + [YP_ERR_PARAMETER_NO_DEFAULT] = "Expected a default value for the parameter", + [YP_ERR_PARAMETER_NO_DEFAULT_KW] = "Expected a default value for the keyword parameter", + [YP_ERR_PARAMETER_NUMBERED_RESERVED] = "Token reserved for a numbered parameter", + [YP_ERR_PARAMETER_ORDER] = "Unexpected parameter order", + [YP_ERR_PARAMETER_SPLAT_MULTI] = "Unexpected multiple `*` splat parameters", + [YP_ERR_PARAMETER_STAR] = "Unexpected parameter `*`", + [YP_ERR_PARAMETER_WILD_LOOSE_COMMA] = "Unexpected `,` in parameters", + [YP_ERR_PATTERN_EXPRESSION_AFTER_BRACKET] = "Expected a pattern expression after the `[` operator", + [YP_ERR_PATTERN_EXPRESSION_AFTER_COMMA] = "Expected a pattern expression after `,`", + [YP_ERR_PATTERN_EXPRESSION_AFTER_HROCKET] = "Expected a pattern expression after `=>`", + [YP_ERR_PATTERN_EXPRESSION_AFTER_IN] = "Expected a pattern expression after the `in` keyword", + [YP_ERR_PATTERN_EXPRESSION_AFTER_KEY] = "Expected a pattern expression after the key", + [YP_ERR_PATTERN_EXPRESSION_AFTER_PAREN] = "Expected a pattern expression after the `(` operator", + [YP_ERR_PATTERN_EXPRESSION_AFTER_PIN] = "Expected a pattern expression after the `^` pin operator", + [YP_ERR_PATTERN_EXPRESSION_AFTER_PIPE] = "Expected a pattern expression after the `|` operator", + [YP_ERR_PATTERN_EXPRESSION_AFTER_RANGE] = "Expected a pattern expression after the range operator", + [YP_ERR_PATTERN_HASH_KEY] = "Expected a key in the hash pattern", + [YP_ERR_PATTERN_HASH_KEY_LABEL] = "Expected a label as the key in the hash pattern", // TODO // THIS // AND // ABOVE // IS WEIRD + [YP_ERR_PATTERN_IDENT_AFTER_HROCKET] = "Expected an identifier after the `=>` operator", + [YP_ERR_PATTERN_LABEL_AFTER_COMMA] = "Expected a label after the `,` in the hash pattern", + [YP_ERR_PATTERN_REST] = "Unexpected rest pattern", + [YP_ERR_PATTERN_TERM_BRACE] = "Expected a `}` to close the pattern expression", + [YP_ERR_PATTERN_TERM_BRACKET] = "Expected a `]` to close the pattern expression", + [YP_ERR_PATTERN_TERM_PAREN] = "Expected a `)` to close the pattern expression", + [YP_ERR_PIPEPIPEEQ_MULTI_ASSIGN] = "Unexpected `||=` in a multiple assignment", + [YP_ERR_REGEXP_TERM] = "Expected a closing delimiter for the regular expression", + [YP_ERR_RESCUE_EXPRESSION] = "Expected a rescued expression", + [YP_ERR_RESCUE_MODIFIER_VALUE] = "Expected a value after the `rescue` modifier", + [YP_ERR_RESCUE_TERM] = "Expected a closing delimiter for the `rescue` clause", + [YP_ERR_RESCUE_VARIABLE] = "Expected an exception variable after `=>` in a rescue statement", + [YP_ERR_RETURN_INVALID] = "Invalid `return` in a class or module body", + [YP_ERR_STRING_CONCATENATION] = "Expected a string for concatenation", + [YP_ERR_STRING_INTERPOLATED_TERM] = "Expected a closing delimiter for the interpolated string", + [YP_ERR_STRING_LITERAL_TERM] = "Expected a closing delimiter for the string literal", + [YP_ERR_SYMBOL_INVALID] = "Invalid symbol", // TODO expected symbol? yarp.c ~9719 + [YP_ERR_SYMBOL_TERM_DYNAMIC] = "Expected a closing delimiter for the dynamic symbol", + [YP_ERR_SYMBOL_TERM_INTERPOLATED] = "Expected a closing delimiter for the interpolated symbol", + [YP_ERR_TERNARY_COLON] = "Expected a `:` after the true expression of a ternary operator", + [YP_ERR_TERNARY_EXPRESSION_FALSE] = "Expected an expression after `:` in the ternary operator", + [YP_ERR_TERNARY_EXPRESSION_TRUE] = "Expected an expression after `?` in the ternary operator", + [YP_ERR_UNDEF_ARGUMENT] = "Invalid argument being passed to `undef`; expected a bare word, constant, or symbol argument", + [YP_ERR_UNARY_RECEIVER_BANG] = "Expected a receiver for unary `!`", + [YP_ERR_UNARY_RECEIVER_MINUS] = "Expected a receiver for unary `-`", + [YP_ERR_UNARY_RECEIVER_PLUS] = "Expected a receiver for unary `+`", + [YP_ERR_UNARY_RECEIVER_TILDE] = "Expected a receiver for unary `~`", + [YP_ERR_UNTIL_TERM] = "Expected an `end` to close the `until` statement", + [YP_ERR_WHILE_TERM] = "Expected an `end` to close the `while` statement", + [YP_ERR_WRITE_TARGET_READONLY] = "Immutable variable as a write target", + [YP_ERR_WRITE_TARGET_UNEXPECTED] = "Unexpected write target", + [YP_ERR_XSTRING_TERM] = "Expected a closing delimiter for the `%x` or backtick string", + [YP_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS] = "Ambiguous first argument; put parentheses or a space even after `-` operator", + [YP_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS] = "Ambiguous first argument; put parentheses or a space even after `+` operator", + [YP_WARN_AMBIGUOUS_PREFIX_STAR] = "Ambiguous `*` has been interpreted as an argument prefix", + [YP_WARN_AMBIGUOUS_SLASH] = "Ambiguous `/`; wrap regexp in parentheses or add a space after `/` operator", +}; + +static const char* +yp_diagnostic_message(yp_diagnostic_id_t diag_id) { + assert(diag_id < YP_DIAGNOSTIC_ID_LEN); + const char *message = diagnostic_messages[diag_id]; + assert(message); + return message; +} + // Append an error to the given list of diagnostic. bool -yp_diagnostic_list_append(yp_list_t *list, const uint8_t *start, const uint8_t *end, const char *message) { +yp_diagnostic_list_append(yp_list_t *list, const uint8_t *start, const uint8_t *end, yp_diagnostic_id_t diag_id) { yp_diagnostic_t *diagnostic = (yp_diagnostic_t *) malloc(sizeof(yp_diagnostic_t)); if (diagnostic == NULL) return false; - *diagnostic = (yp_diagnostic_t) { .start = start, .end = end, .message = message }; + *diagnostic = (yp_diagnostic_t) { .start = start, .end = end, .message = yp_diagnostic_message(diag_id) }; yp_list_append(list, (yp_list_node_t *) diagnostic); return true; } diff --git a/src/main/c/yarp/src/enc/yp_unicode.c b/src/main/c/yarp/src/enc/yp_unicode.c index bb4e041309ba..196955d48376 100644 --- a/src/main/c/yarp/src/enc/yp_unicode.c +++ b/src/main/c/yarp/src/enc/yp_unicode.c @@ -10,7 +10,7 @@ typedef uint32_t yp_unicode_codepoint_t; // this table is different from other encodings where we used a lookup table // because the indices of those tables are the byte representations, not the // codepoints themselves. -uint8_t yp_encoding_unicode_table[256] = { +const uint8_t yp_encoding_unicode_table[256] = { // 0 1 2 3 4 5 6 7 8 9 A B C D E F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x @@ -31,7 +31,7 @@ uint8_t yp_encoding_unicode_table[256] = { }; #define UNICODE_ALPHA_CODEPOINTS_LENGTH 1450 -static yp_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEPOINTS_LENGTH] = { +static const yp_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEPOINTS_LENGTH] = { 0x100, 0x2C1, 0x2C6, 0x2D1, 0x2E0, 0x2E4, @@ -760,7 +760,7 @@ static yp_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEPOINTS_ }; #define UNICODE_ALNUM_CODEPOINTS_LENGTH 1528 -static yp_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEPOINTS_LENGTH] = { +static const yp_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEPOINTS_LENGTH] = { 0x100, 0x2C1, 0x2C6, 0x2D1, 0x2E0, 0x2E4, @@ -1528,7 +1528,7 @@ static yp_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEPOINTS_ }; #define UNICODE_ISUPPER_CODEPOINTS_LENGTH 1296 -static yp_unicode_codepoint_t unicode_isupper_codepoints[UNICODE_ISUPPER_CODEPOINTS_LENGTH] = { +static const yp_unicode_codepoint_t unicode_isupper_codepoints[UNICODE_ISUPPER_CODEPOINTS_LENGTH] = { 0x100, 0x100, 0x102, 0x102, 0x104, 0x104, @@ -2180,7 +2180,7 @@ static yp_unicode_codepoint_t unicode_isupper_codepoints[UNICODE_ISUPPER_CODEPOI }; static bool -yp_unicode_codepoint_match(yp_unicode_codepoint_t codepoint, yp_unicode_codepoint_t *codepoints, size_t size) { +yp_unicode_codepoint_match(yp_unicode_codepoint_t codepoint, const yp_unicode_codepoint_t *codepoints, size_t size) { size_t start = 0; size_t end = size; diff --git a/src/main/c/yarp/src/node.c b/src/main/c/yarp/src/node.c index ddc9348be889..3b75aef054db 100644 --- a/src/main/c/yarp/src/node.c +++ b/src/main/c/yarp/src/node.c @@ -15,30 +15,6 @@ void yp_node_clear(yp_node_t *node) { node->location = location; } -// Calculate the size of the token list in bytes. -static size_t -yp_location_list_memsize(yp_location_list_t *list) { - return sizeof(yp_location_list_t) + (list->capacity * sizeof(yp_location_t)); -} - -// Append a token to the given list. -void -yp_location_list_append(yp_location_list_t *list, const yp_token_t *token) { - if (list->size == list->capacity) { - list->capacity = list->capacity == 0 ? 2 : list->capacity * 2; - list->locations = (yp_location_t *) realloc(list->locations, sizeof(yp_location_t) * list->capacity); - } - list->locations[list->size++] = (yp_location_t) { .start = token->start, .end = token->end }; -} - -// Free the memory associated with the token list. -static void -yp_location_list_free(yp_location_list_t *list) { - if (list->locations != NULL) { - free(list->locations); - } -} - static void yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize); @@ -83,41 +59,48 @@ yp_node_list_free(yp_parser_t *parser, yp_node_list_t *list) { YP_EXPORTED_FUNCTION void yp_node_destroy(yp_parser_t *parser, yp_node_t *node) { switch (YP_NODE_TYPE(node)) { -#line 81 "node.c.erb" - case YP_NODE_ALIAS_NODE: { - yp_alias_node_t *cast = (yp_alias_node_t *) node; +#line 57 "node.c.erb" + case YP_ALIAS_GLOBAL_VARIABLE_NODE: { + yp_alias_global_variable_node_t *cast = (yp_alias_global_variable_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->new_name); yp_node_destroy(parser, (yp_node_t *)cast->old_name); break; } -#line 81 "node.c.erb" - case YP_NODE_ALTERNATION_PATTERN_NODE: { +#line 57 "node.c.erb" + case YP_ALIAS_METHOD_NODE: { + yp_alias_method_node_t *cast = (yp_alias_method_node_t *) node; + yp_node_destroy(parser, (yp_node_t *)cast->new_name); + yp_node_destroy(parser, (yp_node_t *)cast->old_name); + break; + } +#line 57 "node.c.erb" + case YP_ALTERNATION_PATTERN_NODE: { yp_alternation_pattern_node_t *cast = (yp_alternation_pattern_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->left); yp_node_destroy(parser, (yp_node_t *)cast->right); break; } -#line 81 "node.c.erb" - case YP_NODE_AND_NODE: { +#line 57 "node.c.erb" + case YP_AND_NODE: { yp_and_node_t *cast = (yp_and_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->left); yp_node_destroy(parser, (yp_node_t *)cast->right); break; } -#line 81 "node.c.erb" - case YP_NODE_ARGUMENTS_NODE: { +#line 57 "node.c.erb" + case YP_ARGUMENTS_NODE: { yp_arguments_node_t *cast = (yp_arguments_node_t *) node; yp_node_list_free(parser, &cast->arguments); break; } -#line 81 "node.c.erb" - case YP_NODE_ARRAY_NODE: { +#line 57 "node.c.erb" + case YP_ARRAY_NODE: { yp_array_node_t *cast = (yp_array_node_t *) node; yp_node_list_free(parser, &cast->elements); break; } -#line 81 "node.c.erb" - case YP_NODE_ARRAY_PATTERN_NODE: { +#line 57 "node.c.erb" + case YP_ARRAY_PATTERN_NODE: { yp_array_pattern_node_t *cast = (yp_array_pattern_node_t *) node; if (cast->constant != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->constant); @@ -129,8 +112,8 @@ yp_node_destroy(yp_parser_t *parser, yp_node_t *node) { yp_node_list_free(parser, &cast->posts); break; } -#line 81 "node.c.erb" - case YP_NODE_ASSOC_NODE: { +#line 57 "node.c.erb" + case YP_ASSOC_NODE: { yp_assoc_node_t *cast = (yp_assoc_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->key); if (cast->value != NULL) { @@ -138,20 +121,20 @@ yp_node_destroy(yp_parser_t *parser, yp_node_t *node) { } break; } -#line 81 "node.c.erb" - case YP_NODE_ASSOC_SPLAT_NODE: { +#line 57 "node.c.erb" + case YP_ASSOC_SPLAT_NODE: { yp_assoc_splat_node_t *cast = (yp_assoc_splat_node_t *) node; if (cast->value != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->value); } break; } -#line 81 "node.c.erb" - case YP_NODE_BACK_REFERENCE_READ_NODE: { +#line 57 "node.c.erb" + case YP_BACK_REFERENCE_READ_NODE: { break; } -#line 81 "node.c.erb" - case YP_NODE_BEGIN_NODE: { +#line 57 "node.c.erb" + case YP_BEGIN_NODE: { yp_begin_node_t *cast = (yp_begin_node_t *) node; if (cast->statements != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->statements); @@ -167,16 +150,20 @@ yp_node_destroy(yp_parser_t *parser, yp_node_t *node) { } break; } -#line 81 "node.c.erb" - case YP_NODE_BLOCK_ARGUMENT_NODE: { +#line 57 "node.c.erb" + case YP_BLOCK_ARGUMENT_NODE: { yp_block_argument_node_t *cast = (yp_block_argument_node_t *) node; if (cast->expression != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->expression); } break; } -#line 81 "node.c.erb" - case YP_NODE_BLOCK_NODE: { +#line 57 "node.c.erb" + case YP_BLOCK_LOCAL_VARIABLE_NODE: { + break; + } +#line 57 "node.c.erb" + case YP_BLOCK_NODE: { yp_block_node_t *cast = (yp_block_node_t *) node; yp_constant_id_list_free(&cast->locals); if (cast->parameters != NULL) { @@ -187,29 +174,43 @@ yp_node_destroy(yp_parser_t *parser, yp_node_t *node) { } break; } -#line 81 "node.c.erb" - case YP_NODE_BLOCK_PARAMETER_NODE: { +#line 57 "node.c.erb" + case YP_BLOCK_PARAMETER_NODE: { break; } -#line 81 "node.c.erb" - case YP_NODE_BLOCK_PARAMETERS_NODE: { +#line 57 "node.c.erb" + case YP_BLOCK_PARAMETERS_NODE: { yp_block_parameters_node_t *cast = (yp_block_parameters_node_t *) node; if (cast->parameters != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->parameters); } - yp_location_list_free(&cast->locals); + yp_node_list_free(parser, &cast->locals); break; } -#line 81 "node.c.erb" - case YP_NODE_BREAK_NODE: { +#line 57 "node.c.erb" + case YP_BREAK_NODE: { yp_break_node_t *cast = (yp_break_node_t *) node; if (cast->arguments != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->arguments); } break; } -#line 81 "node.c.erb" - case YP_NODE_CALL_NODE: { +#line 57 "node.c.erb" + case YP_CALL_AND_WRITE_NODE: { + yp_call_and_write_node_t *cast = (yp_call_and_write_node_t *) node; + if (cast->receiver != NULL) { + yp_node_destroy(parser, (yp_node_t *)cast->receiver); + } + if (cast->arguments != NULL) { + yp_node_destroy(parser, (yp_node_t *)cast->arguments); + } + yp_string_free(&cast->read_name); + yp_string_free(&cast->write_name); + yp_node_destroy(parser, (yp_node_t *)cast->value); + break; + } +#line 57 "node.c.erb" + case YP_CALL_NODE: { yp_call_node_t *cast = (yp_call_node_t *) node; if (cast->receiver != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->receiver); @@ -223,36 +224,43 @@ yp_node_destroy(yp_parser_t *parser, yp_node_t *node) { yp_string_free(&cast->name); break; } -#line 81 "node.c.erb" - case YP_NODE_CALL_OPERATOR_AND_WRITE_NODE: { - yp_call_operator_and_write_node_t *cast = (yp_call_operator_and_write_node_t *) node; - yp_node_destroy(parser, (yp_node_t *)cast->target); - yp_node_destroy(parser, (yp_node_t *)cast->value); - break; - } -#line 81 "node.c.erb" - case YP_NODE_CALL_OPERATOR_OR_WRITE_NODE: { - yp_call_operator_or_write_node_t *cast = (yp_call_operator_or_write_node_t *) node; - yp_node_destroy(parser, (yp_node_t *)cast->target); +#line 57 "node.c.erb" + case YP_CALL_OPERATOR_WRITE_NODE: { + yp_call_operator_write_node_t *cast = (yp_call_operator_write_node_t *) node; + if (cast->receiver != NULL) { + yp_node_destroy(parser, (yp_node_t *)cast->receiver); + } + if (cast->arguments != NULL) { + yp_node_destroy(parser, (yp_node_t *)cast->arguments); + } + yp_string_free(&cast->read_name); + yp_string_free(&cast->write_name); yp_node_destroy(parser, (yp_node_t *)cast->value); break; } -#line 81 "node.c.erb" - case YP_NODE_CALL_OPERATOR_WRITE_NODE: { - yp_call_operator_write_node_t *cast = (yp_call_operator_write_node_t *) node; - yp_node_destroy(parser, (yp_node_t *)cast->target); +#line 57 "node.c.erb" + case YP_CALL_OR_WRITE_NODE: { + yp_call_or_write_node_t *cast = (yp_call_or_write_node_t *) node; + if (cast->receiver != NULL) { + yp_node_destroy(parser, (yp_node_t *)cast->receiver); + } + if (cast->arguments != NULL) { + yp_node_destroy(parser, (yp_node_t *)cast->arguments); + } + yp_string_free(&cast->read_name); + yp_string_free(&cast->write_name); yp_node_destroy(parser, (yp_node_t *)cast->value); break; } -#line 81 "node.c.erb" - case YP_NODE_CAPTURE_PATTERN_NODE: { +#line 57 "node.c.erb" + case YP_CAPTURE_PATTERN_NODE: { yp_capture_pattern_node_t *cast = (yp_capture_pattern_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->value); yp_node_destroy(parser, (yp_node_t *)cast->target); break; } -#line 81 "node.c.erb" - case YP_NODE_CASE_NODE: { +#line 57 "node.c.erb" + case YP_CASE_NODE: { yp_case_node_t *cast = (yp_case_node_t *) node; if (cast->predicate != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->predicate); @@ -263,8 +271,8 @@ yp_node_destroy(yp_parser_t *parser, yp_node_t *node) { } break; } -#line 81 "node.c.erb" - case YP_NODE_CLASS_NODE: { +#line 57 "node.c.erb" + case YP_CLASS_NODE: { yp_class_node_t *cast = (yp_class_node_t *) node; yp_constant_id_list_free(&cast->locals); yp_node_destroy(parser, (yp_node_t *)cast->constant_path); @@ -274,70 +282,67 @@ yp_node_destroy(yp_parser_t *parser, yp_node_t *node) { if (cast->body != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->body); } - yp_string_free(&cast->name); break; } -#line 81 "node.c.erb" - case YP_NODE_CLASS_VARIABLE_AND_WRITE_NODE: { +#line 57 "node.c.erb" + case YP_CLASS_VARIABLE_AND_WRITE_NODE: { yp_class_variable_and_write_node_t *cast = (yp_class_variable_and_write_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->value); break; } -#line 81 "node.c.erb" - case YP_NODE_CLASS_VARIABLE_OPERATOR_WRITE_NODE: { +#line 57 "node.c.erb" + case YP_CLASS_VARIABLE_OPERATOR_WRITE_NODE: { yp_class_variable_operator_write_node_t *cast = (yp_class_variable_operator_write_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->value); break; } -#line 81 "node.c.erb" - case YP_NODE_CLASS_VARIABLE_OR_WRITE_NODE: { +#line 57 "node.c.erb" + case YP_CLASS_VARIABLE_OR_WRITE_NODE: { yp_class_variable_or_write_node_t *cast = (yp_class_variable_or_write_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->value); break; } -#line 81 "node.c.erb" - case YP_NODE_CLASS_VARIABLE_READ_NODE: { +#line 57 "node.c.erb" + case YP_CLASS_VARIABLE_READ_NODE: { break; } -#line 81 "node.c.erb" - case YP_NODE_CLASS_VARIABLE_TARGET_NODE: { +#line 57 "node.c.erb" + case YP_CLASS_VARIABLE_TARGET_NODE: { break; } -#line 81 "node.c.erb" - case YP_NODE_CLASS_VARIABLE_WRITE_NODE: { +#line 57 "node.c.erb" + case YP_CLASS_VARIABLE_WRITE_NODE: { yp_class_variable_write_node_t *cast = (yp_class_variable_write_node_t *) node; - if (cast->value != NULL) { - yp_node_destroy(parser, (yp_node_t *)cast->value); - } + yp_node_destroy(parser, (yp_node_t *)cast->value); break; } -#line 81 "node.c.erb" - case YP_NODE_CONSTANT_AND_WRITE_NODE: { +#line 57 "node.c.erb" + case YP_CONSTANT_AND_WRITE_NODE: { yp_constant_and_write_node_t *cast = (yp_constant_and_write_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->value); break; } -#line 81 "node.c.erb" - case YP_NODE_CONSTANT_OPERATOR_WRITE_NODE: { +#line 57 "node.c.erb" + case YP_CONSTANT_OPERATOR_WRITE_NODE: { yp_constant_operator_write_node_t *cast = (yp_constant_operator_write_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->value); break; } -#line 81 "node.c.erb" - case YP_NODE_CONSTANT_OR_WRITE_NODE: { +#line 57 "node.c.erb" + case YP_CONSTANT_OR_WRITE_NODE: { yp_constant_or_write_node_t *cast = (yp_constant_or_write_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->value); break; } -#line 81 "node.c.erb" - case YP_NODE_CONSTANT_PATH_AND_WRITE_NODE: { +#line 57 "node.c.erb" + case YP_CONSTANT_PATH_AND_WRITE_NODE: { yp_constant_path_and_write_node_t *cast = (yp_constant_path_and_write_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->target); yp_node_destroy(parser, (yp_node_t *)cast->value); break; } -#line 81 "node.c.erb" - case YP_NODE_CONSTANT_PATH_NODE: { +#line 57 "node.c.erb" + case YP_CONSTANT_PATH_NODE: { yp_constant_path_node_t *cast = (yp_constant_path_node_t *) node; if (cast->parent != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->parent); @@ -345,22 +350,22 @@ yp_node_destroy(yp_parser_t *parser, yp_node_t *node) { yp_node_destroy(parser, (yp_node_t *)cast->child); break; } -#line 81 "node.c.erb" - case YP_NODE_CONSTANT_PATH_OPERATOR_WRITE_NODE: { +#line 57 "node.c.erb" + case YP_CONSTANT_PATH_OPERATOR_WRITE_NODE: { yp_constant_path_operator_write_node_t *cast = (yp_constant_path_operator_write_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->target); yp_node_destroy(parser, (yp_node_t *)cast->value); break; } -#line 81 "node.c.erb" - case YP_NODE_CONSTANT_PATH_OR_WRITE_NODE: { +#line 57 "node.c.erb" + case YP_CONSTANT_PATH_OR_WRITE_NODE: { yp_constant_path_or_write_node_t *cast = (yp_constant_path_or_write_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->target); yp_node_destroy(parser, (yp_node_t *)cast->value); break; } -#line 81 "node.c.erb" - case YP_NODE_CONSTANT_PATH_TARGET_NODE: { +#line 57 "node.c.erb" + case YP_CONSTANT_PATH_TARGET_NODE: { yp_constant_path_target_node_t *cast = (yp_constant_path_target_node_t *) node; if (cast->parent != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->parent); @@ -368,29 +373,29 @@ yp_node_destroy(yp_parser_t *parser, yp_node_t *node) { yp_node_destroy(parser, (yp_node_t *)cast->child); break; } -#line 81 "node.c.erb" - case YP_NODE_CONSTANT_PATH_WRITE_NODE: { +#line 57 "node.c.erb" + case YP_CONSTANT_PATH_WRITE_NODE: { yp_constant_path_write_node_t *cast = (yp_constant_path_write_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->target); yp_node_destroy(parser, (yp_node_t *)cast->value); break; } -#line 81 "node.c.erb" - case YP_NODE_CONSTANT_READ_NODE: { +#line 57 "node.c.erb" + case YP_CONSTANT_READ_NODE: { break; } -#line 81 "node.c.erb" - case YP_NODE_CONSTANT_TARGET_NODE: { +#line 57 "node.c.erb" + case YP_CONSTANT_TARGET_NODE: { break; } -#line 81 "node.c.erb" - case YP_NODE_CONSTANT_WRITE_NODE: { +#line 57 "node.c.erb" + case YP_CONSTANT_WRITE_NODE: { yp_constant_write_node_t *cast = (yp_constant_write_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->value); break; } -#line 81 "node.c.erb" - case YP_NODE_DEF_NODE: { +#line 57 "node.c.erb" + case YP_DEF_NODE: { yp_def_node_t *cast = (yp_def_node_t *) node; if (cast->receiver != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->receiver); @@ -404,48 +409,48 @@ yp_node_destroy(yp_parser_t *parser, yp_node_t *node) { yp_constant_id_list_free(&cast->locals); break; } -#line 81 "node.c.erb" - case YP_NODE_DEFINED_NODE: { +#line 57 "node.c.erb" + case YP_DEFINED_NODE: { yp_defined_node_t *cast = (yp_defined_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->value); break; } -#line 81 "node.c.erb" - case YP_NODE_ELSE_NODE: { +#line 57 "node.c.erb" + case YP_ELSE_NODE: { yp_else_node_t *cast = (yp_else_node_t *) node; if (cast->statements != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->statements); } break; } -#line 81 "node.c.erb" - case YP_NODE_EMBEDDED_STATEMENTS_NODE: { +#line 57 "node.c.erb" + case YP_EMBEDDED_STATEMENTS_NODE: { yp_embedded_statements_node_t *cast = (yp_embedded_statements_node_t *) node; if (cast->statements != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->statements); } break; } -#line 81 "node.c.erb" - case YP_NODE_EMBEDDED_VARIABLE_NODE: { +#line 57 "node.c.erb" + case YP_EMBEDDED_VARIABLE_NODE: { yp_embedded_variable_node_t *cast = (yp_embedded_variable_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->variable); break; } -#line 81 "node.c.erb" - case YP_NODE_ENSURE_NODE: { +#line 57 "node.c.erb" + case YP_ENSURE_NODE: { yp_ensure_node_t *cast = (yp_ensure_node_t *) node; if (cast->statements != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->statements); } break; } -#line 81 "node.c.erb" - case YP_NODE_FALSE_NODE: { +#line 57 "node.c.erb" + case YP_FALSE_NODE: { break; } -#line 81 "node.c.erb" - case YP_NODE_FIND_PATTERN_NODE: { +#line 57 "node.c.erb" + case YP_FIND_PATTERN_NODE: { yp_find_pattern_node_t *cast = (yp_find_pattern_node_t *) node; if (cast->constant != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->constant); @@ -455,8 +460,8 @@ yp_node_destroy(yp_parser_t *parser, yp_node_t *node) { yp_node_destroy(parser, (yp_node_t *)cast->right); break; } -#line 81 "node.c.erb" - case YP_NODE_FLIP_FLOP_NODE: { +#line 57 "node.c.erb" + case YP_FLIP_FLOP_NODE: { yp_flip_flop_node_t *cast = (yp_flip_flop_node_t *) node; if (cast->left != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->left); @@ -466,12 +471,12 @@ yp_node_destroy(yp_parser_t *parser, yp_node_t *node) { } break; } -#line 81 "node.c.erb" - case YP_NODE_FLOAT_NODE: { +#line 57 "node.c.erb" + case YP_FLOAT_NODE: { break; } -#line 81 "node.c.erb" - case YP_NODE_FOR_NODE: { +#line 57 "node.c.erb" + case YP_FOR_NODE: { yp_for_node_t *cast = (yp_for_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->index); yp_node_destroy(parser, (yp_node_t *)cast->collection); @@ -480,62 +485,62 @@ yp_node_destroy(yp_parser_t *parser, yp_node_t *node) { } break; } -#line 81 "node.c.erb" - case YP_NODE_FORWARDING_ARGUMENTS_NODE: { +#line 57 "node.c.erb" + case YP_FORWARDING_ARGUMENTS_NODE: { break; } -#line 81 "node.c.erb" - case YP_NODE_FORWARDING_PARAMETER_NODE: { +#line 57 "node.c.erb" + case YP_FORWARDING_PARAMETER_NODE: { break; } -#line 81 "node.c.erb" - case YP_NODE_FORWARDING_SUPER_NODE: { +#line 57 "node.c.erb" + case YP_FORWARDING_SUPER_NODE: { yp_forwarding_super_node_t *cast = (yp_forwarding_super_node_t *) node; if (cast->block != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->block); } break; } -#line 81 "node.c.erb" - case YP_NODE_GLOBAL_VARIABLE_AND_WRITE_NODE: { +#line 57 "node.c.erb" + case YP_GLOBAL_VARIABLE_AND_WRITE_NODE: { yp_global_variable_and_write_node_t *cast = (yp_global_variable_and_write_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->value); break; } -#line 81 "node.c.erb" - case YP_NODE_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE: { +#line 57 "node.c.erb" + case YP_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE: { yp_global_variable_operator_write_node_t *cast = (yp_global_variable_operator_write_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->value); break; } -#line 81 "node.c.erb" - case YP_NODE_GLOBAL_VARIABLE_OR_WRITE_NODE: { +#line 57 "node.c.erb" + case YP_GLOBAL_VARIABLE_OR_WRITE_NODE: { yp_global_variable_or_write_node_t *cast = (yp_global_variable_or_write_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->value); break; } -#line 81 "node.c.erb" - case YP_NODE_GLOBAL_VARIABLE_READ_NODE: { +#line 57 "node.c.erb" + case YP_GLOBAL_VARIABLE_READ_NODE: { break; } -#line 81 "node.c.erb" - case YP_NODE_GLOBAL_VARIABLE_TARGET_NODE: { +#line 57 "node.c.erb" + case YP_GLOBAL_VARIABLE_TARGET_NODE: { break; } -#line 81 "node.c.erb" - case YP_NODE_GLOBAL_VARIABLE_WRITE_NODE: { +#line 57 "node.c.erb" + case YP_GLOBAL_VARIABLE_WRITE_NODE: { yp_global_variable_write_node_t *cast = (yp_global_variable_write_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->value); break; } -#line 81 "node.c.erb" - case YP_NODE_HASH_NODE: { +#line 57 "node.c.erb" + case YP_HASH_NODE: { yp_hash_node_t *cast = (yp_hash_node_t *) node; yp_node_list_free(parser, &cast->elements); break; } -#line 81 "node.c.erb" - case YP_NODE_HASH_PATTERN_NODE: { +#line 57 "node.c.erb" + case YP_HASH_PATTERN_NODE: { yp_hash_pattern_node_t *cast = (yp_hash_pattern_node_t *) node; if (cast->constant != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->constant); @@ -546,8 +551,8 @@ yp_node_destroy(yp_parser_t *parser, yp_node_t *node) { } break; } -#line 81 "node.c.erb" - case YP_NODE_IF_NODE: { +#line 57 "node.c.erb" + case YP_IF_NODE: { yp_if_node_t *cast = (yp_if_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->predicate); if (cast->statements != NULL) { @@ -558,14 +563,20 @@ yp_node_destroy(yp_parser_t *parser, yp_node_t *node) { } break; } -#line 81 "node.c.erb" - case YP_NODE_IMAGINARY_NODE: { +#line 57 "node.c.erb" + case YP_IMAGINARY_NODE: { yp_imaginary_node_t *cast = (yp_imaginary_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->numeric); break; } -#line 81 "node.c.erb" - case YP_NODE_IN_NODE: { +#line 57 "node.c.erb" + case YP_IMPLICIT_NODE: { + yp_implicit_node_t *cast = (yp_implicit_node_t *) node; + yp_node_destroy(parser, (yp_node_t *)cast->value); + break; + } +#line 57 "node.c.erb" + case YP_IN_NODE: { yp_in_node_t *cast = (yp_in_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->pattern); if (cast->statements != NULL) { @@ -573,86 +584,92 @@ yp_node_destroy(yp_parser_t *parser, yp_node_t *node) { } break; } -#line 81 "node.c.erb" - case YP_NODE_INSTANCE_VARIABLE_AND_WRITE_NODE: { +#line 57 "node.c.erb" + case YP_INSTANCE_VARIABLE_AND_WRITE_NODE: { yp_instance_variable_and_write_node_t *cast = (yp_instance_variable_and_write_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->value); break; } -#line 81 "node.c.erb" - case YP_NODE_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE: { +#line 57 "node.c.erb" + case YP_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE: { yp_instance_variable_operator_write_node_t *cast = (yp_instance_variable_operator_write_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->value); break; } -#line 81 "node.c.erb" - case YP_NODE_INSTANCE_VARIABLE_OR_WRITE_NODE: { +#line 57 "node.c.erb" + case YP_INSTANCE_VARIABLE_OR_WRITE_NODE: { yp_instance_variable_or_write_node_t *cast = (yp_instance_variable_or_write_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->value); break; } -#line 81 "node.c.erb" - case YP_NODE_INSTANCE_VARIABLE_READ_NODE: { +#line 57 "node.c.erb" + case YP_INSTANCE_VARIABLE_READ_NODE: { break; } -#line 81 "node.c.erb" - case YP_NODE_INSTANCE_VARIABLE_TARGET_NODE: { +#line 57 "node.c.erb" + case YP_INSTANCE_VARIABLE_TARGET_NODE: { break; } -#line 81 "node.c.erb" - case YP_NODE_INSTANCE_VARIABLE_WRITE_NODE: { +#line 57 "node.c.erb" + case YP_INSTANCE_VARIABLE_WRITE_NODE: { yp_instance_variable_write_node_t *cast = (yp_instance_variable_write_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->value); break; } -#line 81 "node.c.erb" - case YP_NODE_INTEGER_NODE: { +#line 57 "node.c.erb" + case YP_INTEGER_NODE: { break; } -#line 81 "node.c.erb" - case YP_NODE_INTERPOLATED_REGULAR_EXPRESSION_NODE: { +#line 57 "node.c.erb" + case YP_INTERPOLATED_MATCH_LAST_LINE_NODE: { + yp_interpolated_match_last_line_node_t *cast = (yp_interpolated_match_last_line_node_t *) node; + yp_node_list_free(parser, &cast->parts); + break; + } +#line 57 "node.c.erb" + case YP_INTERPOLATED_REGULAR_EXPRESSION_NODE: { yp_interpolated_regular_expression_node_t *cast = (yp_interpolated_regular_expression_node_t *) node; yp_node_list_free(parser, &cast->parts); break; } -#line 81 "node.c.erb" - case YP_NODE_INTERPOLATED_STRING_NODE: { +#line 57 "node.c.erb" + case YP_INTERPOLATED_STRING_NODE: { yp_interpolated_string_node_t *cast = (yp_interpolated_string_node_t *) node; yp_node_list_free(parser, &cast->parts); break; } -#line 81 "node.c.erb" - case YP_NODE_INTERPOLATED_SYMBOL_NODE: { +#line 57 "node.c.erb" + case YP_INTERPOLATED_SYMBOL_NODE: { yp_interpolated_symbol_node_t *cast = (yp_interpolated_symbol_node_t *) node; yp_node_list_free(parser, &cast->parts); break; } -#line 81 "node.c.erb" - case YP_NODE_INTERPOLATED_X_STRING_NODE: { +#line 57 "node.c.erb" + case YP_INTERPOLATED_X_STRING_NODE: { yp_interpolated_x_string_node_t *cast = (yp_interpolated_x_string_node_t *) node; yp_node_list_free(parser, &cast->parts); break; } -#line 81 "node.c.erb" - case YP_NODE_KEYWORD_HASH_NODE: { +#line 57 "node.c.erb" + case YP_KEYWORD_HASH_NODE: { yp_keyword_hash_node_t *cast = (yp_keyword_hash_node_t *) node; yp_node_list_free(parser, &cast->elements); break; } -#line 81 "node.c.erb" - case YP_NODE_KEYWORD_PARAMETER_NODE: { +#line 57 "node.c.erb" + case YP_KEYWORD_PARAMETER_NODE: { yp_keyword_parameter_node_t *cast = (yp_keyword_parameter_node_t *) node; if (cast->value != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->value); } break; } -#line 81 "node.c.erb" - case YP_NODE_KEYWORD_REST_PARAMETER_NODE: { +#line 57 "node.c.erb" + case YP_KEYWORD_REST_PARAMETER_NODE: { break; } -#line 81 "node.c.erb" - case YP_NODE_LAMBDA_NODE: { +#line 57 "node.c.erb" + case YP_LAMBDA_NODE: { yp_lambda_node_t *cast = (yp_lambda_node_t *) node; yp_constant_id_list_free(&cast->locals); if (cast->parameters != NULL) { @@ -663,118 +680,134 @@ yp_node_destroy(yp_parser_t *parser, yp_node_t *node) { } break; } -#line 81 "node.c.erb" - case YP_NODE_LOCAL_VARIABLE_AND_WRITE_NODE: { +#line 57 "node.c.erb" + case YP_LOCAL_VARIABLE_AND_WRITE_NODE: { yp_local_variable_and_write_node_t *cast = (yp_local_variable_and_write_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->value); break; } -#line 81 "node.c.erb" - case YP_NODE_LOCAL_VARIABLE_OPERATOR_WRITE_NODE: { +#line 57 "node.c.erb" + case YP_LOCAL_VARIABLE_OPERATOR_WRITE_NODE: { yp_local_variable_operator_write_node_t *cast = (yp_local_variable_operator_write_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->value); break; } -#line 81 "node.c.erb" - case YP_NODE_LOCAL_VARIABLE_OR_WRITE_NODE: { +#line 57 "node.c.erb" + case YP_LOCAL_VARIABLE_OR_WRITE_NODE: { yp_local_variable_or_write_node_t *cast = (yp_local_variable_or_write_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->value); break; } -#line 81 "node.c.erb" - case YP_NODE_LOCAL_VARIABLE_READ_NODE: { +#line 57 "node.c.erb" + case YP_LOCAL_VARIABLE_READ_NODE: { break; } -#line 81 "node.c.erb" - case YP_NODE_LOCAL_VARIABLE_TARGET_NODE: { +#line 57 "node.c.erb" + case YP_LOCAL_VARIABLE_TARGET_NODE: { break; } -#line 81 "node.c.erb" - case YP_NODE_LOCAL_VARIABLE_WRITE_NODE: { +#line 57 "node.c.erb" + case YP_LOCAL_VARIABLE_WRITE_NODE: { yp_local_variable_write_node_t *cast = (yp_local_variable_write_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->value); break; } -#line 81 "node.c.erb" - case YP_NODE_MATCH_PREDICATE_NODE: { +#line 57 "node.c.erb" + case YP_MATCH_LAST_LINE_NODE: { + yp_match_last_line_node_t *cast = (yp_match_last_line_node_t *) node; + yp_string_free(&cast->unescaped); + break; + } +#line 57 "node.c.erb" + case YP_MATCH_PREDICATE_NODE: { yp_match_predicate_node_t *cast = (yp_match_predicate_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->value); yp_node_destroy(parser, (yp_node_t *)cast->pattern); break; } -#line 81 "node.c.erb" - case YP_NODE_MATCH_REQUIRED_NODE: { +#line 57 "node.c.erb" + case YP_MATCH_REQUIRED_NODE: { yp_match_required_node_t *cast = (yp_match_required_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->value); yp_node_destroy(parser, (yp_node_t *)cast->pattern); break; } -#line 81 "node.c.erb" - case YP_NODE_MISSING_NODE: { +#line 57 "node.c.erb" + case YP_MATCH_WRITE_NODE: { + yp_match_write_node_t *cast = (yp_match_write_node_t *) node; + yp_node_destroy(parser, (yp_node_t *)cast->call); + yp_constant_id_list_free(&cast->locals); break; } -#line 81 "node.c.erb" - case YP_NODE_MODULE_NODE: { +#line 57 "node.c.erb" + case YP_MISSING_NODE: { + break; + } +#line 57 "node.c.erb" + case YP_MODULE_NODE: { yp_module_node_t *cast = (yp_module_node_t *) node; yp_constant_id_list_free(&cast->locals); yp_node_destroy(parser, (yp_node_t *)cast->constant_path); if (cast->body != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->body); } - yp_string_free(&cast->name); break; } -#line 81 "node.c.erb" - case YP_NODE_MULTI_WRITE_NODE: { +#line 57 "node.c.erb" + case YP_MULTI_TARGET_NODE: { + yp_multi_target_node_t *cast = (yp_multi_target_node_t *) node; + yp_node_list_free(parser, &cast->targets); + break; + } +#line 57 "node.c.erb" + case YP_MULTI_WRITE_NODE: { yp_multi_write_node_t *cast = (yp_multi_write_node_t *) node; yp_node_list_free(parser, &cast->targets); - if (cast->value != NULL) { - yp_node_destroy(parser, (yp_node_t *)cast->value); - } + yp_node_destroy(parser, (yp_node_t *)cast->value); break; } -#line 81 "node.c.erb" - case YP_NODE_NEXT_NODE: { +#line 57 "node.c.erb" + case YP_NEXT_NODE: { yp_next_node_t *cast = (yp_next_node_t *) node; if (cast->arguments != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->arguments); } break; } -#line 81 "node.c.erb" - case YP_NODE_NIL_NODE: { +#line 57 "node.c.erb" + case YP_NIL_NODE: { break; } -#line 81 "node.c.erb" - case YP_NODE_NO_KEYWORDS_PARAMETER_NODE: { +#line 57 "node.c.erb" + case YP_NO_KEYWORDS_PARAMETER_NODE: { break; } -#line 81 "node.c.erb" - case YP_NODE_NUMBERED_REFERENCE_READ_NODE: { +#line 57 "node.c.erb" + case YP_NUMBERED_REFERENCE_READ_NODE: { break; } -#line 81 "node.c.erb" - case YP_NODE_OPTIONAL_PARAMETER_NODE: { +#line 57 "node.c.erb" + case YP_OPTIONAL_PARAMETER_NODE: { yp_optional_parameter_node_t *cast = (yp_optional_parameter_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->value); break; } -#line 81 "node.c.erb" - case YP_NODE_OR_NODE: { +#line 57 "node.c.erb" + case YP_OR_NODE: { yp_or_node_t *cast = (yp_or_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->left); yp_node_destroy(parser, (yp_node_t *)cast->right); break; } -#line 81 "node.c.erb" - case YP_NODE_PARAMETERS_NODE: { +#line 57 "node.c.erb" + case YP_PARAMETERS_NODE: { yp_parameters_node_t *cast = (yp_parameters_node_t *) node; yp_node_list_free(parser, &cast->requireds); yp_node_list_free(parser, &cast->optionals); - yp_node_list_free(parser, &cast->posts); if (cast->rest != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->rest); } + yp_node_list_free(parser, &cast->posts); yp_node_list_free(parser, &cast->keywords); if (cast->keyword_rest != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->keyword_rest); @@ -784,51 +817,51 @@ yp_node_destroy(yp_parser_t *parser, yp_node_t *node) { } break; } -#line 81 "node.c.erb" - case YP_NODE_PARENTHESES_NODE: { +#line 57 "node.c.erb" + case YP_PARENTHESES_NODE: { yp_parentheses_node_t *cast = (yp_parentheses_node_t *) node; if (cast->body != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->body); } break; } -#line 81 "node.c.erb" - case YP_NODE_PINNED_EXPRESSION_NODE: { +#line 57 "node.c.erb" + case YP_PINNED_EXPRESSION_NODE: { yp_pinned_expression_node_t *cast = (yp_pinned_expression_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->expression); break; } -#line 81 "node.c.erb" - case YP_NODE_PINNED_VARIABLE_NODE: { +#line 57 "node.c.erb" + case YP_PINNED_VARIABLE_NODE: { yp_pinned_variable_node_t *cast = (yp_pinned_variable_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->variable); break; } -#line 81 "node.c.erb" - case YP_NODE_POST_EXECUTION_NODE: { +#line 57 "node.c.erb" + case YP_POST_EXECUTION_NODE: { yp_post_execution_node_t *cast = (yp_post_execution_node_t *) node; if (cast->statements != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->statements); } break; } -#line 81 "node.c.erb" - case YP_NODE_PRE_EXECUTION_NODE: { +#line 57 "node.c.erb" + case YP_PRE_EXECUTION_NODE: { yp_pre_execution_node_t *cast = (yp_pre_execution_node_t *) node; if (cast->statements != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->statements); } break; } -#line 81 "node.c.erb" - case YP_NODE_PROGRAM_NODE: { +#line 57 "node.c.erb" + case YP_PROGRAM_NODE: { yp_program_node_t *cast = (yp_program_node_t *) node; yp_constant_id_list_free(&cast->locals); yp_node_destroy(parser, (yp_node_t *)cast->statements); break; } -#line 81 "node.c.erb" - case YP_NODE_RANGE_NODE: { +#line 57 "node.c.erb" + case YP_RANGE_NODE: { yp_range_node_t *cast = (yp_range_node_t *) node; if (cast->left != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->left); @@ -838,41 +871,41 @@ yp_node_destroy(yp_parser_t *parser, yp_node_t *node) { } break; } -#line 81 "node.c.erb" - case YP_NODE_RATIONAL_NODE: { +#line 57 "node.c.erb" + case YP_RATIONAL_NODE: { yp_rational_node_t *cast = (yp_rational_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->numeric); break; } -#line 81 "node.c.erb" - case YP_NODE_REDO_NODE: { +#line 57 "node.c.erb" + case YP_REDO_NODE: { break; } -#line 81 "node.c.erb" - case YP_NODE_REGULAR_EXPRESSION_NODE: { +#line 57 "node.c.erb" + case YP_REGULAR_EXPRESSION_NODE: { yp_regular_expression_node_t *cast = (yp_regular_expression_node_t *) node; yp_string_free(&cast->unescaped); break; } -#line 81 "node.c.erb" - case YP_NODE_REQUIRED_DESTRUCTURED_PARAMETER_NODE: { +#line 57 "node.c.erb" + case YP_REQUIRED_DESTRUCTURED_PARAMETER_NODE: { yp_required_destructured_parameter_node_t *cast = (yp_required_destructured_parameter_node_t *) node; yp_node_list_free(parser, &cast->parameters); break; } -#line 81 "node.c.erb" - case YP_NODE_REQUIRED_PARAMETER_NODE: { +#line 57 "node.c.erb" + case YP_REQUIRED_PARAMETER_NODE: { break; } -#line 81 "node.c.erb" - case YP_NODE_RESCUE_MODIFIER_NODE: { +#line 57 "node.c.erb" + case YP_RESCUE_MODIFIER_NODE: { yp_rescue_modifier_node_t *cast = (yp_rescue_modifier_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->expression); yp_node_destroy(parser, (yp_node_t *)cast->rescue_expression); break; } -#line 81 "node.c.erb" - case YP_NODE_RESCUE_NODE: { +#line 57 "node.c.erb" + case YP_RESCUE_NODE: { yp_rescue_node_t *cast = (yp_rescue_node_t *) node; yp_node_list_free(parser, &cast->exceptions); if (cast->reference != NULL) { @@ -886,28 +919,28 @@ yp_node_destroy(yp_parser_t *parser, yp_node_t *node) { } break; } -#line 81 "node.c.erb" - case YP_NODE_REST_PARAMETER_NODE: { +#line 57 "node.c.erb" + case YP_REST_PARAMETER_NODE: { break; } -#line 81 "node.c.erb" - case YP_NODE_RETRY_NODE: { +#line 57 "node.c.erb" + case YP_RETRY_NODE: { break; } -#line 81 "node.c.erb" - case YP_NODE_RETURN_NODE: { +#line 57 "node.c.erb" + case YP_RETURN_NODE: { yp_return_node_t *cast = (yp_return_node_t *) node; if (cast->arguments != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->arguments); } break; } -#line 81 "node.c.erb" - case YP_NODE_SELF_NODE: { +#line 57 "node.c.erb" + case YP_SELF_NODE: { break; } -#line 81 "node.c.erb" - case YP_NODE_SINGLETON_CLASS_NODE: { +#line 57 "node.c.erb" + case YP_SINGLETON_CLASS_NODE: { yp_singleton_class_node_t *cast = (yp_singleton_class_node_t *) node; yp_constant_id_list_free(&cast->locals); yp_node_destroy(parser, (yp_node_t *)cast->expression); @@ -916,49 +949,49 @@ yp_node_destroy(yp_parser_t *parser, yp_node_t *node) { } break; } -#line 81 "node.c.erb" - case YP_NODE_SOURCE_ENCODING_NODE: { +#line 57 "node.c.erb" + case YP_SOURCE_ENCODING_NODE: { break; } -#line 81 "node.c.erb" - case YP_NODE_SOURCE_FILE_NODE: { +#line 57 "node.c.erb" + case YP_SOURCE_FILE_NODE: { yp_source_file_node_t *cast = (yp_source_file_node_t *) node; yp_string_free(&cast->filepath); break; } -#line 81 "node.c.erb" - case YP_NODE_SOURCE_LINE_NODE: { +#line 57 "node.c.erb" + case YP_SOURCE_LINE_NODE: { break; } -#line 81 "node.c.erb" - case YP_NODE_SPLAT_NODE: { +#line 57 "node.c.erb" + case YP_SPLAT_NODE: { yp_splat_node_t *cast = (yp_splat_node_t *) node; if (cast->expression != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->expression); } break; } -#line 81 "node.c.erb" - case YP_NODE_STATEMENTS_NODE: { +#line 57 "node.c.erb" + case YP_STATEMENTS_NODE: { yp_statements_node_t *cast = (yp_statements_node_t *) node; yp_node_list_free(parser, &cast->body); break; } -#line 81 "node.c.erb" - case YP_NODE_STRING_CONCAT_NODE: { +#line 57 "node.c.erb" + case YP_STRING_CONCAT_NODE: { yp_string_concat_node_t *cast = (yp_string_concat_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->left); yp_node_destroy(parser, (yp_node_t *)cast->right); break; } -#line 81 "node.c.erb" - case YP_NODE_STRING_NODE: { +#line 57 "node.c.erb" + case YP_STRING_NODE: { yp_string_node_t *cast = (yp_string_node_t *) node; yp_string_free(&cast->unescaped); break; } -#line 81 "node.c.erb" - case YP_NODE_SUPER_NODE: { +#line 57 "node.c.erb" + case YP_SUPER_NODE: { yp_super_node_t *cast = (yp_super_node_t *) node; if (cast->arguments != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->arguments); @@ -968,24 +1001,24 @@ yp_node_destroy(yp_parser_t *parser, yp_node_t *node) { } break; } -#line 81 "node.c.erb" - case YP_NODE_SYMBOL_NODE: { +#line 57 "node.c.erb" + case YP_SYMBOL_NODE: { yp_symbol_node_t *cast = (yp_symbol_node_t *) node; yp_string_free(&cast->unescaped); break; } -#line 81 "node.c.erb" - case YP_NODE_TRUE_NODE: { +#line 57 "node.c.erb" + case YP_TRUE_NODE: { break; } -#line 81 "node.c.erb" - case YP_NODE_UNDEF_NODE: { +#line 57 "node.c.erb" + case YP_UNDEF_NODE: { yp_undef_node_t *cast = (yp_undef_node_t *) node; yp_node_list_free(parser, &cast->names); break; } -#line 81 "node.c.erb" - case YP_NODE_UNLESS_NODE: { +#line 57 "node.c.erb" + case YP_UNLESS_NODE: { yp_unless_node_t *cast = (yp_unless_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->predicate); if (cast->statements != NULL) { @@ -996,8 +1029,8 @@ yp_node_destroy(yp_parser_t *parser, yp_node_t *node) { } break; } -#line 81 "node.c.erb" - case YP_NODE_UNTIL_NODE: { +#line 57 "node.c.erb" + case YP_UNTIL_NODE: { yp_until_node_t *cast = (yp_until_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->predicate); if (cast->statements != NULL) { @@ -1005,8 +1038,8 @@ yp_node_destroy(yp_parser_t *parser, yp_node_t *node) { } break; } -#line 81 "node.c.erb" - case YP_NODE_WHEN_NODE: { +#line 57 "node.c.erb" + case YP_WHEN_NODE: { yp_when_node_t *cast = (yp_when_node_t *) node; yp_node_list_free(parser, &cast->conditions); if (cast->statements != NULL) { @@ -1014,8 +1047,8 @@ yp_node_destroy(yp_parser_t *parser, yp_node_t *node) { } break; } -#line 81 "node.c.erb" - case YP_NODE_WHILE_NODE: { +#line 57 "node.c.erb" + case YP_WHILE_NODE: { yp_while_node_t *cast = (yp_while_node_t *) node; yp_node_destroy(parser, (yp_node_t *)cast->predicate); if (cast->statements != NULL) { @@ -1023,21 +1056,21 @@ yp_node_destroy(yp_parser_t *parser, yp_node_t *node) { } break; } -#line 81 "node.c.erb" - case YP_NODE_X_STRING_NODE: { +#line 57 "node.c.erb" + case YP_X_STRING_NODE: { yp_x_string_node_t *cast = (yp_x_string_node_t *) node; yp_string_free(&cast->unescaped); break; } -#line 81 "node.c.erb" - case YP_NODE_YIELD_NODE: { +#line 57 "node.c.erb" + case YP_YIELD_NODE: { yp_yield_node_t *cast = (yp_yield_node_t *) node; if (cast->arguments != NULL) { yp_node_destroy(parser, (yp_node_t *)cast->arguments); } break; } -#line 110 "node.c.erb" +#line 84 "node.c.erb" default: assert(false && "unreachable"); break; @@ -1052,62 +1085,76 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { switch (YP_NODE_TYPE(node)) { // We do not calculate memsize of a ScopeNode // as it should never be generated - case YP_NODE_SCOPE_NODE: + case YP_SCOPE_NODE: return; -#line 128 "node.c.erb" - case YP_NODE_ALIAS_NODE: { - yp_alias_node_t *cast = (yp_alias_node_t *) node; +#line 102 "node.c.erb" + case YP_ALIAS_GLOBAL_VARIABLE_NODE: { + yp_alias_global_variable_node_t *cast = (yp_alias_global_variable_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->new_name, memsize); yp_node_memsize_node((yp_node_t *)cast->old_name, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_ALTERNATION_PATTERN_NODE: { +#line 102 "node.c.erb" + case YP_ALIAS_METHOD_NODE: { + yp_alias_method_node_t *cast = (yp_alias_method_node_t *) node; + memsize->memsize += sizeof(*cast); + yp_node_memsize_node((yp_node_t *)cast->new_name, memsize); + yp_node_memsize_node((yp_node_t *)cast->old_name, memsize); + break; + } +#line 102 "node.c.erb" + case YP_ALTERNATION_PATTERN_NODE: { yp_alternation_pattern_node_t *cast = (yp_alternation_pattern_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->left, memsize); yp_node_memsize_node((yp_node_t *)cast->right, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_AND_NODE: { +#line 102 "node.c.erb" + case YP_AND_NODE: { yp_and_node_t *cast = (yp_and_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->left, memsize); yp_node_memsize_node((yp_node_t *)cast->right, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_ARGUMENTS_NODE: { +#line 102 "node.c.erb" + case YP_ARGUMENTS_NODE: { yp_arguments_node_t *cast = (yp_arguments_node_t *) node; memsize->memsize += sizeof(*cast); - yp_node_list_memsize(&cast->arguments, memsize); + // Node lists will add in their own sizes below. + memsize->memsize -= sizeof(yp_node_list_t) * 1; + memsize->memsize += yp_node_list_memsize(&cast->arguments, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_ARRAY_NODE: { +#line 102 "node.c.erb" + case YP_ARRAY_NODE: { yp_array_node_t *cast = (yp_array_node_t *) node; memsize->memsize += sizeof(*cast); - yp_node_list_memsize(&cast->elements, memsize); + // Node lists will add in their own sizes below. + memsize->memsize -= sizeof(yp_node_list_t) * 1; + memsize->memsize += yp_node_list_memsize(&cast->elements, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_ARRAY_PATTERN_NODE: { +#line 102 "node.c.erb" + case YP_ARRAY_PATTERN_NODE: { yp_array_pattern_node_t *cast = (yp_array_pattern_node_t *) node; memsize->memsize += sizeof(*cast); + // Node lists will add in their own sizes below. + memsize->memsize -= sizeof(yp_node_list_t) * 2; if (cast->constant != NULL) { yp_node_memsize_node((yp_node_t *)cast->constant, memsize); } - yp_node_list_memsize(&cast->requireds, memsize); + memsize->memsize += yp_node_list_memsize(&cast->requireds, memsize); if (cast->rest != NULL) { yp_node_memsize_node((yp_node_t *)cast->rest, memsize); } - yp_node_list_memsize(&cast->posts, memsize); + memsize->memsize += yp_node_list_memsize(&cast->posts, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_ASSOC_NODE: { +#line 102 "node.c.erb" + case YP_ASSOC_NODE: { yp_assoc_node_t *cast = (yp_assoc_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->key, memsize); @@ -1116,8 +1163,8 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 128 "node.c.erb" - case YP_NODE_ASSOC_SPLAT_NODE: { +#line 102 "node.c.erb" + case YP_ASSOC_SPLAT_NODE: { yp_assoc_splat_node_t *cast = (yp_assoc_splat_node_t *) node; memsize->memsize += sizeof(*cast); if (cast->value != NULL) { @@ -1125,14 +1172,14 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 128 "node.c.erb" - case YP_NODE_BACK_REFERENCE_READ_NODE: { +#line 102 "node.c.erb" + case YP_BACK_REFERENCE_READ_NODE: { yp_back_reference_read_node_t *cast = (yp_back_reference_read_node_t *) node; memsize->memsize += sizeof(*cast); break; } -#line 128 "node.c.erb" - case YP_NODE_BEGIN_NODE: { +#line 102 "node.c.erb" + case YP_BEGIN_NODE: { yp_begin_node_t *cast = (yp_begin_node_t *) node; memsize->memsize += sizeof(*cast); if (cast->statements != NULL) { @@ -1149,8 +1196,8 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 128 "node.c.erb" - case YP_NODE_BLOCK_ARGUMENT_NODE: { +#line 102 "node.c.erb" + case YP_BLOCK_ARGUMENT_NODE: { yp_block_argument_node_t *cast = (yp_block_argument_node_t *) node; memsize->memsize += sizeof(*cast); if (cast->expression != NULL) { @@ -1158,10 +1205,18 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 128 "node.c.erb" - case YP_NODE_BLOCK_NODE: { +#line 102 "node.c.erb" + case YP_BLOCK_LOCAL_VARIABLE_NODE: { + yp_block_local_variable_node_t *cast = (yp_block_local_variable_node_t *) node; + memsize->memsize += sizeof(*cast); + break; + } +#line 102 "node.c.erb" + case YP_BLOCK_NODE: { yp_block_node_t *cast = (yp_block_node_t *) node; memsize->memsize += sizeof(*cast); + // Constant id lists will add in their own sizes below. + memsize->memsize -= sizeof(yp_constant_id_list_t) * 1; memsize->memsize += yp_constant_id_list_memsize(&cast->locals); if (cast->parameters != NULL) { yp_node_memsize_node((yp_node_t *)cast->parameters, memsize); @@ -1171,24 +1226,26 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 128 "node.c.erb" - case YP_NODE_BLOCK_PARAMETER_NODE: { +#line 102 "node.c.erb" + case YP_BLOCK_PARAMETER_NODE: { yp_block_parameter_node_t *cast = (yp_block_parameter_node_t *) node; memsize->memsize += sizeof(*cast); break; } -#line 128 "node.c.erb" - case YP_NODE_BLOCK_PARAMETERS_NODE: { +#line 102 "node.c.erb" + case YP_BLOCK_PARAMETERS_NODE: { yp_block_parameters_node_t *cast = (yp_block_parameters_node_t *) node; memsize->memsize += sizeof(*cast); + // Node lists will add in their own sizes below. + memsize->memsize -= sizeof(yp_node_list_t) * 1; if (cast->parameters != NULL) { yp_node_memsize_node((yp_node_t *)cast->parameters, memsize); } - memsize->memsize += yp_location_list_memsize(&cast->locals); + memsize->memsize += yp_node_list_memsize(&cast->locals, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_BREAK_NODE: { +#line 102 "node.c.erb" + case YP_BREAK_NODE: { yp_break_node_t *cast = (yp_break_node_t *) node; memsize->memsize += sizeof(*cast); if (cast->arguments != NULL) { @@ -1196,8 +1253,23 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 128 "node.c.erb" - case YP_NODE_CALL_NODE: { +#line 102 "node.c.erb" + case YP_CALL_AND_WRITE_NODE: { + yp_call_and_write_node_t *cast = (yp_call_and_write_node_t *) node; + memsize->memsize += sizeof(*cast); + if (cast->receiver != NULL) { + yp_node_memsize_node((yp_node_t *)cast->receiver, memsize); + } + if (cast->arguments != NULL) { + yp_node_memsize_node((yp_node_t *)cast->arguments, memsize); + } + memsize->memsize += yp_string_memsize(&cast->read_name); + memsize->memsize += yp_string_memsize(&cast->write_name); + yp_node_memsize_node((yp_node_t *)cast->value, memsize); + break; + } +#line 102 "node.c.erb" + case YP_CALL_NODE: { yp_call_node_t *cast = (yp_call_node_t *) node; memsize->memsize += sizeof(*cast); if (cast->receiver != NULL) { @@ -1212,55 +1284,65 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { memsize->memsize += yp_string_memsize(&cast->name); break; } -#line 128 "node.c.erb" - case YP_NODE_CALL_OPERATOR_AND_WRITE_NODE: { - yp_call_operator_and_write_node_t *cast = (yp_call_operator_and_write_node_t *) node; - memsize->memsize += sizeof(*cast); - yp_node_memsize_node((yp_node_t *)cast->target, memsize); - yp_node_memsize_node((yp_node_t *)cast->value, memsize); - break; - } -#line 128 "node.c.erb" - case YP_NODE_CALL_OPERATOR_OR_WRITE_NODE: { - yp_call_operator_or_write_node_t *cast = (yp_call_operator_or_write_node_t *) node; +#line 102 "node.c.erb" + case YP_CALL_OPERATOR_WRITE_NODE: { + yp_call_operator_write_node_t *cast = (yp_call_operator_write_node_t *) node; memsize->memsize += sizeof(*cast); - yp_node_memsize_node((yp_node_t *)cast->target, memsize); + if (cast->receiver != NULL) { + yp_node_memsize_node((yp_node_t *)cast->receiver, memsize); + } + if (cast->arguments != NULL) { + yp_node_memsize_node((yp_node_t *)cast->arguments, memsize); + } + memsize->memsize += yp_string_memsize(&cast->read_name); + memsize->memsize += yp_string_memsize(&cast->write_name); yp_node_memsize_node((yp_node_t *)cast->value, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_CALL_OPERATOR_WRITE_NODE: { - yp_call_operator_write_node_t *cast = (yp_call_operator_write_node_t *) node; +#line 102 "node.c.erb" + case YP_CALL_OR_WRITE_NODE: { + yp_call_or_write_node_t *cast = (yp_call_or_write_node_t *) node; memsize->memsize += sizeof(*cast); - yp_node_memsize_node((yp_node_t *)cast->target, memsize); + if (cast->receiver != NULL) { + yp_node_memsize_node((yp_node_t *)cast->receiver, memsize); + } + if (cast->arguments != NULL) { + yp_node_memsize_node((yp_node_t *)cast->arguments, memsize); + } + memsize->memsize += yp_string_memsize(&cast->read_name); + memsize->memsize += yp_string_memsize(&cast->write_name); yp_node_memsize_node((yp_node_t *)cast->value, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_CAPTURE_PATTERN_NODE: { +#line 102 "node.c.erb" + case YP_CAPTURE_PATTERN_NODE: { yp_capture_pattern_node_t *cast = (yp_capture_pattern_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->value, memsize); yp_node_memsize_node((yp_node_t *)cast->target, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_CASE_NODE: { +#line 102 "node.c.erb" + case YP_CASE_NODE: { yp_case_node_t *cast = (yp_case_node_t *) node; memsize->memsize += sizeof(*cast); + // Node lists will add in their own sizes below. + memsize->memsize -= sizeof(yp_node_list_t) * 1; if (cast->predicate != NULL) { yp_node_memsize_node((yp_node_t *)cast->predicate, memsize); } - yp_node_list_memsize(&cast->conditions, memsize); + memsize->memsize += yp_node_list_memsize(&cast->conditions, memsize); if (cast->consequent != NULL) { yp_node_memsize_node((yp_node_t *)cast->consequent, memsize); } break; } -#line 128 "node.c.erb" - case YP_NODE_CLASS_NODE: { +#line 102 "node.c.erb" + case YP_CLASS_NODE: { yp_class_node_t *cast = (yp_class_node_t *) node; memsize->memsize += sizeof(*cast); + // Constant id lists will add in their own sizes below. + memsize->memsize -= sizeof(yp_constant_id_list_t) * 1; memsize->memsize += yp_constant_id_list_memsize(&cast->locals); yp_node_memsize_node((yp_node_t *)cast->constant_path, memsize); if (cast->superclass != NULL) { @@ -1269,82 +1351,79 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { if (cast->body != NULL) { yp_node_memsize_node((yp_node_t *)cast->body, memsize); } - memsize->memsize += yp_string_memsize(&cast->name); break; } -#line 128 "node.c.erb" - case YP_NODE_CLASS_VARIABLE_AND_WRITE_NODE: { +#line 102 "node.c.erb" + case YP_CLASS_VARIABLE_AND_WRITE_NODE: { yp_class_variable_and_write_node_t *cast = (yp_class_variable_and_write_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->value, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_CLASS_VARIABLE_OPERATOR_WRITE_NODE: { +#line 102 "node.c.erb" + case YP_CLASS_VARIABLE_OPERATOR_WRITE_NODE: { yp_class_variable_operator_write_node_t *cast = (yp_class_variable_operator_write_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->value, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_CLASS_VARIABLE_OR_WRITE_NODE: { +#line 102 "node.c.erb" + case YP_CLASS_VARIABLE_OR_WRITE_NODE: { yp_class_variable_or_write_node_t *cast = (yp_class_variable_or_write_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->value, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_CLASS_VARIABLE_READ_NODE: { +#line 102 "node.c.erb" + case YP_CLASS_VARIABLE_READ_NODE: { yp_class_variable_read_node_t *cast = (yp_class_variable_read_node_t *) node; memsize->memsize += sizeof(*cast); break; } -#line 128 "node.c.erb" - case YP_NODE_CLASS_VARIABLE_TARGET_NODE: { +#line 102 "node.c.erb" + case YP_CLASS_VARIABLE_TARGET_NODE: { yp_class_variable_target_node_t *cast = (yp_class_variable_target_node_t *) node; memsize->memsize += sizeof(*cast); break; } -#line 128 "node.c.erb" - case YP_NODE_CLASS_VARIABLE_WRITE_NODE: { +#line 102 "node.c.erb" + case YP_CLASS_VARIABLE_WRITE_NODE: { yp_class_variable_write_node_t *cast = (yp_class_variable_write_node_t *) node; memsize->memsize += sizeof(*cast); - if (cast->value != NULL) { - yp_node_memsize_node((yp_node_t *)cast->value, memsize); - } + yp_node_memsize_node((yp_node_t *)cast->value, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_CONSTANT_AND_WRITE_NODE: { +#line 102 "node.c.erb" + case YP_CONSTANT_AND_WRITE_NODE: { yp_constant_and_write_node_t *cast = (yp_constant_and_write_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->value, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_CONSTANT_OPERATOR_WRITE_NODE: { +#line 102 "node.c.erb" + case YP_CONSTANT_OPERATOR_WRITE_NODE: { yp_constant_operator_write_node_t *cast = (yp_constant_operator_write_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->value, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_CONSTANT_OR_WRITE_NODE: { +#line 102 "node.c.erb" + case YP_CONSTANT_OR_WRITE_NODE: { yp_constant_or_write_node_t *cast = (yp_constant_or_write_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->value, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_CONSTANT_PATH_AND_WRITE_NODE: { +#line 102 "node.c.erb" + case YP_CONSTANT_PATH_AND_WRITE_NODE: { yp_constant_path_and_write_node_t *cast = (yp_constant_path_and_write_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->target, memsize); yp_node_memsize_node((yp_node_t *)cast->value, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_CONSTANT_PATH_NODE: { +#line 102 "node.c.erb" + case YP_CONSTANT_PATH_NODE: { yp_constant_path_node_t *cast = (yp_constant_path_node_t *) node; memsize->memsize += sizeof(*cast); if (cast->parent != NULL) { @@ -1353,24 +1432,24 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { yp_node_memsize_node((yp_node_t *)cast->child, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_CONSTANT_PATH_OPERATOR_WRITE_NODE: { +#line 102 "node.c.erb" + case YP_CONSTANT_PATH_OPERATOR_WRITE_NODE: { yp_constant_path_operator_write_node_t *cast = (yp_constant_path_operator_write_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->target, memsize); yp_node_memsize_node((yp_node_t *)cast->value, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_CONSTANT_PATH_OR_WRITE_NODE: { +#line 102 "node.c.erb" + case YP_CONSTANT_PATH_OR_WRITE_NODE: { yp_constant_path_or_write_node_t *cast = (yp_constant_path_or_write_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->target, memsize); yp_node_memsize_node((yp_node_t *)cast->value, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_CONSTANT_PATH_TARGET_NODE: { +#line 102 "node.c.erb" + case YP_CONSTANT_PATH_TARGET_NODE: { yp_constant_path_target_node_t *cast = (yp_constant_path_target_node_t *) node; memsize->memsize += sizeof(*cast); if (cast->parent != NULL) { @@ -1379,37 +1458,39 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { yp_node_memsize_node((yp_node_t *)cast->child, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_CONSTANT_PATH_WRITE_NODE: { +#line 102 "node.c.erb" + case YP_CONSTANT_PATH_WRITE_NODE: { yp_constant_path_write_node_t *cast = (yp_constant_path_write_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->target, memsize); yp_node_memsize_node((yp_node_t *)cast->value, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_CONSTANT_READ_NODE: { +#line 102 "node.c.erb" + case YP_CONSTANT_READ_NODE: { yp_constant_read_node_t *cast = (yp_constant_read_node_t *) node; memsize->memsize += sizeof(*cast); break; } -#line 128 "node.c.erb" - case YP_NODE_CONSTANT_TARGET_NODE: { +#line 102 "node.c.erb" + case YP_CONSTANT_TARGET_NODE: { yp_constant_target_node_t *cast = (yp_constant_target_node_t *) node; memsize->memsize += sizeof(*cast); break; } -#line 128 "node.c.erb" - case YP_NODE_CONSTANT_WRITE_NODE: { +#line 102 "node.c.erb" + case YP_CONSTANT_WRITE_NODE: { yp_constant_write_node_t *cast = (yp_constant_write_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->value, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_DEF_NODE: { +#line 102 "node.c.erb" + case YP_DEF_NODE: { yp_def_node_t *cast = (yp_def_node_t *) node; memsize->memsize += sizeof(*cast); + // Constant id lists will add in their own sizes below. + memsize->memsize -= sizeof(yp_constant_id_list_t) * 1; if (cast->receiver != NULL) { yp_node_memsize_node((yp_node_t *)cast->receiver, memsize); } @@ -1422,15 +1503,15 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { memsize->memsize += yp_constant_id_list_memsize(&cast->locals); break; } -#line 128 "node.c.erb" - case YP_NODE_DEFINED_NODE: { +#line 102 "node.c.erb" + case YP_DEFINED_NODE: { yp_defined_node_t *cast = (yp_defined_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->value, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_ELSE_NODE: { +#line 102 "node.c.erb" + case YP_ELSE_NODE: { yp_else_node_t *cast = (yp_else_node_t *) node; memsize->memsize += sizeof(*cast); if (cast->statements != NULL) { @@ -1438,8 +1519,8 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 128 "node.c.erb" - case YP_NODE_EMBEDDED_STATEMENTS_NODE: { +#line 102 "node.c.erb" + case YP_EMBEDDED_STATEMENTS_NODE: { yp_embedded_statements_node_t *cast = (yp_embedded_statements_node_t *) node; memsize->memsize += sizeof(*cast); if (cast->statements != NULL) { @@ -1447,15 +1528,15 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 128 "node.c.erb" - case YP_NODE_EMBEDDED_VARIABLE_NODE: { +#line 102 "node.c.erb" + case YP_EMBEDDED_VARIABLE_NODE: { yp_embedded_variable_node_t *cast = (yp_embedded_variable_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->variable, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_ENSURE_NODE: { +#line 102 "node.c.erb" + case YP_ENSURE_NODE: { yp_ensure_node_t *cast = (yp_ensure_node_t *) node; memsize->memsize += sizeof(*cast); if (cast->statements != NULL) { @@ -1463,26 +1544,28 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 128 "node.c.erb" - case YP_NODE_FALSE_NODE: { +#line 102 "node.c.erb" + case YP_FALSE_NODE: { yp_false_node_t *cast = (yp_false_node_t *) node; memsize->memsize += sizeof(*cast); break; } -#line 128 "node.c.erb" - case YP_NODE_FIND_PATTERN_NODE: { +#line 102 "node.c.erb" + case YP_FIND_PATTERN_NODE: { yp_find_pattern_node_t *cast = (yp_find_pattern_node_t *) node; memsize->memsize += sizeof(*cast); + // Node lists will add in their own sizes below. + memsize->memsize -= sizeof(yp_node_list_t) * 1; if (cast->constant != NULL) { yp_node_memsize_node((yp_node_t *)cast->constant, memsize); } yp_node_memsize_node((yp_node_t *)cast->left, memsize); - yp_node_list_memsize(&cast->requireds, memsize); + memsize->memsize += yp_node_list_memsize(&cast->requireds, memsize); yp_node_memsize_node((yp_node_t *)cast->right, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_FLIP_FLOP_NODE: { +#line 102 "node.c.erb" + case YP_FLIP_FLOP_NODE: { yp_flip_flop_node_t *cast = (yp_flip_flop_node_t *) node; memsize->memsize += sizeof(*cast); if (cast->left != NULL) { @@ -1493,14 +1576,14 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 128 "node.c.erb" - case YP_NODE_FLOAT_NODE: { +#line 102 "node.c.erb" + case YP_FLOAT_NODE: { yp_float_node_t *cast = (yp_float_node_t *) node; memsize->memsize += sizeof(*cast); break; } -#line 128 "node.c.erb" - case YP_NODE_FOR_NODE: { +#line 102 "node.c.erb" + case YP_FOR_NODE: { yp_for_node_t *cast = (yp_for_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->index, memsize); @@ -1510,20 +1593,20 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 128 "node.c.erb" - case YP_NODE_FORWARDING_ARGUMENTS_NODE: { +#line 102 "node.c.erb" + case YP_FORWARDING_ARGUMENTS_NODE: { yp_forwarding_arguments_node_t *cast = (yp_forwarding_arguments_node_t *) node; memsize->memsize += sizeof(*cast); break; } -#line 128 "node.c.erb" - case YP_NODE_FORWARDING_PARAMETER_NODE: { +#line 102 "node.c.erb" + case YP_FORWARDING_PARAMETER_NODE: { yp_forwarding_parameter_node_t *cast = (yp_forwarding_parameter_node_t *) node; memsize->memsize += sizeof(*cast); break; } -#line 128 "node.c.erb" - case YP_NODE_FORWARDING_SUPER_NODE: { +#line 102 "node.c.erb" + case YP_FORWARDING_SUPER_NODE: { yp_forwarding_super_node_t *cast = (yp_forwarding_super_node_t *) node; memsize->memsize += sizeof(*cast); if (cast->block != NULL) { @@ -1531,68 +1614,72 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 128 "node.c.erb" - case YP_NODE_GLOBAL_VARIABLE_AND_WRITE_NODE: { +#line 102 "node.c.erb" + case YP_GLOBAL_VARIABLE_AND_WRITE_NODE: { yp_global_variable_and_write_node_t *cast = (yp_global_variable_and_write_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->value, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE: { +#line 102 "node.c.erb" + case YP_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE: { yp_global_variable_operator_write_node_t *cast = (yp_global_variable_operator_write_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->value, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_GLOBAL_VARIABLE_OR_WRITE_NODE: { +#line 102 "node.c.erb" + case YP_GLOBAL_VARIABLE_OR_WRITE_NODE: { yp_global_variable_or_write_node_t *cast = (yp_global_variable_or_write_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->value, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_GLOBAL_VARIABLE_READ_NODE: { +#line 102 "node.c.erb" + case YP_GLOBAL_VARIABLE_READ_NODE: { yp_global_variable_read_node_t *cast = (yp_global_variable_read_node_t *) node; memsize->memsize += sizeof(*cast); break; } -#line 128 "node.c.erb" - case YP_NODE_GLOBAL_VARIABLE_TARGET_NODE: { +#line 102 "node.c.erb" + case YP_GLOBAL_VARIABLE_TARGET_NODE: { yp_global_variable_target_node_t *cast = (yp_global_variable_target_node_t *) node; memsize->memsize += sizeof(*cast); break; } -#line 128 "node.c.erb" - case YP_NODE_GLOBAL_VARIABLE_WRITE_NODE: { +#line 102 "node.c.erb" + case YP_GLOBAL_VARIABLE_WRITE_NODE: { yp_global_variable_write_node_t *cast = (yp_global_variable_write_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->value, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_HASH_NODE: { +#line 102 "node.c.erb" + case YP_HASH_NODE: { yp_hash_node_t *cast = (yp_hash_node_t *) node; memsize->memsize += sizeof(*cast); - yp_node_list_memsize(&cast->elements, memsize); + // Node lists will add in their own sizes below. + memsize->memsize -= sizeof(yp_node_list_t) * 1; + memsize->memsize += yp_node_list_memsize(&cast->elements, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_HASH_PATTERN_NODE: { +#line 102 "node.c.erb" + case YP_HASH_PATTERN_NODE: { yp_hash_pattern_node_t *cast = (yp_hash_pattern_node_t *) node; memsize->memsize += sizeof(*cast); + // Node lists will add in their own sizes below. + memsize->memsize -= sizeof(yp_node_list_t) * 1; if (cast->constant != NULL) { yp_node_memsize_node((yp_node_t *)cast->constant, memsize); } - yp_node_list_memsize(&cast->assocs, memsize); + memsize->memsize += yp_node_list_memsize(&cast->assocs, memsize); if (cast->kwrest != NULL) { yp_node_memsize_node((yp_node_t *)cast->kwrest, memsize); } break; } -#line 128 "node.c.erb" - case YP_NODE_IF_NODE: { +#line 102 "node.c.erb" + case YP_IF_NODE: { yp_if_node_t *cast = (yp_if_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->predicate, memsize); @@ -1604,15 +1691,22 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 128 "node.c.erb" - case YP_NODE_IMAGINARY_NODE: { +#line 102 "node.c.erb" + case YP_IMAGINARY_NODE: { yp_imaginary_node_t *cast = (yp_imaginary_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->numeric, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_IN_NODE: { +#line 102 "node.c.erb" + case YP_IMPLICIT_NODE: { + yp_implicit_node_t *cast = (yp_implicit_node_t *) node; + memsize->memsize += sizeof(*cast); + yp_node_memsize_node((yp_node_t *)cast->value, memsize); + break; + } +#line 102 "node.c.erb" + case YP_IN_NODE: { yp_in_node_t *cast = (yp_in_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->pattern, memsize); @@ -1621,89 +1715,108 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 128 "node.c.erb" - case YP_NODE_INSTANCE_VARIABLE_AND_WRITE_NODE: { +#line 102 "node.c.erb" + case YP_INSTANCE_VARIABLE_AND_WRITE_NODE: { yp_instance_variable_and_write_node_t *cast = (yp_instance_variable_and_write_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->value, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE: { +#line 102 "node.c.erb" + case YP_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE: { yp_instance_variable_operator_write_node_t *cast = (yp_instance_variable_operator_write_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->value, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_INSTANCE_VARIABLE_OR_WRITE_NODE: { +#line 102 "node.c.erb" + case YP_INSTANCE_VARIABLE_OR_WRITE_NODE: { yp_instance_variable_or_write_node_t *cast = (yp_instance_variable_or_write_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->value, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_INSTANCE_VARIABLE_READ_NODE: { +#line 102 "node.c.erb" + case YP_INSTANCE_VARIABLE_READ_NODE: { yp_instance_variable_read_node_t *cast = (yp_instance_variable_read_node_t *) node; memsize->memsize += sizeof(*cast); break; } -#line 128 "node.c.erb" - case YP_NODE_INSTANCE_VARIABLE_TARGET_NODE: { +#line 102 "node.c.erb" + case YP_INSTANCE_VARIABLE_TARGET_NODE: { yp_instance_variable_target_node_t *cast = (yp_instance_variable_target_node_t *) node; memsize->memsize += sizeof(*cast); break; } -#line 128 "node.c.erb" - case YP_NODE_INSTANCE_VARIABLE_WRITE_NODE: { +#line 102 "node.c.erb" + case YP_INSTANCE_VARIABLE_WRITE_NODE: { yp_instance_variable_write_node_t *cast = (yp_instance_variable_write_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->value, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_INTEGER_NODE: { +#line 102 "node.c.erb" + case YP_INTEGER_NODE: { yp_integer_node_t *cast = (yp_integer_node_t *) node; memsize->memsize += sizeof(*cast); break; } -#line 128 "node.c.erb" - case YP_NODE_INTERPOLATED_REGULAR_EXPRESSION_NODE: { +#line 102 "node.c.erb" + case YP_INTERPOLATED_MATCH_LAST_LINE_NODE: { + yp_interpolated_match_last_line_node_t *cast = (yp_interpolated_match_last_line_node_t *) node; + memsize->memsize += sizeof(*cast); + // Node lists will add in their own sizes below. + memsize->memsize -= sizeof(yp_node_list_t) * 1; + memsize->memsize += yp_node_list_memsize(&cast->parts, memsize); + break; + } +#line 102 "node.c.erb" + case YP_INTERPOLATED_REGULAR_EXPRESSION_NODE: { yp_interpolated_regular_expression_node_t *cast = (yp_interpolated_regular_expression_node_t *) node; memsize->memsize += sizeof(*cast); - yp_node_list_memsize(&cast->parts, memsize); + // Node lists will add in their own sizes below. + memsize->memsize -= sizeof(yp_node_list_t) * 1; + memsize->memsize += yp_node_list_memsize(&cast->parts, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_INTERPOLATED_STRING_NODE: { +#line 102 "node.c.erb" + case YP_INTERPOLATED_STRING_NODE: { yp_interpolated_string_node_t *cast = (yp_interpolated_string_node_t *) node; memsize->memsize += sizeof(*cast); - yp_node_list_memsize(&cast->parts, memsize); + // Node lists will add in their own sizes below. + memsize->memsize -= sizeof(yp_node_list_t) * 1; + memsize->memsize += yp_node_list_memsize(&cast->parts, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_INTERPOLATED_SYMBOL_NODE: { +#line 102 "node.c.erb" + case YP_INTERPOLATED_SYMBOL_NODE: { yp_interpolated_symbol_node_t *cast = (yp_interpolated_symbol_node_t *) node; memsize->memsize += sizeof(*cast); - yp_node_list_memsize(&cast->parts, memsize); + // Node lists will add in their own sizes below. + memsize->memsize -= sizeof(yp_node_list_t) * 1; + memsize->memsize += yp_node_list_memsize(&cast->parts, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_INTERPOLATED_X_STRING_NODE: { +#line 102 "node.c.erb" + case YP_INTERPOLATED_X_STRING_NODE: { yp_interpolated_x_string_node_t *cast = (yp_interpolated_x_string_node_t *) node; memsize->memsize += sizeof(*cast); - yp_node_list_memsize(&cast->parts, memsize); + // Node lists will add in their own sizes below. + memsize->memsize -= sizeof(yp_node_list_t) * 1; + memsize->memsize += yp_node_list_memsize(&cast->parts, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_KEYWORD_HASH_NODE: { +#line 102 "node.c.erb" + case YP_KEYWORD_HASH_NODE: { yp_keyword_hash_node_t *cast = (yp_keyword_hash_node_t *) node; memsize->memsize += sizeof(*cast); - yp_node_list_memsize(&cast->elements, memsize); + // Node lists will add in their own sizes below. + memsize->memsize -= sizeof(yp_node_list_t) * 1; + memsize->memsize += yp_node_list_memsize(&cast->elements, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_KEYWORD_PARAMETER_NODE: { +#line 102 "node.c.erb" + case YP_KEYWORD_PARAMETER_NODE: { yp_keyword_parameter_node_t *cast = (yp_keyword_parameter_node_t *) node; memsize->memsize += sizeof(*cast); if (cast->value != NULL) { @@ -1711,16 +1824,18 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 128 "node.c.erb" - case YP_NODE_KEYWORD_REST_PARAMETER_NODE: { +#line 102 "node.c.erb" + case YP_KEYWORD_REST_PARAMETER_NODE: { yp_keyword_rest_parameter_node_t *cast = (yp_keyword_rest_parameter_node_t *) node; memsize->memsize += sizeof(*cast); break; } -#line 128 "node.c.erb" - case YP_NODE_LAMBDA_NODE: { +#line 102 "node.c.erb" + case YP_LAMBDA_NODE: { yp_lambda_node_t *cast = (yp_lambda_node_t *) node; memsize->memsize += sizeof(*cast); + // Constant id lists will add in their own sizes below. + memsize->memsize -= sizeof(yp_constant_id_list_t) * 1; memsize->memsize += yp_constant_id_list_memsize(&cast->locals); if (cast->parameters != NULL) { yp_node_memsize_node((yp_node_t *)cast->parameters, memsize); @@ -1730,92 +1845,119 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 128 "node.c.erb" - case YP_NODE_LOCAL_VARIABLE_AND_WRITE_NODE: { +#line 102 "node.c.erb" + case YP_LOCAL_VARIABLE_AND_WRITE_NODE: { yp_local_variable_and_write_node_t *cast = (yp_local_variable_and_write_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->value, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_LOCAL_VARIABLE_OPERATOR_WRITE_NODE: { +#line 102 "node.c.erb" + case YP_LOCAL_VARIABLE_OPERATOR_WRITE_NODE: { yp_local_variable_operator_write_node_t *cast = (yp_local_variable_operator_write_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->value, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_LOCAL_VARIABLE_OR_WRITE_NODE: { +#line 102 "node.c.erb" + case YP_LOCAL_VARIABLE_OR_WRITE_NODE: { yp_local_variable_or_write_node_t *cast = (yp_local_variable_or_write_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->value, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_LOCAL_VARIABLE_READ_NODE: { +#line 102 "node.c.erb" + case YP_LOCAL_VARIABLE_READ_NODE: { yp_local_variable_read_node_t *cast = (yp_local_variable_read_node_t *) node; memsize->memsize += sizeof(*cast); break; } -#line 128 "node.c.erb" - case YP_NODE_LOCAL_VARIABLE_TARGET_NODE: { +#line 102 "node.c.erb" + case YP_LOCAL_VARIABLE_TARGET_NODE: { yp_local_variable_target_node_t *cast = (yp_local_variable_target_node_t *) node; memsize->memsize += sizeof(*cast); break; } -#line 128 "node.c.erb" - case YP_NODE_LOCAL_VARIABLE_WRITE_NODE: { +#line 102 "node.c.erb" + case YP_LOCAL_VARIABLE_WRITE_NODE: { yp_local_variable_write_node_t *cast = (yp_local_variable_write_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->value, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_MATCH_PREDICATE_NODE: { +#line 102 "node.c.erb" + case YP_MATCH_LAST_LINE_NODE: { + yp_match_last_line_node_t *cast = (yp_match_last_line_node_t *) node; + memsize->memsize += sizeof(*cast); + memsize->memsize += yp_string_memsize(&cast->unescaped); + break; + } +#line 102 "node.c.erb" + case YP_MATCH_PREDICATE_NODE: { yp_match_predicate_node_t *cast = (yp_match_predicate_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->value, memsize); yp_node_memsize_node((yp_node_t *)cast->pattern, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_MATCH_REQUIRED_NODE: { +#line 102 "node.c.erb" + case YP_MATCH_REQUIRED_NODE: { yp_match_required_node_t *cast = (yp_match_required_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->value, memsize); yp_node_memsize_node((yp_node_t *)cast->pattern, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_MISSING_NODE: { +#line 102 "node.c.erb" + case YP_MATCH_WRITE_NODE: { + yp_match_write_node_t *cast = (yp_match_write_node_t *) node; + memsize->memsize += sizeof(*cast); + // Constant id lists will add in their own sizes below. + memsize->memsize -= sizeof(yp_constant_id_list_t) * 1; + yp_node_memsize_node((yp_node_t *)cast->call, memsize); + memsize->memsize += yp_constant_id_list_memsize(&cast->locals); + break; + } +#line 102 "node.c.erb" + case YP_MISSING_NODE: { yp_missing_node_t *cast = (yp_missing_node_t *) node; memsize->memsize += sizeof(*cast); break; } -#line 128 "node.c.erb" - case YP_NODE_MODULE_NODE: { +#line 102 "node.c.erb" + case YP_MODULE_NODE: { yp_module_node_t *cast = (yp_module_node_t *) node; memsize->memsize += sizeof(*cast); + // Constant id lists will add in their own sizes below. + memsize->memsize -= sizeof(yp_constant_id_list_t) * 1; memsize->memsize += yp_constant_id_list_memsize(&cast->locals); yp_node_memsize_node((yp_node_t *)cast->constant_path, memsize); if (cast->body != NULL) { yp_node_memsize_node((yp_node_t *)cast->body, memsize); } - memsize->memsize += yp_string_memsize(&cast->name); break; } -#line 128 "node.c.erb" - case YP_NODE_MULTI_WRITE_NODE: { +#line 102 "node.c.erb" + case YP_MULTI_TARGET_NODE: { + yp_multi_target_node_t *cast = (yp_multi_target_node_t *) node; + memsize->memsize += sizeof(*cast); + // Node lists will add in their own sizes below. + memsize->memsize -= sizeof(yp_node_list_t) * 1; + memsize->memsize += yp_node_list_memsize(&cast->targets, memsize); + break; + } +#line 102 "node.c.erb" + case YP_MULTI_WRITE_NODE: { yp_multi_write_node_t *cast = (yp_multi_write_node_t *) node; memsize->memsize += sizeof(*cast); - yp_node_list_memsize(&cast->targets, memsize); - if (cast->value != NULL) { - yp_node_memsize_node((yp_node_t *)cast->value, memsize); - } + // Node lists will add in their own sizes below. + memsize->memsize -= sizeof(yp_node_list_t) * 1; + memsize->memsize += yp_node_list_memsize(&cast->targets, memsize); + yp_node_memsize_node((yp_node_t *)cast->value, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_NEXT_NODE: { +#line 102 "node.c.erb" + case YP_NEXT_NODE: { yp_next_node_t *cast = (yp_next_node_t *) node; memsize->memsize += sizeof(*cast); if (cast->arguments != NULL) { @@ -1823,50 +1965,52 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 128 "node.c.erb" - case YP_NODE_NIL_NODE: { +#line 102 "node.c.erb" + case YP_NIL_NODE: { yp_nil_node_t *cast = (yp_nil_node_t *) node; memsize->memsize += sizeof(*cast); break; } -#line 128 "node.c.erb" - case YP_NODE_NO_KEYWORDS_PARAMETER_NODE: { +#line 102 "node.c.erb" + case YP_NO_KEYWORDS_PARAMETER_NODE: { yp_no_keywords_parameter_node_t *cast = (yp_no_keywords_parameter_node_t *) node; memsize->memsize += sizeof(*cast); break; } -#line 128 "node.c.erb" - case YP_NODE_NUMBERED_REFERENCE_READ_NODE: { +#line 102 "node.c.erb" + case YP_NUMBERED_REFERENCE_READ_NODE: { yp_numbered_reference_read_node_t *cast = (yp_numbered_reference_read_node_t *) node; memsize->memsize += sizeof(*cast); break; } -#line 128 "node.c.erb" - case YP_NODE_OPTIONAL_PARAMETER_NODE: { +#line 102 "node.c.erb" + case YP_OPTIONAL_PARAMETER_NODE: { yp_optional_parameter_node_t *cast = (yp_optional_parameter_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->value, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_OR_NODE: { +#line 102 "node.c.erb" + case YP_OR_NODE: { yp_or_node_t *cast = (yp_or_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->left, memsize); yp_node_memsize_node((yp_node_t *)cast->right, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_PARAMETERS_NODE: { +#line 102 "node.c.erb" + case YP_PARAMETERS_NODE: { yp_parameters_node_t *cast = (yp_parameters_node_t *) node; memsize->memsize += sizeof(*cast); - yp_node_list_memsize(&cast->requireds, memsize); - yp_node_list_memsize(&cast->optionals, memsize); - yp_node_list_memsize(&cast->posts, memsize); + // Node lists will add in their own sizes below. + memsize->memsize -= sizeof(yp_node_list_t) * 4; + memsize->memsize += yp_node_list_memsize(&cast->requireds, memsize); + memsize->memsize += yp_node_list_memsize(&cast->optionals, memsize); if (cast->rest != NULL) { yp_node_memsize_node((yp_node_t *)cast->rest, memsize); } - yp_node_list_memsize(&cast->keywords, memsize); + memsize->memsize += yp_node_list_memsize(&cast->posts, memsize); + memsize->memsize += yp_node_list_memsize(&cast->keywords, memsize); if (cast->keyword_rest != NULL) { yp_node_memsize_node((yp_node_t *)cast->keyword_rest, memsize); } @@ -1875,8 +2019,8 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 128 "node.c.erb" - case YP_NODE_PARENTHESES_NODE: { +#line 102 "node.c.erb" + case YP_PARENTHESES_NODE: { yp_parentheses_node_t *cast = (yp_parentheses_node_t *) node; memsize->memsize += sizeof(*cast); if (cast->body != NULL) { @@ -1884,22 +2028,22 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 128 "node.c.erb" - case YP_NODE_PINNED_EXPRESSION_NODE: { +#line 102 "node.c.erb" + case YP_PINNED_EXPRESSION_NODE: { yp_pinned_expression_node_t *cast = (yp_pinned_expression_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->expression, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_PINNED_VARIABLE_NODE: { +#line 102 "node.c.erb" + case YP_PINNED_VARIABLE_NODE: { yp_pinned_variable_node_t *cast = (yp_pinned_variable_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->variable, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_POST_EXECUTION_NODE: { +#line 102 "node.c.erb" + case YP_POST_EXECUTION_NODE: { yp_post_execution_node_t *cast = (yp_post_execution_node_t *) node; memsize->memsize += sizeof(*cast); if (cast->statements != NULL) { @@ -1907,8 +2051,8 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 128 "node.c.erb" - case YP_NODE_PRE_EXECUTION_NODE: { +#line 102 "node.c.erb" + case YP_PRE_EXECUTION_NODE: { yp_pre_execution_node_t *cast = (yp_pre_execution_node_t *) node; memsize->memsize += sizeof(*cast); if (cast->statements != NULL) { @@ -1916,16 +2060,18 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 128 "node.c.erb" - case YP_NODE_PROGRAM_NODE: { +#line 102 "node.c.erb" + case YP_PROGRAM_NODE: { yp_program_node_t *cast = (yp_program_node_t *) node; memsize->memsize += sizeof(*cast); + // Constant id lists will add in their own sizes below. + memsize->memsize -= sizeof(yp_constant_id_list_t) * 1; memsize->memsize += yp_constant_id_list_memsize(&cast->locals); yp_node_memsize_node((yp_node_t *)cast->statements, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_RANGE_NODE: { +#line 102 "node.c.erb" + case YP_RANGE_NODE: { yp_range_node_t *cast = (yp_range_node_t *) node; memsize->memsize += sizeof(*cast); if (cast->left != NULL) { @@ -1936,52 +2082,56 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 128 "node.c.erb" - case YP_NODE_RATIONAL_NODE: { +#line 102 "node.c.erb" + case YP_RATIONAL_NODE: { yp_rational_node_t *cast = (yp_rational_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->numeric, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_REDO_NODE: { +#line 102 "node.c.erb" + case YP_REDO_NODE: { yp_redo_node_t *cast = (yp_redo_node_t *) node; memsize->memsize += sizeof(*cast); break; } -#line 128 "node.c.erb" - case YP_NODE_REGULAR_EXPRESSION_NODE: { +#line 102 "node.c.erb" + case YP_REGULAR_EXPRESSION_NODE: { yp_regular_expression_node_t *cast = (yp_regular_expression_node_t *) node; memsize->memsize += sizeof(*cast); memsize->memsize += yp_string_memsize(&cast->unescaped); break; } -#line 128 "node.c.erb" - case YP_NODE_REQUIRED_DESTRUCTURED_PARAMETER_NODE: { +#line 102 "node.c.erb" + case YP_REQUIRED_DESTRUCTURED_PARAMETER_NODE: { yp_required_destructured_parameter_node_t *cast = (yp_required_destructured_parameter_node_t *) node; memsize->memsize += sizeof(*cast); - yp_node_list_memsize(&cast->parameters, memsize); + // Node lists will add in their own sizes below. + memsize->memsize -= sizeof(yp_node_list_t) * 1; + memsize->memsize += yp_node_list_memsize(&cast->parameters, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_REQUIRED_PARAMETER_NODE: { +#line 102 "node.c.erb" + case YP_REQUIRED_PARAMETER_NODE: { yp_required_parameter_node_t *cast = (yp_required_parameter_node_t *) node; memsize->memsize += sizeof(*cast); break; } -#line 128 "node.c.erb" - case YP_NODE_RESCUE_MODIFIER_NODE: { +#line 102 "node.c.erb" + case YP_RESCUE_MODIFIER_NODE: { yp_rescue_modifier_node_t *cast = (yp_rescue_modifier_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->expression, memsize); yp_node_memsize_node((yp_node_t *)cast->rescue_expression, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_RESCUE_NODE: { +#line 102 "node.c.erb" + case YP_RESCUE_NODE: { yp_rescue_node_t *cast = (yp_rescue_node_t *) node; memsize->memsize += sizeof(*cast); - yp_node_list_memsize(&cast->exceptions, memsize); + // Node lists will add in their own sizes below. + memsize->memsize -= sizeof(yp_node_list_t) * 1; + memsize->memsize += yp_node_list_memsize(&cast->exceptions, memsize); if (cast->reference != NULL) { yp_node_memsize_node((yp_node_t *)cast->reference, memsize); } @@ -1993,20 +2143,20 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 128 "node.c.erb" - case YP_NODE_REST_PARAMETER_NODE: { +#line 102 "node.c.erb" + case YP_REST_PARAMETER_NODE: { yp_rest_parameter_node_t *cast = (yp_rest_parameter_node_t *) node; memsize->memsize += sizeof(*cast); break; } -#line 128 "node.c.erb" - case YP_NODE_RETRY_NODE: { +#line 102 "node.c.erb" + case YP_RETRY_NODE: { yp_retry_node_t *cast = (yp_retry_node_t *) node; memsize->memsize += sizeof(*cast); break; } -#line 128 "node.c.erb" - case YP_NODE_RETURN_NODE: { +#line 102 "node.c.erb" + case YP_RETURN_NODE: { yp_return_node_t *cast = (yp_return_node_t *) node; memsize->memsize += sizeof(*cast); if (cast->arguments != NULL) { @@ -2014,16 +2164,18 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 128 "node.c.erb" - case YP_NODE_SELF_NODE: { +#line 102 "node.c.erb" + case YP_SELF_NODE: { yp_self_node_t *cast = (yp_self_node_t *) node; memsize->memsize += sizeof(*cast); break; } -#line 128 "node.c.erb" - case YP_NODE_SINGLETON_CLASS_NODE: { +#line 102 "node.c.erb" + case YP_SINGLETON_CLASS_NODE: { yp_singleton_class_node_t *cast = (yp_singleton_class_node_t *) node; memsize->memsize += sizeof(*cast); + // Constant id lists will add in their own sizes below. + memsize->memsize -= sizeof(yp_constant_id_list_t) * 1; memsize->memsize += yp_constant_id_list_memsize(&cast->locals); yp_node_memsize_node((yp_node_t *)cast->expression, memsize); if (cast->body != NULL) { @@ -2031,27 +2183,27 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 128 "node.c.erb" - case YP_NODE_SOURCE_ENCODING_NODE: { +#line 102 "node.c.erb" + case YP_SOURCE_ENCODING_NODE: { yp_source_encoding_node_t *cast = (yp_source_encoding_node_t *) node; memsize->memsize += sizeof(*cast); break; } -#line 128 "node.c.erb" - case YP_NODE_SOURCE_FILE_NODE: { +#line 102 "node.c.erb" + case YP_SOURCE_FILE_NODE: { yp_source_file_node_t *cast = (yp_source_file_node_t *) node; memsize->memsize += sizeof(*cast); memsize->memsize += yp_string_memsize(&cast->filepath); break; } -#line 128 "node.c.erb" - case YP_NODE_SOURCE_LINE_NODE: { +#line 102 "node.c.erb" + case YP_SOURCE_LINE_NODE: { yp_source_line_node_t *cast = (yp_source_line_node_t *) node; memsize->memsize += sizeof(*cast); break; } -#line 128 "node.c.erb" - case YP_NODE_SPLAT_NODE: { +#line 102 "node.c.erb" + case YP_SPLAT_NODE: { yp_splat_node_t *cast = (yp_splat_node_t *) node; memsize->memsize += sizeof(*cast); if (cast->expression != NULL) { @@ -2059,30 +2211,32 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 128 "node.c.erb" - case YP_NODE_STATEMENTS_NODE: { +#line 102 "node.c.erb" + case YP_STATEMENTS_NODE: { yp_statements_node_t *cast = (yp_statements_node_t *) node; memsize->memsize += sizeof(*cast); - yp_node_list_memsize(&cast->body, memsize); + // Node lists will add in their own sizes below. + memsize->memsize -= sizeof(yp_node_list_t) * 1; + memsize->memsize += yp_node_list_memsize(&cast->body, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_STRING_CONCAT_NODE: { +#line 102 "node.c.erb" + case YP_STRING_CONCAT_NODE: { yp_string_concat_node_t *cast = (yp_string_concat_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->left, memsize); yp_node_memsize_node((yp_node_t *)cast->right, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_STRING_NODE: { +#line 102 "node.c.erb" + case YP_STRING_NODE: { yp_string_node_t *cast = (yp_string_node_t *) node; memsize->memsize += sizeof(*cast); memsize->memsize += yp_string_memsize(&cast->unescaped); break; } -#line 128 "node.c.erb" - case YP_NODE_SUPER_NODE: { +#line 102 "node.c.erb" + case YP_SUPER_NODE: { yp_super_node_t *cast = (yp_super_node_t *) node; memsize->memsize += sizeof(*cast); if (cast->arguments != NULL) { @@ -2093,28 +2247,30 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 128 "node.c.erb" - case YP_NODE_SYMBOL_NODE: { +#line 102 "node.c.erb" + case YP_SYMBOL_NODE: { yp_symbol_node_t *cast = (yp_symbol_node_t *) node; memsize->memsize += sizeof(*cast); memsize->memsize += yp_string_memsize(&cast->unescaped); break; } -#line 128 "node.c.erb" - case YP_NODE_TRUE_NODE: { +#line 102 "node.c.erb" + case YP_TRUE_NODE: { yp_true_node_t *cast = (yp_true_node_t *) node; memsize->memsize += sizeof(*cast); break; } -#line 128 "node.c.erb" - case YP_NODE_UNDEF_NODE: { +#line 102 "node.c.erb" + case YP_UNDEF_NODE: { yp_undef_node_t *cast = (yp_undef_node_t *) node; memsize->memsize += sizeof(*cast); - yp_node_list_memsize(&cast->names, memsize); + // Node lists will add in their own sizes below. + memsize->memsize -= sizeof(yp_node_list_t) * 1; + memsize->memsize += yp_node_list_memsize(&cast->names, memsize); break; } -#line 128 "node.c.erb" - case YP_NODE_UNLESS_NODE: { +#line 102 "node.c.erb" + case YP_UNLESS_NODE: { yp_unless_node_t *cast = (yp_unless_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->predicate, memsize); @@ -2126,8 +2282,8 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 128 "node.c.erb" - case YP_NODE_UNTIL_NODE: { +#line 102 "node.c.erb" + case YP_UNTIL_NODE: { yp_until_node_t *cast = (yp_until_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->predicate, memsize); @@ -2136,18 +2292,20 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 128 "node.c.erb" - case YP_NODE_WHEN_NODE: { +#line 102 "node.c.erb" + case YP_WHEN_NODE: { yp_when_node_t *cast = (yp_when_node_t *) node; memsize->memsize += sizeof(*cast); - yp_node_list_memsize(&cast->conditions, memsize); + // Node lists will add in their own sizes below. + memsize->memsize -= sizeof(yp_node_list_t) * 1; + memsize->memsize += yp_node_list_memsize(&cast->conditions, memsize); if (cast->statements != NULL) { yp_node_memsize_node((yp_node_t *)cast->statements, memsize); } break; } -#line 128 "node.c.erb" - case YP_NODE_WHILE_NODE: { +#line 102 "node.c.erb" + case YP_WHILE_NODE: { yp_while_node_t *cast = (yp_while_node_t *) node; memsize->memsize += sizeof(*cast); yp_node_memsize_node((yp_node_t *)cast->predicate, memsize); @@ -2156,15 +2314,15 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 128 "node.c.erb" - case YP_NODE_X_STRING_NODE: { +#line 102 "node.c.erb" + case YP_X_STRING_NODE: { yp_x_string_node_t *cast = (yp_x_string_node_t *) node; memsize->memsize += sizeof(*cast); memsize->memsize += yp_string_memsize(&cast->unescaped); break; } -#line 128 "node.c.erb" - case YP_NODE_YIELD_NODE: { +#line 102 "node.c.erb" + case YP_YIELD_NODE: { yp_yield_node_t *cast = (yp_yield_node_t *) node; memsize->memsize += sizeof(*cast); if (cast->arguments != NULL) { @@ -2172,7 +2330,7 @@ yp_node_memsize_node(yp_node_t *node, yp_memsize_t *memsize) { } break; } -#line 156 "node.c.erb" +#line 136 "node.c.erb" } } @@ -2188,274 +2346,288 @@ YP_EXPORTED_FUNCTION const char * yp_node_type_to_str(yp_node_type_t node_type) { switch (node_type) { - case YP_NODE_ALIAS_NODE: - return "YP_NODE_ALIAS_NODE"; - case YP_NODE_ALTERNATION_PATTERN_NODE: - return "YP_NODE_ALTERNATION_PATTERN_NODE"; - case YP_NODE_AND_NODE: - return "YP_NODE_AND_NODE"; - case YP_NODE_ARGUMENTS_NODE: - return "YP_NODE_ARGUMENTS_NODE"; - case YP_NODE_ARRAY_NODE: - return "YP_NODE_ARRAY_NODE"; - case YP_NODE_ARRAY_PATTERN_NODE: - return "YP_NODE_ARRAY_PATTERN_NODE"; - case YP_NODE_ASSOC_NODE: - return "YP_NODE_ASSOC_NODE"; - case YP_NODE_ASSOC_SPLAT_NODE: - return "YP_NODE_ASSOC_SPLAT_NODE"; - case YP_NODE_BACK_REFERENCE_READ_NODE: - return "YP_NODE_BACK_REFERENCE_READ_NODE"; - case YP_NODE_BEGIN_NODE: - return "YP_NODE_BEGIN_NODE"; - case YP_NODE_BLOCK_ARGUMENT_NODE: - return "YP_NODE_BLOCK_ARGUMENT_NODE"; - case YP_NODE_BLOCK_NODE: - return "YP_NODE_BLOCK_NODE"; - case YP_NODE_BLOCK_PARAMETER_NODE: - return "YP_NODE_BLOCK_PARAMETER_NODE"; - case YP_NODE_BLOCK_PARAMETERS_NODE: - return "YP_NODE_BLOCK_PARAMETERS_NODE"; - case YP_NODE_BREAK_NODE: - return "YP_NODE_BREAK_NODE"; - case YP_NODE_CALL_NODE: - return "YP_NODE_CALL_NODE"; - case YP_NODE_CALL_OPERATOR_AND_WRITE_NODE: - return "YP_NODE_CALL_OPERATOR_AND_WRITE_NODE"; - case YP_NODE_CALL_OPERATOR_OR_WRITE_NODE: - return "YP_NODE_CALL_OPERATOR_OR_WRITE_NODE"; - case YP_NODE_CALL_OPERATOR_WRITE_NODE: - return "YP_NODE_CALL_OPERATOR_WRITE_NODE"; - case YP_NODE_CAPTURE_PATTERN_NODE: - return "YP_NODE_CAPTURE_PATTERN_NODE"; - case YP_NODE_CASE_NODE: - return "YP_NODE_CASE_NODE"; - case YP_NODE_CLASS_NODE: - return "YP_NODE_CLASS_NODE"; - case YP_NODE_CLASS_VARIABLE_AND_WRITE_NODE: - return "YP_NODE_CLASS_VARIABLE_AND_WRITE_NODE"; - case YP_NODE_CLASS_VARIABLE_OPERATOR_WRITE_NODE: - return "YP_NODE_CLASS_VARIABLE_OPERATOR_WRITE_NODE"; - case YP_NODE_CLASS_VARIABLE_OR_WRITE_NODE: - return "YP_NODE_CLASS_VARIABLE_OR_WRITE_NODE"; - case YP_NODE_CLASS_VARIABLE_READ_NODE: - return "YP_NODE_CLASS_VARIABLE_READ_NODE"; - case YP_NODE_CLASS_VARIABLE_TARGET_NODE: - return "YP_NODE_CLASS_VARIABLE_TARGET_NODE"; - case YP_NODE_CLASS_VARIABLE_WRITE_NODE: - return "YP_NODE_CLASS_VARIABLE_WRITE_NODE"; - case YP_NODE_CONSTANT_AND_WRITE_NODE: - return "YP_NODE_CONSTANT_AND_WRITE_NODE"; - case YP_NODE_CONSTANT_OPERATOR_WRITE_NODE: - return "YP_NODE_CONSTANT_OPERATOR_WRITE_NODE"; - case YP_NODE_CONSTANT_OR_WRITE_NODE: - return "YP_NODE_CONSTANT_OR_WRITE_NODE"; - case YP_NODE_CONSTANT_PATH_AND_WRITE_NODE: - return "YP_NODE_CONSTANT_PATH_AND_WRITE_NODE"; - case YP_NODE_CONSTANT_PATH_NODE: - return "YP_NODE_CONSTANT_PATH_NODE"; - case YP_NODE_CONSTANT_PATH_OPERATOR_WRITE_NODE: - return "YP_NODE_CONSTANT_PATH_OPERATOR_WRITE_NODE"; - case YP_NODE_CONSTANT_PATH_OR_WRITE_NODE: - return "YP_NODE_CONSTANT_PATH_OR_WRITE_NODE"; - case YP_NODE_CONSTANT_PATH_TARGET_NODE: - return "YP_NODE_CONSTANT_PATH_TARGET_NODE"; - case YP_NODE_CONSTANT_PATH_WRITE_NODE: - return "YP_NODE_CONSTANT_PATH_WRITE_NODE"; - case YP_NODE_CONSTANT_READ_NODE: - return "YP_NODE_CONSTANT_READ_NODE"; - case YP_NODE_CONSTANT_TARGET_NODE: - return "YP_NODE_CONSTANT_TARGET_NODE"; - case YP_NODE_CONSTANT_WRITE_NODE: - return "YP_NODE_CONSTANT_WRITE_NODE"; - case YP_NODE_DEF_NODE: - return "YP_NODE_DEF_NODE"; - case YP_NODE_DEFINED_NODE: - return "YP_NODE_DEFINED_NODE"; - case YP_NODE_ELSE_NODE: - return "YP_NODE_ELSE_NODE"; - case YP_NODE_EMBEDDED_STATEMENTS_NODE: - return "YP_NODE_EMBEDDED_STATEMENTS_NODE"; - case YP_NODE_EMBEDDED_VARIABLE_NODE: - return "YP_NODE_EMBEDDED_VARIABLE_NODE"; - case YP_NODE_ENSURE_NODE: - return "YP_NODE_ENSURE_NODE"; - case YP_NODE_FALSE_NODE: - return "YP_NODE_FALSE_NODE"; - case YP_NODE_FIND_PATTERN_NODE: - return "YP_NODE_FIND_PATTERN_NODE"; - case YP_NODE_FLIP_FLOP_NODE: - return "YP_NODE_FLIP_FLOP_NODE"; - case YP_NODE_FLOAT_NODE: - return "YP_NODE_FLOAT_NODE"; - case YP_NODE_FOR_NODE: - return "YP_NODE_FOR_NODE"; - case YP_NODE_FORWARDING_ARGUMENTS_NODE: - return "YP_NODE_FORWARDING_ARGUMENTS_NODE"; - case YP_NODE_FORWARDING_PARAMETER_NODE: - return "YP_NODE_FORWARDING_PARAMETER_NODE"; - case YP_NODE_FORWARDING_SUPER_NODE: - return "YP_NODE_FORWARDING_SUPER_NODE"; - case YP_NODE_GLOBAL_VARIABLE_AND_WRITE_NODE: - return "YP_NODE_GLOBAL_VARIABLE_AND_WRITE_NODE"; - case YP_NODE_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE: - return "YP_NODE_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE"; - case YP_NODE_GLOBAL_VARIABLE_OR_WRITE_NODE: - return "YP_NODE_GLOBAL_VARIABLE_OR_WRITE_NODE"; - case YP_NODE_GLOBAL_VARIABLE_READ_NODE: - return "YP_NODE_GLOBAL_VARIABLE_READ_NODE"; - case YP_NODE_GLOBAL_VARIABLE_TARGET_NODE: - return "YP_NODE_GLOBAL_VARIABLE_TARGET_NODE"; - case YP_NODE_GLOBAL_VARIABLE_WRITE_NODE: - return "YP_NODE_GLOBAL_VARIABLE_WRITE_NODE"; - case YP_NODE_HASH_NODE: - return "YP_NODE_HASH_NODE"; - case YP_NODE_HASH_PATTERN_NODE: - return "YP_NODE_HASH_PATTERN_NODE"; - case YP_NODE_IF_NODE: - return "YP_NODE_IF_NODE"; - case YP_NODE_IMAGINARY_NODE: - return "YP_NODE_IMAGINARY_NODE"; - case YP_NODE_IN_NODE: - return "YP_NODE_IN_NODE"; - case YP_NODE_INSTANCE_VARIABLE_AND_WRITE_NODE: - return "YP_NODE_INSTANCE_VARIABLE_AND_WRITE_NODE"; - case YP_NODE_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE: - return "YP_NODE_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE"; - case YP_NODE_INSTANCE_VARIABLE_OR_WRITE_NODE: - return "YP_NODE_INSTANCE_VARIABLE_OR_WRITE_NODE"; - case YP_NODE_INSTANCE_VARIABLE_READ_NODE: - return "YP_NODE_INSTANCE_VARIABLE_READ_NODE"; - case YP_NODE_INSTANCE_VARIABLE_TARGET_NODE: - return "YP_NODE_INSTANCE_VARIABLE_TARGET_NODE"; - case YP_NODE_INSTANCE_VARIABLE_WRITE_NODE: - return "YP_NODE_INSTANCE_VARIABLE_WRITE_NODE"; - case YP_NODE_INTEGER_NODE: - return "YP_NODE_INTEGER_NODE"; - case YP_NODE_INTERPOLATED_REGULAR_EXPRESSION_NODE: - return "YP_NODE_INTERPOLATED_REGULAR_EXPRESSION_NODE"; - case YP_NODE_INTERPOLATED_STRING_NODE: - return "YP_NODE_INTERPOLATED_STRING_NODE"; - case YP_NODE_INTERPOLATED_SYMBOL_NODE: - return "YP_NODE_INTERPOLATED_SYMBOL_NODE"; - case YP_NODE_INTERPOLATED_X_STRING_NODE: - return "YP_NODE_INTERPOLATED_X_STRING_NODE"; - case YP_NODE_KEYWORD_HASH_NODE: - return "YP_NODE_KEYWORD_HASH_NODE"; - case YP_NODE_KEYWORD_PARAMETER_NODE: - return "YP_NODE_KEYWORD_PARAMETER_NODE"; - case YP_NODE_KEYWORD_REST_PARAMETER_NODE: - return "YP_NODE_KEYWORD_REST_PARAMETER_NODE"; - case YP_NODE_LAMBDA_NODE: - return "YP_NODE_LAMBDA_NODE"; - case YP_NODE_LOCAL_VARIABLE_AND_WRITE_NODE: - return "YP_NODE_LOCAL_VARIABLE_AND_WRITE_NODE"; - case YP_NODE_LOCAL_VARIABLE_OPERATOR_WRITE_NODE: - return "YP_NODE_LOCAL_VARIABLE_OPERATOR_WRITE_NODE"; - case YP_NODE_LOCAL_VARIABLE_OR_WRITE_NODE: - return "YP_NODE_LOCAL_VARIABLE_OR_WRITE_NODE"; - case YP_NODE_LOCAL_VARIABLE_READ_NODE: - return "YP_NODE_LOCAL_VARIABLE_READ_NODE"; - case YP_NODE_LOCAL_VARIABLE_TARGET_NODE: - return "YP_NODE_LOCAL_VARIABLE_TARGET_NODE"; - case YP_NODE_LOCAL_VARIABLE_WRITE_NODE: - return "YP_NODE_LOCAL_VARIABLE_WRITE_NODE"; - case YP_NODE_MATCH_PREDICATE_NODE: - return "YP_NODE_MATCH_PREDICATE_NODE"; - case YP_NODE_MATCH_REQUIRED_NODE: - return "YP_NODE_MATCH_REQUIRED_NODE"; - case YP_NODE_MISSING_NODE: - return "YP_NODE_MISSING_NODE"; - case YP_NODE_MODULE_NODE: - return "YP_NODE_MODULE_NODE"; - case YP_NODE_MULTI_WRITE_NODE: - return "YP_NODE_MULTI_WRITE_NODE"; - case YP_NODE_NEXT_NODE: - return "YP_NODE_NEXT_NODE"; - case YP_NODE_NIL_NODE: - return "YP_NODE_NIL_NODE"; - case YP_NODE_NO_KEYWORDS_PARAMETER_NODE: - return "YP_NODE_NO_KEYWORDS_PARAMETER_NODE"; - case YP_NODE_NUMBERED_REFERENCE_READ_NODE: - return "YP_NODE_NUMBERED_REFERENCE_READ_NODE"; - case YP_NODE_OPTIONAL_PARAMETER_NODE: - return "YP_NODE_OPTIONAL_PARAMETER_NODE"; - case YP_NODE_OR_NODE: - return "YP_NODE_OR_NODE"; - case YP_NODE_PARAMETERS_NODE: - return "YP_NODE_PARAMETERS_NODE"; - case YP_NODE_PARENTHESES_NODE: - return "YP_NODE_PARENTHESES_NODE"; - case YP_NODE_PINNED_EXPRESSION_NODE: - return "YP_NODE_PINNED_EXPRESSION_NODE"; - case YP_NODE_PINNED_VARIABLE_NODE: - return "YP_NODE_PINNED_VARIABLE_NODE"; - case YP_NODE_POST_EXECUTION_NODE: - return "YP_NODE_POST_EXECUTION_NODE"; - case YP_NODE_PRE_EXECUTION_NODE: - return "YP_NODE_PRE_EXECUTION_NODE"; - case YP_NODE_PROGRAM_NODE: - return "YP_NODE_PROGRAM_NODE"; - case YP_NODE_RANGE_NODE: - return "YP_NODE_RANGE_NODE"; - case YP_NODE_RATIONAL_NODE: - return "YP_NODE_RATIONAL_NODE"; - case YP_NODE_REDO_NODE: - return "YP_NODE_REDO_NODE"; - case YP_NODE_REGULAR_EXPRESSION_NODE: - return "YP_NODE_REGULAR_EXPRESSION_NODE"; - case YP_NODE_REQUIRED_DESTRUCTURED_PARAMETER_NODE: - return "YP_NODE_REQUIRED_DESTRUCTURED_PARAMETER_NODE"; - case YP_NODE_REQUIRED_PARAMETER_NODE: - return "YP_NODE_REQUIRED_PARAMETER_NODE"; - case YP_NODE_RESCUE_MODIFIER_NODE: - return "YP_NODE_RESCUE_MODIFIER_NODE"; - case YP_NODE_RESCUE_NODE: - return "YP_NODE_RESCUE_NODE"; - case YP_NODE_REST_PARAMETER_NODE: - return "YP_NODE_REST_PARAMETER_NODE"; - case YP_NODE_RETRY_NODE: - return "YP_NODE_RETRY_NODE"; - case YP_NODE_RETURN_NODE: - return "YP_NODE_RETURN_NODE"; - case YP_NODE_SELF_NODE: - return "YP_NODE_SELF_NODE"; - case YP_NODE_SINGLETON_CLASS_NODE: - return "YP_NODE_SINGLETON_CLASS_NODE"; - case YP_NODE_SOURCE_ENCODING_NODE: - return "YP_NODE_SOURCE_ENCODING_NODE"; - case YP_NODE_SOURCE_FILE_NODE: - return "YP_NODE_SOURCE_FILE_NODE"; - case YP_NODE_SOURCE_LINE_NODE: - return "YP_NODE_SOURCE_LINE_NODE"; - case YP_NODE_SPLAT_NODE: - return "YP_NODE_SPLAT_NODE"; - case YP_NODE_STATEMENTS_NODE: - return "YP_NODE_STATEMENTS_NODE"; - case YP_NODE_STRING_CONCAT_NODE: - return "YP_NODE_STRING_CONCAT_NODE"; - case YP_NODE_STRING_NODE: - return "YP_NODE_STRING_NODE"; - case YP_NODE_SUPER_NODE: - return "YP_NODE_SUPER_NODE"; - case YP_NODE_SYMBOL_NODE: - return "YP_NODE_SYMBOL_NODE"; - case YP_NODE_TRUE_NODE: - return "YP_NODE_TRUE_NODE"; - case YP_NODE_UNDEF_NODE: - return "YP_NODE_UNDEF_NODE"; - case YP_NODE_UNLESS_NODE: - return "YP_NODE_UNLESS_NODE"; - case YP_NODE_UNTIL_NODE: - return "YP_NODE_UNTIL_NODE"; - case YP_NODE_WHEN_NODE: - return "YP_NODE_WHEN_NODE"; - case YP_NODE_WHILE_NODE: - return "YP_NODE_WHILE_NODE"; - case YP_NODE_X_STRING_NODE: - return "YP_NODE_X_STRING_NODE"; - case YP_NODE_YIELD_NODE: - return "YP_NODE_YIELD_NODE"; + case YP_ALIAS_GLOBAL_VARIABLE_NODE: + return "YP_ALIAS_GLOBAL_VARIABLE_NODE"; + case YP_ALIAS_METHOD_NODE: + return "YP_ALIAS_METHOD_NODE"; + case YP_ALTERNATION_PATTERN_NODE: + return "YP_ALTERNATION_PATTERN_NODE"; + case YP_AND_NODE: + return "YP_AND_NODE"; + case YP_ARGUMENTS_NODE: + return "YP_ARGUMENTS_NODE"; + case YP_ARRAY_NODE: + return "YP_ARRAY_NODE"; + case YP_ARRAY_PATTERN_NODE: + return "YP_ARRAY_PATTERN_NODE"; + case YP_ASSOC_NODE: + return "YP_ASSOC_NODE"; + case YP_ASSOC_SPLAT_NODE: + return "YP_ASSOC_SPLAT_NODE"; + case YP_BACK_REFERENCE_READ_NODE: + return "YP_BACK_REFERENCE_READ_NODE"; + case YP_BEGIN_NODE: + return "YP_BEGIN_NODE"; + case YP_BLOCK_ARGUMENT_NODE: + return "YP_BLOCK_ARGUMENT_NODE"; + case YP_BLOCK_LOCAL_VARIABLE_NODE: + return "YP_BLOCK_LOCAL_VARIABLE_NODE"; + case YP_BLOCK_NODE: + return "YP_BLOCK_NODE"; + case YP_BLOCK_PARAMETER_NODE: + return "YP_BLOCK_PARAMETER_NODE"; + case YP_BLOCK_PARAMETERS_NODE: + return "YP_BLOCK_PARAMETERS_NODE"; + case YP_BREAK_NODE: + return "YP_BREAK_NODE"; + case YP_CALL_AND_WRITE_NODE: + return "YP_CALL_AND_WRITE_NODE"; + case YP_CALL_NODE: + return "YP_CALL_NODE"; + case YP_CALL_OPERATOR_WRITE_NODE: + return "YP_CALL_OPERATOR_WRITE_NODE"; + case YP_CALL_OR_WRITE_NODE: + return "YP_CALL_OR_WRITE_NODE"; + case YP_CAPTURE_PATTERN_NODE: + return "YP_CAPTURE_PATTERN_NODE"; + case YP_CASE_NODE: + return "YP_CASE_NODE"; + case YP_CLASS_NODE: + return "YP_CLASS_NODE"; + case YP_CLASS_VARIABLE_AND_WRITE_NODE: + return "YP_CLASS_VARIABLE_AND_WRITE_NODE"; + case YP_CLASS_VARIABLE_OPERATOR_WRITE_NODE: + return "YP_CLASS_VARIABLE_OPERATOR_WRITE_NODE"; + case YP_CLASS_VARIABLE_OR_WRITE_NODE: + return "YP_CLASS_VARIABLE_OR_WRITE_NODE"; + case YP_CLASS_VARIABLE_READ_NODE: + return "YP_CLASS_VARIABLE_READ_NODE"; + case YP_CLASS_VARIABLE_TARGET_NODE: + return "YP_CLASS_VARIABLE_TARGET_NODE"; + case YP_CLASS_VARIABLE_WRITE_NODE: + return "YP_CLASS_VARIABLE_WRITE_NODE"; + case YP_CONSTANT_AND_WRITE_NODE: + return "YP_CONSTANT_AND_WRITE_NODE"; + case YP_CONSTANT_OPERATOR_WRITE_NODE: + return "YP_CONSTANT_OPERATOR_WRITE_NODE"; + case YP_CONSTANT_OR_WRITE_NODE: + return "YP_CONSTANT_OR_WRITE_NODE"; + case YP_CONSTANT_PATH_AND_WRITE_NODE: + return "YP_CONSTANT_PATH_AND_WRITE_NODE"; + case YP_CONSTANT_PATH_NODE: + return "YP_CONSTANT_PATH_NODE"; + case YP_CONSTANT_PATH_OPERATOR_WRITE_NODE: + return "YP_CONSTANT_PATH_OPERATOR_WRITE_NODE"; + case YP_CONSTANT_PATH_OR_WRITE_NODE: + return "YP_CONSTANT_PATH_OR_WRITE_NODE"; + case YP_CONSTANT_PATH_TARGET_NODE: + return "YP_CONSTANT_PATH_TARGET_NODE"; + case YP_CONSTANT_PATH_WRITE_NODE: + return "YP_CONSTANT_PATH_WRITE_NODE"; + case YP_CONSTANT_READ_NODE: + return "YP_CONSTANT_READ_NODE"; + case YP_CONSTANT_TARGET_NODE: + return "YP_CONSTANT_TARGET_NODE"; + case YP_CONSTANT_WRITE_NODE: + return "YP_CONSTANT_WRITE_NODE"; + case YP_DEF_NODE: + return "YP_DEF_NODE"; + case YP_DEFINED_NODE: + return "YP_DEFINED_NODE"; + case YP_ELSE_NODE: + return "YP_ELSE_NODE"; + case YP_EMBEDDED_STATEMENTS_NODE: + return "YP_EMBEDDED_STATEMENTS_NODE"; + case YP_EMBEDDED_VARIABLE_NODE: + return "YP_EMBEDDED_VARIABLE_NODE"; + case YP_ENSURE_NODE: + return "YP_ENSURE_NODE"; + case YP_FALSE_NODE: + return "YP_FALSE_NODE"; + case YP_FIND_PATTERN_NODE: + return "YP_FIND_PATTERN_NODE"; + case YP_FLIP_FLOP_NODE: + return "YP_FLIP_FLOP_NODE"; + case YP_FLOAT_NODE: + return "YP_FLOAT_NODE"; + case YP_FOR_NODE: + return "YP_FOR_NODE"; + case YP_FORWARDING_ARGUMENTS_NODE: + return "YP_FORWARDING_ARGUMENTS_NODE"; + case YP_FORWARDING_PARAMETER_NODE: + return "YP_FORWARDING_PARAMETER_NODE"; + case YP_FORWARDING_SUPER_NODE: + return "YP_FORWARDING_SUPER_NODE"; + case YP_GLOBAL_VARIABLE_AND_WRITE_NODE: + return "YP_GLOBAL_VARIABLE_AND_WRITE_NODE"; + case YP_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE: + return "YP_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE"; + case YP_GLOBAL_VARIABLE_OR_WRITE_NODE: + return "YP_GLOBAL_VARIABLE_OR_WRITE_NODE"; + case YP_GLOBAL_VARIABLE_READ_NODE: + return "YP_GLOBAL_VARIABLE_READ_NODE"; + case YP_GLOBAL_VARIABLE_TARGET_NODE: + return "YP_GLOBAL_VARIABLE_TARGET_NODE"; + case YP_GLOBAL_VARIABLE_WRITE_NODE: + return "YP_GLOBAL_VARIABLE_WRITE_NODE"; + case YP_HASH_NODE: + return "YP_HASH_NODE"; + case YP_HASH_PATTERN_NODE: + return "YP_HASH_PATTERN_NODE"; + case YP_IF_NODE: + return "YP_IF_NODE"; + case YP_IMAGINARY_NODE: + return "YP_IMAGINARY_NODE"; + case YP_IMPLICIT_NODE: + return "YP_IMPLICIT_NODE"; + case YP_IN_NODE: + return "YP_IN_NODE"; + case YP_INSTANCE_VARIABLE_AND_WRITE_NODE: + return "YP_INSTANCE_VARIABLE_AND_WRITE_NODE"; + case YP_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE: + return "YP_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE"; + case YP_INSTANCE_VARIABLE_OR_WRITE_NODE: + return "YP_INSTANCE_VARIABLE_OR_WRITE_NODE"; + case YP_INSTANCE_VARIABLE_READ_NODE: + return "YP_INSTANCE_VARIABLE_READ_NODE"; + case YP_INSTANCE_VARIABLE_TARGET_NODE: + return "YP_INSTANCE_VARIABLE_TARGET_NODE"; + case YP_INSTANCE_VARIABLE_WRITE_NODE: + return "YP_INSTANCE_VARIABLE_WRITE_NODE"; + case YP_INTEGER_NODE: + return "YP_INTEGER_NODE"; + case YP_INTERPOLATED_MATCH_LAST_LINE_NODE: + return "YP_INTERPOLATED_MATCH_LAST_LINE_NODE"; + case YP_INTERPOLATED_REGULAR_EXPRESSION_NODE: + return "YP_INTERPOLATED_REGULAR_EXPRESSION_NODE"; + case YP_INTERPOLATED_STRING_NODE: + return "YP_INTERPOLATED_STRING_NODE"; + case YP_INTERPOLATED_SYMBOL_NODE: + return "YP_INTERPOLATED_SYMBOL_NODE"; + case YP_INTERPOLATED_X_STRING_NODE: + return "YP_INTERPOLATED_X_STRING_NODE"; + case YP_KEYWORD_HASH_NODE: + return "YP_KEYWORD_HASH_NODE"; + case YP_KEYWORD_PARAMETER_NODE: + return "YP_KEYWORD_PARAMETER_NODE"; + case YP_KEYWORD_REST_PARAMETER_NODE: + return "YP_KEYWORD_REST_PARAMETER_NODE"; + case YP_LAMBDA_NODE: + return "YP_LAMBDA_NODE"; + case YP_LOCAL_VARIABLE_AND_WRITE_NODE: + return "YP_LOCAL_VARIABLE_AND_WRITE_NODE"; + case YP_LOCAL_VARIABLE_OPERATOR_WRITE_NODE: + return "YP_LOCAL_VARIABLE_OPERATOR_WRITE_NODE"; + case YP_LOCAL_VARIABLE_OR_WRITE_NODE: + return "YP_LOCAL_VARIABLE_OR_WRITE_NODE"; + case YP_LOCAL_VARIABLE_READ_NODE: + return "YP_LOCAL_VARIABLE_READ_NODE"; + case YP_LOCAL_VARIABLE_TARGET_NODE: + return "YP_LOCAL_VARIABLE_TARGET_NODE"; + case YP_LOCAL_VARIABLE_WRITE_NODE: + return "YP_LOCAL_VARIABLE_WRITE_NODE"; + case YP_MATCH_LAST_LINE_NODE: + return "YP_MATCH_LAST_LINE_NODE"; + case YP_MATCH_PREDICATE_NODE: + return "YP_MATCH_PREDICATE_NODE"; + case YP_MATCH_REQUIRED_NODE: + return "YP_MATCH_REQUIRED_NODE"; + case YP_MATCH_WRITE_NODE: + return "YP_MATCH_WRITE_NODE"; + case YP_MISSING_NODE: + return "YP_MISSING_NODE"; + case YP_MODULE_NODE: + return "YP_MODULE_NODE"; + case YP_MULTI_TARGET_NODE: + return "YP_MULTI_TARGET_NODE"; + case YP_MULTI_WRITE_NODE: + return "YP_MULTI_WRITE_NODE"; + case YP_NEXT_NODE: + return "YP_NEXT_NODE"; + case YP_NIL_NODE: + return "YP_NIL_NODE"; + case YP_NO_KEYWORDS_PARAMETER_NODE: + return "YP_NO_KEYWORDS_PARAMETER_NODE"; + case YP_NUMBERED_REFERENCE_READ_NODE: + return "YP_NUMBERED_REFERENCE_READ_NODE"; + case YP_OPTIONAL_PARAMETER_NODE: + return "YP_OPTIONAL_PARAMETER_NODE"; + case YP_OR_NODE: + return "YP_OR_NODE"; + case YP_PARAMETERS_NODE: + return "YP_PARAMETERS_NODE"; + case YP_PARENTHESES_NODE: + return "YP_PARENTHESES_NODE"; + case YP_PINNED_EXPRESSION_NODE: + return "YP_PINNED_EXPRESSION_NODE"; + case YP_PINNED_VARIABLE_NODE: + return "YP_PINNED_VARIABLE_NODE"; + case YP_POST_EXECUTION_NODE: + return "YP_POST_EXECUTION_NODE"; + case YP_PRE_EXECUTION_NODE: + return "YP_PRE_EXECUTION_NODE"; + case YP_PROGRAM_NODE: + return "YP_PROGRAM_NODE"; + case YP_RANGE_NODE: + return "YP_RANGE_NODE"; + case YP_RATIONAL_NODE: + return "YP_RATIONAL_NODE"; + case YP_REDO_NODE: + return "YP_REDO_NODE"; + case YP_REGULAR_EXPRESSION_NODE: + return "YP_REGULAR_EXPRESSION_NODE"; + case YP_REQUIRED_DESTRUCTURED_PARAMETER_NODE: + return "YP_REQUIRED_DESTRUCTURED_PARAMETER_NODE"; + case YP_REQUIRED_PARAMETER_NODE: + return "YP_REQUIRED_PARAMETER_NODE"; + case YP_RESCUE_MODIFIER_NODE: + return "YP_RESCUE_MODIFIER_NODE"; + case YP_RESCUE_NODE: + return "YP_RESCUE_NODE"; + case YP_REST_PARAMETER_NODE: + return "YP_REST_PARAMETER_NODE"; + case YP_RETRY_NODE: + return "YP_RETRY_NODE"; + case YP_RETURN_NODE: + return "YP_RETURN_NODE"; + case YP_SELF_NODE: + return "YP_SELF_NODE"; + case YP_SINGLETON_CLASS_NODE: + return "YP_SINGLETON_CLASS_NODE"; + case YP_SOURCE_ENCODING_NODE: + return "YP_SOURCE_ENCODING_NODE"; + case YP_SOURCE_FILE_NODE: + return "YP_SOURCE_FILE_NODE"; + case YP_SOURCE_LINE_NODE: + return "YP_SOURCE_LINE_NODE"; + case YP_SPLAT_NODE: + return "YP_SPLAT_NODE"; + case YP_STATEMENTS_NODE: + return "YP_STATEMENTS_NODE"; + case YP_STRING_CONCAT_NODE: + return "YP_STRING_CONCAT_NODE"; + case YP_STRING_NODE: + return "YP_STRING_NODE"; + case YP_SUPER_NODE: + return "YP_SUPER_NODE"; + case YP_SYMBOL_NODE: + return "YP_SYMBOL_NODE"; + case YP_TRUE_NODE: + return "YP_TRUE_NODE"; + case YP_UNDEF_NODE: + return "YP_UNDEF_NODE"; + case YP_UNLESS_NODE: + return "YP_UNLESS_NODE"; + case YP_UNTIL_NODE: + return "YP_UNTIL_NODE"; + case YP_WHEN_NODE: + return "YP_WHEN_NODE"; + case YP_WHILE_NODE: + return "YP_WHILE_NODE"; + case YP_X_STRING_NODE: + return "YP_X_STRING_NODE"; + case YP_YIELD_NODE: + return "YP_YIELD_NODE"; } return ""; } diff --git a/src/main/c/yarp/src/prettyprint.c b/src/main/c/yarp/src/prettyprint.c index 72e73907455a..9dc327e1a07b 100644 --- a/src/main/c/yarp/src/prettyprint.c +++ b/src/main/c/yarp/src/prettyprint.c @@ -25,17 +25,25 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { switch (YP_NODE_TYPE(node)) { // We do not need to print a ScopeNode as it's not part // of the AST - case YP_NODE_SCOPE_NODE: + case YP_SCOPE_NODE: return; - case YP_NODE_ALIAS_NODE: { - yp_buffer_append_str(buffer, "AliasNode(", 10); - prettyprint_node(buffer, parser, (yp_node_t *)((yp_alias_node_t *)node)->new_name); - yp_buffer_append_str(buffer, ", ", 2); prettyprint_node(buffer, parser, (yp_node_t *)((yp_alias_node_t *)node)->old_name); - yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_alias_node_t *)node)->keyword_loc); + case YP_ALIAS_GLOBAL_VARIABLE_NODE: { + yp_buffer_append_str(buffer, "AliasGlobalVariableNode(", 24); + prettyprint_node(buffer, parser, (yp_node_t *)((yp_alias_global_variable_node_t *)node)->new_name); + yp_buffer_append_str(buffer, ", ", 2); prettyprint_node(buffer, parser, (yp_node_t *)((yp_alias_global_variable_node_t *)node)->old_name); + yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_alias_global_variable_node_t *)node)->keyword_loc); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_ALTERNATION_PATTERN_NODE: { + case YP_ALIAS_METHOD_NODE: { + yp_buffer_append_str(buffer, "AliasMethodNode(", 16); + prettyprint_node(buffer, parser, (yp_node_t *)((yp_alias_method_node_t *)node)->new_name); + yp_buffer_append_str(buffer, ", ", 2); prettyprint_node(buffer, parser, (yp_node_t *)((yp_alias_method_node_t *)node)->old_name); + yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_alias_method_node_t *)node)->keyword_loc); + yp_buffer_append_str(buffer, ")", 1); + break; + } + case YP_ALTERNATION_PATTERN_NODE: { yp_buffer_append_str(buffer, "AlternationPatternNode(", 23); prettyprint_node(buffer, parser, (yp_node_t *)((yp_alternation_pattern_node_t *)node)->left); yp_buffer_append_str(buffer, ", ", 2); prettyprint_node(buffer, parser, (yp_node_t *)((yp_alternation_pattern_node_t *)node)->right); @@ -43,7 +51,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_AND_NODE: { + case YP_AND_NODE: { yp_buffer_append_str(buffer, "AndNode(", 8); prettyprint_node(buffer, parser, (yp_node_t *)((yp_and_node_t *)node)->left); yp_buffer_append_str(buffer, ", ", 2); prettyprint_node(buffer, parser, (yp_node_t *)((yp_and_node_t *)node)->right); @@ -51,7 +59,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_ARGUMENTS_NODE: { + case YP_ARGUMENTS_NODE: { yp_buffer_append_str(buffer, "ArgumentsNode(", 14); yp_buffer_append_str(buffer, "[", 1); for (uint32_t index = 0; index < ((yp_arguments_node_t *)node)->arguments.size; index++) { @@ -62,7 +70,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_ARRAY_NODE: { + case YP_ARRAY_NODE: { yp_buffer_append_str(buffer, "ArrayNode(", 10); yp_buffer_append_str(buffer, "[", 1); for (uint32_t index = 0; index < ((yp_array_node_t *)node)->elements.size; index++) { @@ -83,7 +91,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_ARRAY_PATTERN_NODE: { + case YP_ARRAY_PATTERN_NODE: { yp_buffer_append_str(buffer, "ArrayPatternNode(", 17); if (((yp_array_pattern_node_t *)node)->constant == NULL) { yp_buffer_append_str(buffer, "nil", 3); @@ -120,7 +128,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_ASSOC_NODE: { + case YP_ASSOC_NODE: { yp_buffer_append_str(buffer, "AssocNode(", 10); prettyprint_node(buffer, parser, (yp_node_t *)((yp_assoc_node_t *)node)->key); yp_buffer_append_str(buffer, ", ", 2); if (((yp_assoc_node_t *)node)->value == NULL) { @@ -136,7 +144,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_ASSOC_SPLAT_NODE: { + case YP_ASSOC_SPLAT_NODE: { yp_buffer_append_str(buffer, "AssocSplatNode(", 15); if (((yp_assoc_splat_node_t *)node)->value == NULL) { yp_buffer_append_str(buffer, "nil", 3); @@ -147,12 +155,12 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_BACK_REFERENCE_READ_NODE: { + case YP_BACK_REFERENCE_READ_NODE: { yp_buffer_append_str(buffer, "BackReferenceReadNode(", 22); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_BEGIN_NODE: { + case YP_BEGIN_NODE: { yp_buffer_append_str(buffer, "BeginNode(", 10); if (((yp_begin_node_t *)node)->begin_keyword_loc.start == NULL) { yp_buffer_append_str(buffer, "nil", 3); @@ -187,7 +195,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_BLOCK_ARGUMENT_NODE: { + case YP_BLOCK_ARGUMENT_NODE: { yp_buffer_append_str(buffer, "BlockArgumentNode(", 18); if (((yp_block_argument_node_t *)node)->expression == NULL) { yp_buffer_append_str(buffer, "nil", 3); @@ -198,7 +206,15 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_BLOCK_NODE: { + case YP_BLOCK_LOCAL_VARIABLE_NODE: { + yp_buffer_append_str(buffer, "BlockLocalVariableNode(", 23); + char name_buffer[12]; + snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_block_local_variable_node_t *)node)->name); + yp_buffer_append_str(buffer, name_buffer, strlen(name_buffer)); + yp_buffer_append_str(buffer, ")", 1); + break; + } + case YP_BLOCK_NODE: { yp_buffer_append_str(buffer, "BlockNode(", 10); yp_buffer_append_str(buffer, "[", 1); for (uint32_t index = 0; index < ((yp_block_node_t *)node)->locals.size; index++) { @@ -223,9 +239,16 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_BLOCK_PARAMETER_NODE: { + case YP_BLOCK_PARAMETER_NODE: { yp_buffer_append_str(buffer, "BlockParameterNode(", 19); - if (((yp_block_parameter_node_t *)node)->name_loc.start == NULL) { + if (((yp_block_parameter_node_t *)node)->name == 0) { + yp_buffer_append_str(buffer, "nil", 3); + } else { + char name_buffer[12]; + snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_block_parameter_node_t *)node)->name); + yp_buffer_append_str(buffer, name_buffer, strlen(name_buffer)); + } + yp_buffer_append_str(buffer, ", ", 2); if (((yp_block_parameter_node_t *)node)->name_loc.start == NULL) { yp_buffer_append_str(buffer, "nil", 3); } else { prettyprint_location(buffer, parser, &((yp_block_parameter_node_t *)node)->name_loc); @@ -234,7 +257,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_BLOCK_PARAMETERS_NODE: { + case YP_BLOCK_PARAMETERS_NODE: { yp_buffer_append_str(buffer, "BlockParametersNode(", 20); if (((yp_block_parameters_node_t *)node)->parameters == NULL) { yp_buffer_append_str(buffer, "nil", 3); @@ -244,7 +267,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ", ", 2); yp_buffer_append_str(buffer, "[", 1); for (uint32_t index = 0; index < ((yp_block_parameters_node_t *)node)->locals.size; index++) { if (index != 0) yp_buffer_append_str(buffer, ", ", 2); - prettyprint_location(buffer, parser, &((yp_block_parameters_node_t *)node)->locals.locations[index]); + prettyprint_node(buffer, parser, (yp_node_t *) ((yp_block_parameters_node_t *) node)->locals.nodes[index]); } yp_buffer_append_str(buffer, "]", 1); yp_buffer_append_str(buffer, ", ", 2); if (((yp_block_parameters_node_t *)node)->opening_loc.start == NULL) { @@ -260,7 +283,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_BREAK_NODE: { + case YP_BREAK_NODE: { yp_buffer_append_str(buffer, "BreakNode(", 10); if (((yp_break_node_t *)node)->arguments == NULL) { yp_buffer_append_str(buffer, "nil", 3); @@ -271,17 +294,63 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_CALL_NODE: { + case YP_CALL_AND_WRITE_NODE: { + yp_buffer_append_str(buffer, "CallAndWriteNode(", 17); + if (((yp_call_and_write_node_t *)node)->receiver == NULL) { + yp_buffer_append_str(buffer, "nil", 3); + } else { + prettyprint_node(buffer, parser, (yp_node_t *)((yp_call_and_write_node_t *)node)->receiver); + } + yp_buffer_append_str(buffer, ", ", 2); if (((yp_call_and_write_node_t *)node)->call_operator_loc.start == NULL) { + yp_buffer_append_str(buffer, "nil", 3); + } else { + prettyprint_location(buffer, parser, &((yp_call_and_write_node_t *)node)->call_operator_loc); + } + yp_buffer_append_str(buffer, ", ", 2); if (((yp_call_and_write_node_t *)node)->message_loc.start == NULL) { + yp_buffer_append_str(buffer, "nil", 3); + } else { + prettyprint_location(buffer, parser, &((yp_call_and_write_node_t *)node)->message_loc); + } + yp_buffer_append_str(buffer, ", ", 2); if (((yp_call_and_write_node_t *)node)->opening_loc.start == NULL) { + yp_buffer_append_str(buffer, "nil", 3); + } else { + prettyprint_location(buffer, parser, &((yp_call_and_write_node_t *)node)->opening_loc); + } + yp_buffer_append_str(buffer, ", ", 2); if (((yp_call_and_write_node_t *)node)->arguments == NULL) { + yp_buffer_append_str(buffer, "nil", 3); + } else { + prettyprint_node(buffer, parser, (yp_node_t *)((yp_call_and_write_node_t *)node)->arguments); + } + yp_buffer_append_str(buffer, ", ", 2); if (((yp_call_and_write_node_t *)node)->closing_loc.start == NULL) { + yp_buffer_append_str(buffer, "nil", 3); + } else { + prettyprint_location(buffer, parser, &((yp_call_and_write_node_t *)node)->closing_loc); + } + yp_buffer_append_str(buffer, ", ", 2); char flags_buffer[12]; + snprintf(flags_buffer, sizeof(flags_buffer), "+%d", node->flags >> 2); + yp_buffer_append_str(buffer, flags_buffer, strlen(flags_buffer)); + yp_buffer_append_str(buffer, ", ", 2); yp_buffer_append_str(buffer, "\"", 1); + yp_buffer_append_bytes(buffer, yp_string_source(&((yp_call_and_write_node_t *)node)->read_name), yp_string_length(&((yp_call_and_write_node_t *)node)->read_name)); + yp_buffer_append_str(buffer, "\"", 1); + yp_buffer_append_str(buffer, ", ", 2); yp_buffer_append_str(buffer, "\"", 1); + yp_buffer_append_bytes(buffer, yp_string_source(&((yp_call_and_write_node_t *)node)->write_name), yp_string_length(&((yp_call_and_write_node_t *)node)->write_name)); + yp_buffer_append_str(buffer, "\"", 1); + yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_call_and_write_node_t *)node)->operator_loc); + yp_buffer_append_str(buffer, ", ", 2); prettyprint_node(buffer, parser, (yp_node_t *)((yp_call_and_write_node_t *)node)->value); + yp_buffer_append_str(buffer, ")", 1); + break; + } + case YP_CALL_NODE: { yp_buffer_append_str(buffer, "CallNode(", 9); if (((yp_call_node_t *)node)->receiver == NULL) { yp_buffer_append_str(buffer, "nil", 3); } else { prettyprint_node(buffer, parser, (yp_node_t *)((yp_call_node_t *)node)->receiver); } - yp_buffer_append_str(buffer, ", ", 2); if (((yp_call_node_t *)node)->operator_loc.start == NULL) { + yp_buffer_append_str(buffer, ", ", 2); if (((yp_call_node_t *)node)->call_operator_loc.start == NULL) { yp_buffer_append_str(buffer, "nil", 3); } else { - prettyprint_location(buffer, parser, &((yp_call_node_t *)node)->operator_loc); + prettyprint_location(buffer, parser, &((yp_call_node_t *)node)->call_operator_loc); } yp_buffer_append_str(buffer, ", ", 2); if (((yp_call_node_t *)node)->message_loc.start == NULL) { yp_buffer_append_str(buffer, "nil", 3); @@ -309,7 +378,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { prettyprint_node(buffer, parser, (yp_node_t *)((yp_call_node_t *)node)->block); } yp_buffer_append_str(buffer, ", ", 2); char flags_buffer[12]; - snprintf(flags_buffer, sizeof(flags_buffer), "+%d", node->flags >> 1); + snprintf(flags_buffer, sizeof(flags_buffer), "+%d", node->flags >> 2); yp_buffer_append_str(buffer, flags_buffer, strlen(flags_buffer)); yp_buffer_append_str(buffer, ", ", 2); yp_buffer_append_str(buffer, "\"", 1); yp_buffer_append_bytes(buffer, yp_string_source(&((yp_call_node_t *)node)->name), yp_string_length(&((yp_call_node_t *)node)->name)); @@ -317,34 +386,102 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_CALL_OPERATOR_AND_WRITE_NODE: { - yp_buffer_append_str(buffer, "CallOperatorAndWriteNode(", 25); - prettyprint_node(buffer, parser, (yp_node_t *)((yp_call_operator_and_write_node_t *)node)->target); - yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_call_operator_and_write_node_t *)node)->operator_loc); - yp_buffer_append_str(buffer, ", ", 2); prettyprint_node(buffer, parser, (yp_node_t *)((yp_call_operator_and_write_node_t *)node)->value); - yp_buffer_append_str(buffer, ")", 1); - break; - } - case YP_NODE_CALL_OPERATOR_OR_WRITE_NODE: { - yp_buffer_append_str(buffer, "CallOperatorOrWriteNode(", 24); - prettyprint_node(buffer, parser, (yp_node_t *)((yp_call_operator_or_write_node_t *)node)->target); - yp_buffer_append_str(buffer, ", ", 2); prettyprint_node(buffer, parser, (yp_node_t *)((yp_call_operator_or_write_node_t *)node)->value); - yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_call_operator_or_write_node_t *)node)->operator_loc); - yp_buffer_append_str(buffer, ")", 1); - break; - } - case YP_NODE_CALL_OPERATOR_WRITE_NODE: { + case YP_CALL_OPERATOR_WRITE_NODE: { yp_buffer_append_str(buffer, "CallOperatorWriteNode(", 22); - prettyprint_node(buffer, parser, (yp_node_t *)((yp_call_operator_write_node_t *)node)->target); - yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_call_operator_write_node_t *)node)->operator_loc); - yp_buffer_append_str(buffer, ", ", 2); prettyprint_node(buffer, parser, (yp_node_t *)((yp_call_operator_write_node_t *)node)->value); + if (((yp_call_operator_write_node_t *)node)->receiver == NULL) { + yp_buffer_append_str(buffer, "nil", 3); + } else { + prettyprint_node(buffer, parser, (yp_node_t *)((yp_call_operator_write_node_t *)node)->receiver); + } + yp_buffer_append_str(buffer, ", ", 2); if (((yp_call_operator_write_node_t *)node)->call_operator_loc.start == NULL) { + yp_buffer_append_str(buffer, "nil", 3); + } else { + prettyprint_location(buffer, parser, &((yp_call_operator_write_node_t *)node)->call_operator_loc); + } + yp_buffer_append_str(buffer, ", ", 2); if (((yp_call_operator_write_node_t *)node)->message_loc.start == NULL) { + yp_buffer_append_str(buffer, "nil", 3); + } else { + prettyprint_location(buffer, parser, &((yp_call_operator_write_node_t *)node)->message_loc); + } + yp_buffer_append_str(buffer, ", ", 2); if (((yp_call_operator_write_node_t *)node)->opening_loc.start == NULL) { + yp_buffer_append_str(buffer, "nil", 3); + } else { + prettyprint_location(buffer, parser, &((yp_call_operator_write_node_t *)node)->opening_loc); + } + yp_buffer_append_str(buffer, ", ", 2); if (((yp_call_operator_write_node_t *)node)->arguments == NULL) { + yp_buffer_append_str(buffer, "nil", 3); + } else { + prettyprint_node(buffer, parser, (yp_node_t *)((yp_call_operator_write_node_t *)node)->arguments); + } + yp_buffer_append_str(buffer, ", ", 2); if (((yp_call_operator_write_node_t *)node)->closing_loc.start == NULL) { + yp_buffer_append_str(buffer, "nil", 3); + } else { + prettyprint_location(buffer, parser, &((yp_call_operator_write_node_t *)node)->closing_loc); + } + yp_buffer_append_str(buffer, ", ", 2); char flags_buffer[12]; + snprintf(flags_buffer, sizeof(flags_buffer), "+%d", node->flags >> 2); + yp_buffer_append_str(buffer, flags_buffer, strlen(flags_buffer)); + yp_buffer_append_str(buffer, ", ", 2); yp_buffer_append_str(buffer, "\"", 1); + yp_buffer_append_bytes(buffer, yp_string_source(&((yp_call_operator_write_node_t *)node)->read_name), yp_string_length(&((yp_call_operator_write_node_t *)node)->read_name)); + yp_buffer_append_str(buffer, "\"", 1); + yp_buffer_append_str(buffer, ", ", 2); yp_buffer_append_str(buffer, "\"", 1); + yp_buffer_append_bytes(buffer, yp_string_source(&((yp_call_operator_write_node_t *)node)->write_name), yp_string_length(&((yp_call_operator_write_node_t *)node)->write_name)); + yp_buffer_append_str(buffer, "\"", 1); yp_buffer_append_str(buffer, ", ", 2); char operator_buffer[12]; snprintf(operator_buffer, sizeof(operator_buffer), "%u", ((yp_call_operator_write_node_t *)node)->operator); yp_buffer_append_str(buffer, operator_buffer, strlen(operator_buffer)); + yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_call_operator_write_node_t *)node)->operator_loc); + yp_buffer_append_str(buffer, ", ", 2); prettyprint_node(buffer, parser, (yp_node_t *)((yp_call_operator_write_node_t *)node)->value); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_CAPTURE_PATTERN_NODE: { + case YP_CALL_OR_WRITE_NODE: { + yp_buffer_append_str(buffer, "CallOrWriteNode(", 16); + if (((yp_call_or_write_node_t *)node)->receiver == NULL) { + yp_buffer_append_str(buffer, "nil", 3); + } else { + prettyprint_node(buffer, parser, (yp_node_t *)((yp_call_or_write_node_t *)node)->receiver); + } + yp_buffer_append_str(buffer, ", ", 2); if (((yp_call_or_write_node_t *)node)->call_operator_loc.start == NULL) { + yp_buffer_append_str(buffer, "nil", 3); + } else { + prettyprint_location(buffer, parser, &((yp_call_or_write_node_t *)node)->call_operator_loc); + } + yp_buffer_append_str(buffer, ", ", 2); if (((yp_call_or_write_node_t *)node)->message_loc.start == NULL) { + yp_buffer_append_str(buffer, "nil", 3); + } else { + prettyprint_location(buffer, parser, &((yp_call_or_write_node_t *)node)->message_loc); + } + yp_buffer_append_str(buffer, ", ", 2); if (((yp_call_or_write_node_t *)node)->opening_loc.start == NULL) { + yp_buffer_append_str(buffer, "nil", 3); + } else { + prettyprint_location(buffer, parser, &((yp_call_or_write_node_t *)node)->opening_loc); + } + yp_buffer_append_str(buffer, ", ", 2); if (((yp_call_or_write_node_t *)node)->arguments == NULL) { + yp_buffer_append_str(buffer, "nil", 3); + } else { + prettyprint_node(buffer, parser, (yp_node_t *)((yp_call_or_write_node_t *)node)->arguments); + } + yp_buffer_append_str(buffer, ", ", 2); if (((yp_call_or_write_node_t *)node)->closing_loc.start == NULL) { + yp_buffer_append_str(buffer, "nil", 3); + } else { + prettyprint_location(buffer, parser, &((yp_call_or_write_node_t *)node)->closing_loc); + } + yp_buffer_append_str(buffer, ", ", 2); char flags_buffer[12]; + snprintf(flags_buffer, sizeof(flags_buffer), "+%d", node->flags >> 2); + yp_buffer_append_str(buffer, flags_buffer, strlen(flags_buffer)); + yp_buffer_append_str(buffer, ", ", 2); yp_buffer_append_str(buffer, "\"", 1); + yp_buffer_append_bytes(buffer, yp_string_source(&((yp_call_or_write_node_t *)node)->read_name), yp_string_length(&((yp_call_or_write_node_t *)node)->read_name)); + yp_buffer_append_str(buffer, "\"", 1); + yp_buffer_append_str(buffer, ", ", 2); yp_buffer_append_str(buffer, "\"", 1); + yp_buffer_append_bytes(buffer, yp_string_source(&((yp_call_or_write_node_t *)node)->write_name), yp_string_length(&((yp_call_or_write_node_t *)node)->write_name)); + yp_buffer_append_str(buffer, "\"", 1); + yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_call_or_write_node_t *)node)->operator_loc); + yp_buffer_append_str(buffer, ", ", 2); prettyprint_node(buffer, parser, (yp_node_t *)((yp_call_or_write_node_t *)node)->value); + yp_buffer_append_str(buffer, ")", 1); + break; + } + case YP_CAPTURE_PATTERN_NODE: { yp_buffer_append_str(buffer, "CapturePatternNode(", 19); prettyprint_node(buffer, parser, (yp_node_t *)((yp_capture_pattern_node_t *)node)->value); yp_buffer_append_str(buffer, ", ", 2); prettyprint_node(buffer, parser, (yp_node_t *)((yp_capture_pattern_node_t *)node)->target); @@ -352,7 +489,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_CASE_NODE: { + case YP_CASE_NODE: { yp_buffer_append_str(buffer, "CaseNode(", 9); if (((yp_case_node_t *)node)->predicate == NULL) { yp_buffer_append_str(buffer, "nil", 3); @@ -375,7 +512,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_CLASS_NODE: { + case YP_CLASS_NODE: { yp_buffer_append_str(buffer, "ClassNode(", 10); yp_buffer_append_str(buffer, "[", 1); for (uint32_t index = 0; index < ((yp_class_node_t *)node)->locals.size; index++) { @@ -403,13 +540,13 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { prettyprint_node(buffer, parser, (yp_node_t *)((yp_class_node_t *)node)->body); } yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_class_node_t *)node)->end_keyword_loc); - yp_buffer_append_str(buffer, ", ", 2); yp_buffer_append_str(buffer, "\"", 1); - yp_buffer_append_bytes(buffer, yp_string_source(&((yp_class_node_t *)node)->name), yp_string_length(&((yp_class_node_t *)node)->name)); - yp_buffer_append_str(buffer, "\"", 1); + yp_buffer_append_str(buffer, ", ", 2); char name_buffer[12]; + snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_class_node_t *)node)->name); + yp_buffer_append_str(buffer, name_buffer, strlen(name_buffer)); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_CLASS_VARIABLE_AND_WRITE_NODE: { + case YP_CLASS_VARIABLE_AND_WRITE_NODE: { yp_buffer_append_str(buffer, "ClassVariableAndWriteNode(", 26); char name_buffer[12]; snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_class_variable_and_write_node_t *)node)->name); @@ -420,7 +557,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_CLASS_VARIABLE_OPERATOR_WRITE_NODE: { + case YP_CLASS_VARIABLE_OPERATOR_WRITE_NODE: { yp_buffer_append_str(buffer, "ClassVariableOperatorWriteNode(", 31); char name_buffer[12]; snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_class_variable_operator_write_node_t *)node)->name); @@ -434,7 +571,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_CLASS_VARIABLE_OR_WRITE_NODE: { + case YP_CLASS_VARIABLE_OR_WRITE_NODE: { yp_buffer_append_str(buffer, "ClassVariableOrWriteNode(", 25); char name_buffer[12]; snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_class_variable_or_write_node_t *)node)->name); @@ -445,7 +582,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_CLASS_VARIABLE_READ_NODE: { + case YP_CLASS_VARIABLE_READ_NODE: { yp_buffer_append_str(buffer, "ClassVariableReadNode(", 22); char name_buffer[12]; snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_class_variable_read_node_t *)node)->name); @@ -453,7 +590,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_CLASS_VARIABLE_TARGET_NODE: { + case YP_CLASS_VARIABLE_TARGET_NODE: { yp_buffer_append_str(buffer, "ClassVariableTargetNode(", 24); char name_buffer[12]; snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_class_variable_target_node_t *)node)->name); @@ -461,17 +598,13 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_CLASS_VARIABLE_WRITE_NODE: { + case YP_CLASS_VARIABLE_WRITE_NODE: { yp_buffer_append_str(buffer, "ClassVariableWriteNode(", 23); char name_buffer[12]; snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_class_variable_write_node_t *)node)->name); yp_buffer_append_str(buffer, name_buffer, strlen(name_buffer)); yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_class_variable_write_node_t *)node)->name_loc); - yp_buffer_append_str(buffer, ", ", 2); if (((yp_class_variable_write_node_t *)node)->value == NULL) { - yp_buffer_append_str(buffer, "nil", 3); - } else { - prettyprint_node(buffer, parser, (yp_node_t *)((yp_class_variable_write_node_t *)node)->value); - } + yp_buffer_append_str(buffer, ", ", 2); prettyprint_node(buffer, parser, (yp_node_t *)((yp_class_variable_write_node_t *)node)->value); yp_buffer_append_str(buffer, ", ", 2); if (((yp_class_variable_write_node_t *)node)->operator_loc.start == NULL) { yp_buffer_append_str(buffer, "nil", 3); } else { @@ -480,17 +613,23 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_CONSTANT_AND_WRITE_NODE: { + case YP_CONSTANT_AND_WRITE_NODE: { yp_buffer_append_str(buffer, "ConstantAndWriteNode(", 21); - prettyprint_location(buffer, parser, &((yp_constant_and_write_node_t *)node)->name_loc); + char name_buffer[12]; + snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_constant_and_write_node_t *)node)->name); + yp_buffer_append_str(buffer, name_buffer, strlen(name_buffer)); + yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_constant_and_write_node_t *)node)->name_loc); yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_constant_and_write_node_t *)node)->operator_loc); yp_buffer_append_str(buffer, ", ", 2); prettyprint_node(buffer, parser, (yp_node_t *)((yp_constant_and_write_node_t *)node)->value); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_CONSTANT_OPERATOR_WRITE_NODE: { + case YP_CONSTANT_OPERATOR_WRITE_NODE: { yp_buffer_append_str(buffer, "ConstantOperatorWriteNode(", 26); - prettyprint_location(buffer, parser, &((yp_constant_operator_write_node_t *)node)->name_loc); + char name_buffer[12]; + snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_constant_operator_write_node_t *)node)->name); + yp_buffer_append_str(buffer, name_buffer, strlen(name_buffer)); + yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_constant_operator_write_node_t *)node)->name_loc); yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_constant_operator_write_node_t *)node)->operator_loc); yp_buffer_append_str(buffer, ", ", 2); prettyprint_node(buffer, parser, (yp_node_t *)((yp_constant_operator_write_node_t *)node)->value); yp_buffer_append_str(buffer, ", ", 2); char operator_buffer[12]; @@ -499,15 +638,18 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_CONSTANT_OR_WRITE_NODE: { + case YP_CONSTANT_OR_WRITE_NODE: { yp_buffer_append_str(buffer, "ConstantOrWriteNode(", 20); - prettyprint_location(buffer, parser, &((yp_constant_or_write_node_t *)node)->name_loc); + char name_buffer[12]; + snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_constant_or_write_node_t *)node)->name); + yp_buffer_append_str(buffer, name_buffer, strlen(name_buffer)); + yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_constant_or_write_node_t *)node)->name_loc); yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_constant_or_write_node_t *)node)->operator_loc); yp_buffer_append_str(buffer, ", ", 2); prettyprint_node(buffer, parser, (yp_node_t *)((yp_constant_or_write_node_t *)node)->value); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_CONSTANT_PATH_AND_WRITE_NODE: { + case YP_CONSTANT_PATH_AND_WRITE_NODE: { yp_buffer_append_str(buffer, "ConstantPathAndWriteNode(", 25); prettyprint_node(buffer, parser, (yp_node_t *)((yp_constant_path_and_write_node_t *)node)->target); yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_constant_path_and_write_node_t *)node)->operator_loc); @@ -515,7 +657,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_CONSTANT_PATH_NODE: { + case YP_CONSTANT_PATH_NODE: { yp_buffer_append_str(buffer, "ConstantPathNode(", 17); if (((yp_constant_path_node_t *)node)->parent == NULL) { yp_buffer_append_str(buffer, "nil", 3); @@ -527,7 +669,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_CONSTANT_PATH_OPERATOR_WRITE_NODE: { + case YP_CONSTANT_PATH_OPERATOR_WRITE_NODE: { yp_buffer_append_str(buffer, "ConstantPathOperatorWriteNode(", 30); prettyprint_node(buffer, parser, (yp_node_t *)((yp_constant_path_operator_write_node_t *)node)->target); yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_constant_path_operator_write_node_t *)node)->operator_loc); @@ -538,7 +680,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_CONSTANT_PATH_OR_WRITE_NODE: { + case YP_CONSTANT_PATH_OR_WRITE_NODE: { yp_buffer_append_str(buffer, "ConstantPathOrWriteNode(", 24); prettyprint_node(buffer, parser, (yp_node_t *)((yp_constant_path_or_write_node_t *)node)->target); yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_constant_path_or_write_node_t *)node)->operator_loc); @@ -546,7 +688,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_CONSTANT_PATH_TARGET_NODE: { + case YP_CONSTANT_PATH_TARGET_NODE: { yp_buffer_append_str(buffer, "ConstantPathTargetNode(", 23); if (((yp_constant_path_target_node_t *)node)->parent == NULL) { yp_buffer_append_str(buffer, "nil", 3); @@ -558,7 +700,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_CONSTANT_PATH_WRITE_NODE: { + case YP_CONSTANT_PATH_WRITE_NODE: { yp_buffer_append_str(buffer, "ConstantPathWriteNode(", 22); prettyprint_node(buffer, parser, (yp_node_t *)((yp_constant_path_write_node_t *)node)->target); yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_constant_path_write_node_t *)node)->operator_loc); @@ -566,27 +708,39 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_CONSTANT_READ_NODE: { + case YP_CONSTANT_READ_NODE: { yp_buffer_append_str(buffer, "ConstantReadNode(", 17); + char name_buffer[12]; + snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_constant_read_node_t *)node)->name); + yp_buffer_append_str(buffer, name_buffer, strlen(name_buffer)); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_CONSTANT_TARGET_NODE: { + case YP_CONSTANT_TARGET_NODE: { yp_buffer_append_str(buffer, "ConstantTargetNode(", 19); + char name_buffer[12]; + snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_constant_target_node_t *)node)->name); + yp_buffer_append_str(buffer, name_buffer, strlen(name_buffer)); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_CONSTANT_WRITE_NODE: { + case YP_CONSTANT_WRITE_NODE: { yp_buffer_append_str(buffer, "ConstantWriteNode(", 18); - prettyprint_location(buffer, parser, &((yp_constant_write_node_t *)node)->name_loc); + char name_buffer[12]; + snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_constant_write_node_t *)node)->name); + yp_buffer_append_str(buffer, name_buffer, strlen(name_buffer)); + yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_constant_write_node_t *)node)->name_loc); yp_buffer_append_str(buffer, ", ", 2); prettyprint_node(buffer, parser, (yp_node_t *)((yp_constant_write_node_t *)node)->value); yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_constant_write_node_t *)node)->operator_loc); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_DEF_NODE: { + case YP_DEF_NODE: { yp_buffer_append_str(buffer, "DefNode(", 8); - prettyprint_location(buffer, parser, &((yp_def_node_t *)node)->name_loc); + char name_buffer[12]; + snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_def_node_t *)node)->name); + yp_buffer_append_str(buffer, name_buffer, strlen(name_buffer)); + yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_def_node_t *)node)->name_loc); yp_buffer_append_str(buffer, ", ", 2); if (((yp_def_node_t *)node)->receiver == NULL) { yp_buffer_append_str(buffer, "nil", 3); } else { @@ -639,7 +793,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_DEFINED_NODE: { + case YP_DEFINED_NODE: { yp_buffer_append_str(buffer, "DefinedNode(", 12); if (((yp_defined_node_t *)node)->lparen_loc.start == NULL) { yp_buffer_append_str(buffer, "nil", 3); @@ -656,7 +810,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_ELSE_NODE: { + case YP_ELSE_NODE: { yp_buffer_append_str(buffer, "ElseNode(", 9); prettyprint_location(buffer, parser, &((yp_else_node_t *)node)->else_keyword_loc); yp_buffer_append_str(buffer, ", ", 2); if (((yp_else_node_t *)node)->statements == NULL) { @@ -672,7 +826,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_EMBEDDED_STATEMENTS_NODE: { + case YP_EMBEDDED_STATEMENTS_NODE: { yp_buffer_append_str(buffer, "EmbeddedStatementsNode(", 23); prettyprint_location(buffer, parser, &((yp_embedded_statements_node_t *)node)->opening_loc); yp_buffer_append_str(buffer, ", ", 2); if (((yp_embedded_statements_node_t *)node)->statements == NULL) { @@ -684,14 +838,14 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_EMBEDDED_VARIABLE_NODE: { + case YP_EMBEDDED_VARIABLE_NODE: { yp_buffer_append_str(buffer, "EmbeddedVariableNode(", 21); prettyprint_location(buffer, parser, &((yp_embedded_variable_node_t *)node)->operator_loc); yp_buffer_append_str(buffer, ", ", 2); prettyprint_node(buffer, parser, (yp_node_t *)((yp_embedded_variable_node_t *)node)->variable); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_ENSURE_NODE: { + case YP_ENSURE_NODE: { yp_buffer_append_str(buffer, "EnsureNode(", 11); prettyprint_location(buffer, parser, &((yp_ensure_node_t *)node)->ensure_keyword_loc); yp_buffer_append_str(buffer, ", ", 2); if (((yp_ensure_node_t *)node)->statements == NULL) { @@ -703,12 +857,12 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_FALSE_NODE: { + case YP_FALSE_NODE: { yp_buffer_append_str(buffer, "FalseNode(", 10); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_FIND_PATTERN_NODE: { + case YP_FIND_PATTERN_NODE: { yp_buffer_append_str(buffer, "FindPatternNode(", 16); if (((yp_find_pattern_node_t *)node)->constant == NULL) { yp_buffer_append_str(buffer, "nil", 3); @@ -736,7 +890,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_FLIP_FLOP_NODE: { + case YP_FLIP_FLOP_NODE: { yp_buffer_append_str(buffer, "FlipFlopNode(", 13); if (((yp_flip_flop_node_t *)node)->left == NULL) { yp_buffer_append_str(buffer, "nil", 3); @@ -750,17 +904,17 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { } yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_flip_flop_node_t *)node)->operator_loc); yp_buffer_append_str(buffer, ", ", 2); char flags_buffer[12]; - snprintf(flags_buffer, sizeof(flags_buffer), "+%d", node->flags >> 1); + snprintf(flags_buffer, sizeof(flags_buffer), "+%d", node->flags >> 2); yp_buffer_append_str(buffer, flags_buffer, strlen(flags_buffer)); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_FLOAT_NODE: { + case YP_FLOAT_NODE: { yp_buffer_append_str(buffer, "FloatNode(", 10); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_FOR_NODE: { + case YP_FOR_NODE: { yp_buffer_append_str(buffer, "ForNode(", 8); prettyprint_node(buffer, parser, (yp_node_t *)((yp_for_node_t *)node)->index); yp_buffer_append_str(buffer, ", ", 2); prettyprint_node(buffer, parser, (yp_node_t *)((yp_for_node_t *)node)->collection); @@ -780,17 +934,17 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_FORWARDING_ARGUMENTS_NODE: { + case YP_FORWARDING_ARGUMENTS_NODE: { yp_buffer_append_str(buffer, "ForwardingArgumentsNode(", 24); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_FORWARDING_PARAMETER_NODE: { + case YP_FORWARDING_PARAMETER_NODE: { yp_buffer_append_str(buffer, "ForwardingParameterNode(", 24); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_FORWARDING_SUPER_NODE: { + case YP_FORWARDING_SUPER_NODE: { yp_buffer_append_str(buffer, "ForwardingSuperNode(", 20); if (((yp_forwarding_super_node_t *)node)->block == NULL) { yp_buffer_append_str(buffer, "nil", 3); @@ -800,7 +954,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_GLOBAL_VARIABLE_AND_WRITE_NODE: { + case YP_GLOBAL_VARIABLE_AND_WRITE_NODE: { yp_buffer_append_str(buffer, "GlobalVariableAndWriteNode(", 27); char name_buffer[12]; snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_global_variable_and_write_node_t *)node)->name); @@ -811,7 +965,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE: { + case YP_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE: { yp_buffer_append_str(buffer, "GlobalVariableOperatorWriteNode(", 32); char name_buffer[12]; snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_global_variable_operator_write_node_t *)node)->name); @@ -825,7 +979,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_GLOBAL_VARIABLE_OR_WRITE_NODE: { + case YP_GLOBAL_VARIABLE_OR_WRITE_NODE: { yp_buffer_append_str(buffer, "GlobalVariableOrWriteNode(", 26); char name_buffer[12]; snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_global_variable_or_write_node_t *)node)->name); @@ -836,7 +990,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_GLOBAL_VARIABLE_READ_NODE: { + case YP_GLOBAL_VARIABLE_READ_NODE: { yp_buffer_append_str(buffer, "GlobalVariableReadNode(", 23); char name_buffer[12]; snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_global_variable_read_node_t *)node)->name); @@ -844,7 +998,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_GLOBAL_VARIABLE_TARGET_NODE: { + case YP_GLOBAL_VARIABLE_TARGET_NODE: { yp_buffer_append_str(buffer, "GlobalVariableTargetNode(", 25); char name_buffer[12]; snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_global_variable_target_node_t *)node)->name); @@ -852,7 +1006,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_GLOBAL_VARIABLE_WRITE_NODE: { + case YP_GLOBAL_VARIABLE_WRITE_NODE: { yp_buffer_append_str(buffer, "GlobalVariableWriteNode(", 24); char name_buffer[12]; snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_global_variable_write_node_t *)node)->name); @@ -863,7 +1017,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_HASH_NODE: { + case YP_HASH_NODE: { yp_buffer_append_str(buffer, "HashNode(", 9); prettyprint_location(buffer, parser, &((yp_hash_node_t *)node)->opening_loc); yp_buffer_append_str(buffer, ", ", 2); yp_buffer_append_str(buffer, "[", 1); @@ -876,7 +1030,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_HASH_PATTERN_NODE: { + case YP_HASH_PATTERN_NODE: { yp_buffer_append_str(buffer, "HashPatternNode(", 16); if (((yp_hash_pattern_node_t *)node)->constant == NULL) { yp_buffer_append_str(buffer, "nil", 3); @@ -907,7 +1061,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_IF_NODE: { + case YP_IF_NODE: { yp_buffer_append_str(buffer, "IfNode(", 7); if (((yp_if_node_t *)node)->if_keyword_loc.start == NULL) { yp_buffer_append_str(buffer, "nil", 3); @@ -933,13 +1087,19 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_IMAGINARY_NODE: { + case YP_IMAGINARY_NODE: { yp_buffer_append_str(buffer, "ImaginaryNode(", 14); prettyprint_node(buffer, parser, (yp_node_t *)((yp_imaginary_node_t *)node)->numeric); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_IN_NODE: { + case YP_IMPLICIT_NODE: { + yp_buffer_append_str(buffer, "ImplicitNode(", 13); + prettyprint_node(buffer, parser, (yp_node_t *)((yp_implicit_node_t *)node)->value); + yp_buffer_append_str(buffer, ")", 1); + break; + } + case YP_IN_NODE: { yp_buffer_append_str(buffer, "InNode(", 7); prettyprint_node(buffer, parser, (yp_node_t *)((yp_in_node_t *)node)->pattern); yp_buffer_append_str(buffer, ", ", 2); if (((yp_in_node_t *)node)->statements == NULL) { @@ -956,7 +1116,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_INSTANCE_VARIABLE_AND_WRITE_NODE: { + case YP_INSTANCE_VARIABLE_AND_WRITE_NODE: { yp_buffer_append_str(buffer, "InstanceVariableAndWriteNode(", 29); char name_buffer[12]; snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_instance_variable_and_write_node_t *)node)->name); @@ -967,7 +1127,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE: { + case YP_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE: { yp_buffer_append_str(buffer, "InstanceVariableOperatorWriteNode(", 34); char name_buffer[12]; snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_instance_variable_operator_write_node_t *)node)->name); @@ -981,7 +1141,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_INSTANCE_VARIABLE_OR_WRITE_NODE: { + case YP_INSTANCE_VARIABLE_OR_WRITE_NODE: { yp_buffer_append_str(buffer, "InstanceVariableOrWriteNode(", 28); char name_buffer[12]; snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_instance_variable_or_write_node_t *)node)->name); @@ -992,7 +1152,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_INSTANCE_VARIABLE_READ_NODE: { + case YP_INSTANCE_VARIABLE_READ_NODE: { yp_buffer_append_str(buffer, "InstanceVariableReadNode(", 25); char name_buffer[12]; snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_instance_variable_read_node_t *)node)->name); @@ -1000,7 +1160,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_INSTANCE_VARIABLE_TARGET_NODE: { + case YP_INSTANCE_VARIABLE_TARGET_NODE: { yp_buffer_append_str(buffer, "InstanceVariableTargetNode(", 27); char name_buffer[12]; snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_instance_variable_target_node_t *)node)->name); @@ -1008,7 +1168,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_INSTANCE_VARIABLE_WRITE_NODE: { + case YP_INSTANCE_VARIABLE_WRITE_NODE: { yp_buffer_append_str(buffer, "InstanceVariableWriteNode(", 26); char name_buffer[12]; snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_instance_variable_write_node_t *)node)->name); @@ -1019,12 +1179,31 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_INTEGER_NODE: { + case YP_INTEGER_NODE: { yp_buffer_append_str(buffer, "IntegerNode(", 12); + char flags_buffer[12]; + snprintf(flags_buffer, sizeof(flags_buffer), "+%d", node->flags >> 2); + yp_buffer_append_str(buffer, flags_buffer, strlen(flags_buffer)); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_INTERPOLATED_REGULAR_EXPRESSION_NODE: { + case YP_INTERPOLATED_MATCH_LAST_LINE_NODE: { + yp_buffer_append_str(buffer, "InterpolatedMatchLastLineNode(", 30); + prettyprint_location(buffer, parser, &((yp_interpolated_match_last_line_node_t *)node)->opening_loc); + yp_buffer_append_str(buffer, ", ", 2); yp_buffer_append_str(buffer, "[", 1); + for (uint32_t index = 0; index < ((yp_interpolated_match_last_line_node_t *)node)->parts.size; index++) { + if (index != 0) yp_buffer_append_str(buffer, ", ", 2); + prettyprint_node(buffer, parser, (yp_node_t *) ((yp_interpolated_match_last_line_node_t *) node)->parts.nodes[index]); + } + yp_buffer_append_str(buffer, "]", 1); + yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_interpolated_match_last_line_node_t *)node)->closing_loc); + yp_buffer_append_str(buffer, ", ", 2); char flags_buffer[12]; + snprintf(flags_buffer, sizeof(flags_buffer), "+%d", node->flags >> 2); + yp_buffer_append_str(buffer, flags_buffer, strlen(flags_buffer)); + yp_buffer_append_str(buffer, ")", 1); + break; + } + case YP_INTERPOLATED_REGULAR_EXPRESSION_NODE: { yp_buffer_append_str(buffer, "InterpolatedRegularExpressionNode(", 34); prettyprint_location(buffer, parser, &((yp_interpolated_regular_expression_node_t *)node)->opening_loc); yp_buffer_append_str(buffer, ", ", 2); yp_buffer_append_str(buffer, "[", 1); @@ -1035,12 +1214,12 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, "]", 1); yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_interpolated_regular_expression_node_t *)node)->closing_loc); yp_buffer_append_str(buffer, ", ", 2); char flags_buffer[12]; - snprintf(flags_buffer, sizeof(flags_buffer), "+%d", node->flags >> 1); + snprintf(flags_buffer, sizeof(flags_buffer), "+%d", node->flags >> 2); yp_buffer_append_str(buffer, flags_buffer, strlen(flags_buffer)); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_INTERPOLATED_STRING_NODE: { + case YP_INTERPOLATED_STRING_NODE: { yp_buffer_append_str(buffer, "InterpolatedStringNode(", 23); if (((yp_interpolated_string_node_t *)node)->opening_loc.start == NULL) { yp_buffer_append_str(buffer, "nil", 3); @@ -1061,7 +1240,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_INTERPOLATED_SYMBOL_NODE: { + case YP_INTERPOLATED_SYMBOL_NODE: { yp_buffer_append_str(buffer, "InterpolatedSymbolNode(", 23); if (((yp_interpolated_symbol_node_t *)node)->opening_loc.start == NULL) { yp_buffer_append_str(buffer, "nil", 3); @@ -1082,7 +1261,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_INTERPOLATED_X_STRING_NODE: { + case YP_INTERPOLATED_X_STRING_NODE: { yp_buffer_append_str(buffer, "InterpolatedXStringNode(", 24); prettyprint_location(buffer, parser, &((yp_interpolated_x_string_node_t *)node)->opening_loc); yp_buffer_append_str(buffer, ", ", 2); yp_buffer_append_str(buffer, "[", 1); @@ -1095,7 +1274,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_KEYWORD_HASH_NODE: { + case YP_KEYWORD_HASH_NODE: { yp_buffer_append_str(buffer, "KeywordHashNode(", 16); yp_buffer_append_str(buffer, "[", 1); for (uint32_t index = 0; index < ((yp_keyword_hash_node_t *)node)->elements.size; index++) { @@ -1106,9 +1285,12 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_KEYWORD_PARAMETER_NODE: { + case YP_KEYWORD_PARAMETER_NODE: { yp_buffer_append_str(buffer, "KeywordParameterNode(", 21); - prettyprint_location(buffer, parser, &((yp_keyword_parameter_node_t *)node)->name_loc); + char name_buffer[12]; + snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_keyword_parameter_node_t *)node)->name); + yp_buffer_append_str(buffer, name_buffer, strlen(name_buffer)); + yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_keyword_parameter_node_t *)node)->name_loc); yp_buffer_append_str(buffer, ", ", 2); if (((yp_keyword_parameter_node_t *)node)->value == NULL) { yp_buffer_append_str(buffer, "nil", 3); } else { @@ -1117,18 +1299,25 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_KEYWORD_REST_PARAMETER_NODE: { + case YP_KEYWORD_REST_PARAMETER_NODE: { yp_buffer_append_str(buffer, "KeywordRestParameterNode(", 25); - prettyprint_location(buffer, parser, &((yp_keyword_rest_parameter_node_t *)node)->operator_loc); + if (((yp_keyword_rest_parameter_node_t *)node)->name == 0) { + yp_buffer_append_str(buffer, "nil", 3); + } else { + char name_buffer[12]; + snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_keyword_rest_parameter_node_t *)node)->name); + yp_buffer_append_str(buffer, name_buffer, strlen(name_buffer)); + } yp_buffer_append_str(buffer, ", ", 2); if (((yp_keyword_rest_parameter_node_t *)node)->name_loc.start == NULL) { yp_buffer_append_str(buffer, "nil", 3); } else { prettyprint_location(buffer, parser, &((yp_keyword_rest_parameter_node_t *)node)->name_loc); } + yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_keyword_rest_parameter_node_t *)node)->operator_loc); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_LAMBDA_NODE: { + case YP_LAMBDA_NODE: { yp_buffer_append_str(buffer, "LambdaNode(", 11); yp_buffer_append_str(buffer, "[", 1); for (uint32_t index = 0; index < ((yp_lambda_node_t *)node)->locals.size; index++) { @@ -1154,7 +1343,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_LOCAL_VARIABLE_AND_WRITE_NODE: { + case YP_LOCAL_VARIABLE_AND_WRITE_NODE: { yp_buffer_append_str(buffer, "LocalVariableAndWriteNode(", 26); prettyprint_location(buffer, parser, &((yp_local_variable_and_write_node_t *)node)->name_loc); yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_local_variable_and_write_node_t *)node)->operator_loc); @@ -1168,7 +1357,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_LOCAL_VARIABLE_OPERATOR_WRITE_NODE: { + case YP_LOCAL_VARIABLE_OPERATOR_WRITE_NODE: { yp_buffer_append_str(buffer, "LocalVariableOperatorWriteNode(", 31); prettyprint_location(buffer, parser, &((yp_local_variable_operator_write_node_t *)node)->name_loc); yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_local_variable_operator_write_node_t *)node)->operator_loc); @@ -1185,7 +1374,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_LOCAL_VARIABLE_OR_WRITE_NODE: { + case YP_LOCAL_VARIABLE_OR_WRITE_NODE: { yp_buffer_append_str(buffer, "LocalVariableOrWriteNode(", 25); prettyprint_location(buffer, parser, &((yp_local_variable_or_write_node_t *)node)->name_loc); yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_local_variable_or_write_node_t *)node)->operator_loc); @@ -1199,7 +1388,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_LOCAL_VARIABLE_READ_NODE: { + case YP_LOCAL_VARIABLE_READ_NODE: { yp_buffer_append_str(buffer, "LocalVariableReadNode(", 22); char name_buffer[12]; snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_local_variable_read_node_t *)node)->name); @@ -1210,7 +1399,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_LOCAL_VARIABLE_TARGET_NODE: { + case YP_LOCAL_VARIABLE_TARGET_NODE: { yp_buffer_append_str(buffer, "LocalVariableTargetNode(", 24); char name_buffer[12]; snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_local_variable_target_node_t *)node)->name); @@ -1221,7 +1410,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_LOCAL_VARIABLE_WRITE_NODE: { + case YP_LOCAL_VARIABLE_WRITE_NODE: { yp_buffer_append_str(buffer, "LocalVariableWriteNode(", 23); char name_buffer[12]; snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_local_variable_write_node_t *)node)->name); @@ -1235,7 +1424,21 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_MATCH_PREDICATE_NODE: { + case YP_MATCH_LAST_LINE_NODE: { + yp_buffer_append_str(buffer, "MatchLastLineNode(", 18); + prettyprint_location(buffer, parser, &((yp_match_last_line_node_t *)node)->opening_loc); + yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_match_last_line_node_t *)node)->content_loc); + yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_match_last_line_node_t *)node)->closing_loc); + yp_buffer_append_str(buffer, ", ", 2); yp_buffer_append_str(buffer, "\"", 1); + yp_buffer_append_bytes(buffer, yp_string_source(&((yp_match_last_line_node_t *)node)->unescaped), yp_string_length(&((yp_match_last_line_node_t *)node)->unescaped)); + yp_buffer_append_str(buffer, "\"", 1); + yp_buffer_append_str(buffer, ", ", 2); char flags_buffer[12]; + snprintf(flags_buffer, sizeof(flags_buffer), "+%d", node->flags >> 2); + yp_buffer_append_str(buffer, flags_buffer, strlen(flags_buffer)); + yp_buffer_append_str(buffer, ")", 1); + break; + } + case YP_MATCH_PREDICATE_NODE: { yp_buffer_append_str(buffer, "MatchPredicateNode(", 19); prettyprint_node(buffer, parser, (yp_node_t *)((yp_match_predicate_node_t *)node)->value); yp_buffer_append_str(buffer, ", ", 2); prettyprint_node(buffer, parser, (yp_node_t *)((yp_match_predicate_node_t *)node)->pattern); @@ -1243,7 +1446,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_MATCH_REQUIRED_NODE: { + case YP_MATCH_REQUIRED_NODE: { yp_buffer_append_str(buffer, "MatchRequiredNode(", 18); prettyprint_node(buffer, parser, (yp_node_t *)((yp_match_required_node_t *)node)->value); yp_buffer_append_str(buffer, ", ", 2); prettyprint_node(buffer, parser, (yp_node_t *)((yp_match_required_node_t *)node)->pattern); @@ -1251,12 +1454,26 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_MISSING_NODE: { + case YP_MATCH_WRITE_NODE: { + yp_buffer_append_str(buffer, "MatchWriteNode(", 15); + prettyprint_node(buffer, parser, (yp_node_t *)((yp_match_write_node_t *)node)->call); + yp_buffer_append_str(buffer, ", ", 2); yp_buffer_append_str(buffer, "[", 1); + for (uint32_t index = 0; index < ((yp_match_write_node_t *)node)->locals.size; index++) { + if (index != 0) yp_buffer_append_str(buffer, ", ", 2); + char locals_buffer[12]; + snprintf(locals_buffer, sizeof(locals_buffer), "%u", ((yp_match_write_node_t *)node)->locals.ids[index]); + yp_buffer_append_str(buffer, locals_buffer, strlen(locals_buffer)); + } + yp_buffer_append_str(buffer, "]", 1); + yp_buffer_append_str(buffer, ")", 1); + break; + } + case YP_MISSING_NODE: { yp_buffer_append_str(buffer, "MissingNode(", 12); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_MODULE_NODE: { + case YP_MODULE_NODE: { yp_buffer_append_str(buffer, "ModuleNode(", 11); yp_buffer_append_str(buffer, "[", 1); for (uint32_t index = 0; index < ((yp_module_node_t *)node)->locals.size; index++) { @@ -1274,30 +1491,41 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { prettyprint_node(buffer, parser, (yp_node_t *)((yp_module_node_t *)node)->body); } yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_module_node_t *)node)->end_keyword_loc); - yp_buffer_append_str(buffer, ", ", 2); yp_buffer_append_str(buffer, "\"", 1); - yp_buffer_append_bytes(buffer, yp_string_source(&((yp_module_node_t *)node)->name), yp_string_length(&((yp_module_node_t *)node)->name)); - yp_buffer_append_str(buffer, "\"", 1); + yp_buffer_append_str(buffer, ", ", 2); char name_buffer[12]; + snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_module_node_t *)node)->name); + yp_buffer_append_str(buffer, name_buffer, strlen(name_buffer)); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_MULTI_WRITE_NODE: { - yp_buffer_append_str(buffer, "MultiWriteNode(", 15); + case YP_MULTI_TARGET_NODE: { + yp_buffer_append_str(buffer, "MultiTargetNode(", 16); yp_buffer_append_str(buffer, "[", 1); - for (uint32_t index = 0; index < ((yp_multi_write_node_t *)node)->targets.size; index++) { + for (uint32_t index = 0; index < ((yp_multi_target_node_t *)node)->targets.size; index++) { if (index != 0) yp_buffer_append_str(buffer, ", ", 2); - prettyprint_node(buffer, parser, (yp_node_t *) ((yp_multi_write_node_t *) node)->targets.nodes[index]); + prettyprint_node(buffer, parser, (yp_node_t *) ((yp_multi_target_node_t *) node)->targets.nodes[index]); } yp_buffer_append_str(buffer, "]", 1); - yp_buffer_append_str(buffer, ", ", 2); if (((yp_multi_write_node_t *)node)->operator_loc.start == NULL) { + yp_buffer_append_str(buffer, ", ", 2); if (((yp_multi_target_node_t *)node)->lparen_loc.start == NULL) { yp_buffer_append_str(buffer, "nil", 3); } else { - prettyprint_location(buffer, parser, &((yp_multi_write_node_t *)node)->operator_loc); + prettyprint_location(buffer, parser, &((yp_multi_target_node_t *)node)->lparen_loc); } - yp_buffer_append_str(buffer, ", ", 2); if (((yp_multi_write_node_t *)node)->value == NULL) { + yp_buffer_append_str(buffer, ", ", 2); if (((yp_multi_target_node_t *)node)->rparen_loc.start == NULL) { yp_buffer_append_str(buffer, "nil", 3); } else { - prettyprint_node(buffer, parser, (yp_node_t *)((yp_multi_write_node_t *)node)->value); + prettyprint_location(buffer, parser, &((yp_multi_target_node_t *)node)->rparen_loc); + } + yp_buffer_append_str(buffer, ")", 1); + break; + } + case YP_MULTI_WRITE_NODE: { + yp_buffer_append_str(buffer, "MultiWriteNode(", 15); + yp_buffer_append_str(buffer, "[", 1); + for (uint32_t index = 0; index < ((yp_multi_write_node_t *)node)->targets.size; index++) { + if (index != 0) yp_buffer_append_str(buffer, ", ", 2); + prettyprint_node(buffer, parser, (yp_node_t *) ((yp_multi_write_node_t *) node)->targets.nodes[index]); } + yp_buffer_append_str(buffer, "]", 1); yp_buffer_append_str(buffer, ", ", 2); if (((yp_multi_write_node_t *)node)->lparen_loc.start == NULL) { yp_buffer_append_str(buffer, "nil", 3); } else { @@ -1308,10 +1536,12 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { } else { prettyprint_location(buffer, parser, &((yp_multi_write_node_t *)node)->rparen_loc); } + yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_multi_write_node_t *)node)->operator_loc); + yp_buffer_append_str(buffer, ", ", 2); prettyprint_node(buffer, parser, (yp_node_t *)((yp_multi_write_node_t *)node)->value); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_NEXT_NODE: { + case YP_NEXT_NODE: { yp_buffer_append_str(buffer, "NextNode(", 9); if (((yp_next_node_t *)node)->arguments == NULL) { yp_buffer_append_str(buffer, "nil", 3); @@ -1322,19 +1552,19 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_NIL_NODE: { + case YP_NIL_NODE: { yp_buffer_append_str(buffer, "NilNode(", 8); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_NO_KEYWORDS_PARAMETER_NODE: { + case YP_NO_KEYWORDS_PARAMETER_NODE: { yp_buffer_append_str(buffer, "NoKeywordsParameterNode(", 24); prettyprint_location(buffer, parser, &((yp_no_keywords_parameter_node_t *)node)->operator_loc); yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_no_keywords_parameter_node_t *)node)->keyword_loc); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_NUMBERED_REFERENCE_READ_NODE: { + case YP_NUMBERED_REFERENCE_READ_NODE: { yp_buffer_append_str(buffer, "NumberedReferenceReadNode(", 26); char number_buffer[12]; snprintf(number_buffer, sizeof(number_buffer), "+%d", ((yp_numbered_reference_read_node_t *)node)->number); @@ -1342,7 +1572,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_OPTIONAL_PARAMETER_NODE: { + case YP_OPTIONAL_PARAMETER_NODE: { yp_buffer_append_str(buffer, "OptionalParameterNode(", 22); char name_buffer[12]; snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_optional_parameter_node_t *)node)->name); @@ -1353,7 +1583,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_OR_NODE: { + case YP_OR_NODE: { yp_buffer_append_str(buffer, "OrNode(", 7); prettyprint_node(buffer, parser, (yp_node_t *)((yp_or_node_t *)node)->left); yp_buffer_append_str(buffer, ", ", 2); prettyprint_node(buffer, parser, (yp_node_t *)((yp_or_node_t *)node)->right); @@ -1361,7 +1591,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_PARAMETERS_NODE: { + case YP_PARAMETERS_NODE: { yp_buffer_append_str(buffer, "ParametersNode(", 15); yp_buffer_append_str(buffer, "[", 1); for (uint32_t index = 0; index < ((yp_parameters_node_t *)node)->requireds.size; index++) { @@ -1375,17 +1605,17 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { prettyprint_node(buffer, parser, (yp_node_t *) ((yp_parameters_node_t *) node)->optionals.nodes[index]); } yp_buffer_append_str(buffer, "]", 1); + yp_buffer_append_str(buffer, ", ", 2); if (((yp_parameters_node_t *)node)->rest == NULL) { + yp_buffer_append_str(buffer, "nil", 3); + } else { + prettyprint_node(buffer, parser, (yp_node_t *)((yp_parameters_node_t *)node)->rest); + } yp_buffer_append_str(buffer, ", ", 2); yp_buffer_append_str(buffer, "[", 1); for (uint32_t index = 0; index < ((yp_parameters_node_t *)node)->posts.size; index++) { if (index != 0) yp_buffer_append_str(buffer, ", ", 2); prettyprint_node(buffer, parser, (yp_node_t *) ((yp_parameters_node_t *) node)->posts.nodes[index]); } yp_buffer_append_str(buffer, "]", 1); - yp_buffer_append_str(buffer, ", ", 2); if (((yp_parameters_node_t *)node)->rest == NULL) { - yp_buffer_append_str(buffer, "nil", 3); - } else { - prettyprint_node(buffer, parser, (yp_node_t *)((yp_parameters_node_t *)node)->rest); - } yp_buffer_append_str(buffer, ", ", 2); yp_buffer_append_str(buffer, "[", 1); for (uint32_t index = 0; index < ((yp_parameters_node_t *)node)->keywords.size; index++) { if (index != 0) yp_buffer_append_str(buffer, ", ", 2); @@ -1405,7 +1635,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_PARENTHESES_NODE: { + case YP_PARENTHESES_NODE: { yp_buffer_append_str(buffer, "ParenthesesNode(", 16); if (((yp_parentheses_node_t *)node)->body == NULL) { yp_buffer_append_str(buffer, "nil", 3); @@ -1417,7 +1647,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_PINNED_EXPRESSION_NODE: { + case YP_PINNED_EXPRESSION_NODE: { yp_buffer_append_str(buffer, "PinnedExpressionNode(", 21); prettyprint_node(buffer, parser, (yp_node_t *)((yp_pinned_expression_node_t *)node)->expression); yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_pinned_expression_node_t *)node)->operator_loc); @@ -1426,14 +1656,14 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_PINNED_VARIABLE_NODE: { + case YP_PINNED_VARIABLE_NODE: { yp_buffer_append_str(buffer, "PinnedVariableNode(", 19); prettyprint_node(buffer, parser, (yp_node_t *)((yp_pinned_variable_node_t *)node)->variable); yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_pinned_variable_node_t *)node)->operator_loc); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_POST_EXECUTION_NODE: { + case YP_POST_EXECUTION_NODE: { yp_buffer_append_str(buffer, "PostExecutionNode(", 18); if (((yp_post_execution_node_t *)node)->statements == NULL) { yp_buffer_append_str(buffer, "nil", 3); @@ -1446,7 +1676,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_PRE_EXECUTION_NODE: { + case YP_PRE_EXECUTION_NODE: { yp_buffer_append_str(buffer, "PreExecutionNode(", 17); if (((yp_pre_execution_node_t *)node)->statements == NULL) { yp_buffer_append_str(buffer, "nil", 3); @@ -1459,7 +1689,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_PROGRAM_NODE: { + case YP_PROGRAM_NODE: { yp_buffer_append_str(buffer, "ProgramNode(", 12); yp_buffer_append_str(buffer, "[", 1); for (uint32_t index = 0; index < ((yp_program_node_t *)node)->locals.size; index++) { @@ -1473,7 +1703,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_RANGE_NODE: { + case YP_RANGE_NODE: { yp_buffer_append_str(buffer, "RangeNode(", 10); if (((yp_range_node_t *)node)->left == NULL) { yp_buffer_append_str(buffer, "nil", 3); @@ -1487,23 +1717,23 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { } yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_range_node_t *)node)->operator_loc); yp_buffer_append_str(buffer, ", ", 2); char flags_buffer[12]; - snprintf(flags_buffer, sizeof(flags_buffer), "+%d", node->flags >> 1); + snprintf(flags_buffer, sizeof(flags_buffer), "+%d", node->flags >> 2); yp_buffer_append_str(buffer, flags_buffer, strlen(flags_buffer)); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_RATIONAL_NODE: { + case YP_RATIONAL_NODE: { yp_buffer_append_str(buffer, "RationalNode(", 13); prettyprint_node(buffer, parser, (yp_node_t *)((yp_rational_node_t *)node)->numeric); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_REDO_NODE: { + case YP_REDO_NODE: { yp_buffer_append_str(buffer, "RedoNode(", 9); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_REGULAR_EXPRESSION_NODE: { + case YP_REGULAR_EXPRESSION_NODE: { yp_buffer_append_str(buffer, "RegularExpressionNode(", 22); prettyprint_location(buffer, parser, &((yp_regular_expression_node_t *)node)->opening_loc); yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_regular_expression_node_t *)node)->content_loc); @@ -1512,12 +1742,12 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_bytes(buffer, yp_string_source(&((yp_regular_expression_node_t *)node)->unescaped), yp_string_length(&((yp_regular_expression_node_t *)node)->unescaped)); yp_buffer_append_str(buffer, "\"", 1); yp_buffer_append_str(buffer, ", ", 2); char flags_buffer[12]; - snprintf(flags_buffer, sizeof(flags_buffer), "+%d", node->flags >> 1); + snprintf(flags_buffer, sizeof(flags_buffer), "+%d", node->flags >> 2); yp_buffer_append_str(buffer, flags_buffer, strlen(flags_buffer)); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_REQUIRED_DESTRUCTURED_PARAMETER_NODE: { + case YP_REQUIRED_DESTRUCTURED_PARAMETER_NODE: { yp_buffer_append_str(buffer, "RequiredDestructuredParameterNode(", 34); yp_buffer_append_str(buffer, "[", 1); for (uint32_t index = 0; index < ((yp_required_destructured_parameter_node_t *)node)->parameters.size; index++) { @@ -1530,7 +1760,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_REQUIRED_PARAMETER_NODE: { + case YP_REQUIRED_PARAMETER_NODE: { yp_buffer_append_str(buffer, "RequiredParameterNode(", 22); char name_buffer[12]; snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_required_parameter_node_t *)node)->name); @@ -1538,7 +1768,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_RESCUE_MODIFIER_NODE: { + case YP_RESCUE_MODIFIER_NODE: { yp_buffer_append_str(buffer, "RescueModifierNode(", 19); prettyprint_node(buffer, parser, (yp_node_t *)((yp_rescue_modifier_node_t *)node)->expression); yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_rescue_modifier_node_t *)node)->keyword_loc); @@ -1546,7 +1776,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_RESCUE_NODE: { + case YP_RESCUE_NODE: { yp_buffer_append_str(buffer, "RescueNode(", 11); prettyprint_location(buffer, parser, &((yp_rescue_node_t *)node)->keyword_loc); yp_buffer_append_str(buffer, ", ", 2); yp_buffer_append_str(buffer, "[", 1); @@ -1578,23 +1808,30 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_REST_PARAMETER_NODE: { + case YP_REST_PARAMETER_NODE: { yp_buffer_append_str(buffer, "RestParameterNode(", 18); - prettyprint_location(buffer, parser, &((yp_rest_parameter_node_t *)node)->operator_loc); + if (((yp_rest_parameter_node_t *)node)->name == 0) { + yp_buffer_append_str(buffer, "nil", 3); + } else { + char name_buffer[12]; + snprintf(name_buffer, sizeof(name_buffer), "%u", ((yp_rest_parameter_node_t *)node)->name); + yp_buffer_append_str(buffer, name_buffer, strlen(name_buffer)); + } yp_buffer_append_str(buffer, ", ", 2); if (((yp_rest_parameter_node_t *)node)->name_loc.start == NULL) { yp_buffer_append_str(buffer, "nil", 3); } else { prettyprint_location(buffer, parser, &((yp_rest_parameter_node_t *)node)->name_loc); } + yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_rest_parameter_node_t *)node)->operator_loc); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_RETRY_NODE: { + case YP_RETRY_NODE: { yp_buffer_append_str(buffer, "RetryNode(", 10); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_RETURN_NODE: { + case YP_RETURN_NODE: { yp_buffer_append_str(buffer, "ReturnNode(", 11); prettyprint_location(buffer, parser, &((yp_return_node_t *)node)->keyword_loc); yp_buffer_append_str(buffer, ", ", 2); if (((yp_return_node_t *)node)->arguments == NULL) { @@ -1605,12 +1842,12 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_SELF_NODE: { + case YP_SELF_NODE: { yp_buffer_append_str(buffer, "SelfNode(", 9); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_SINGLETON_CLASS_NODE: { + case YP_SINGLETON_CLASS_NODE: { yp_buffer_append_str(buffer, "SingletonClassNode(", 19); yp_buffer_append_str(buffer, "[", 1); for (uint32_t index = 0; index < ((yp_singleton_class_node_t *)node)->locals.size; index++) { @@ -1632,12 +1869,12 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_SOURCE_ENCODING_NODE: { + case YP_SOURCE_ENCODING_NODE: { yp_buffer_append_str(buffer, "SourceEncodingNode(", 19); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_SOURCE_FILE_NODE: { + case YP_SOURCE_FILE_NODE: { yp_buffer_append_str(buffer, "SourceFileNode(", 15); yp_buffer_append_str(buffer, "\"", 1); yp_buffer_append_bytes(buffer, yp_string_source(&((yp_source_file_node_t *)node)->filepath), yp_string_length(&((yp_source_file_node_t *)node)->filepath)); @@ -1645,12 +1882,12 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_SOURCE_LINE_NODE: { + case YP_SOURCE_LINE_NODE: { yp_buffer_append_str(buffer, "SourceLineNode(", 15); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_SPLAT_NODE: { + case YP_SPLAT_NODE: { yp_buffer_append_str(buffer, "SplatNode(", 10); prettyprint_location(buffer, parser, &((yp_splat_node_t *)node)->operator_loc); yp_buffer_append_str(buffer, ", ", 2); if (((yp_splat_node_t *)node)->expression == NULL) { @@ -1661,7 +1898,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_STATEMENTS_NODE: { + case YP_STATEMENTS_NODE: { yp_buffer_append_str(buffer, "StatementsNode(", 15); yp_buffer_append_str(buffer, "[", 1); for (uint32_t index = 0; index < ((yp_statements_node_t *)node)->body.size; index++) { @@ -1672,16 +1909,19 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_STRING_CONCAT_NODE: { + case YP_STRING_CONCAT_NODE: { yp_buffer_append_str(buffer, "StringConcatNode(", 17); prettyprint_node(buffer, parser, (yp_node_t *)((yp_string_concat_node_t *)node)->left); yp_buffer_append_str(buffer, ", ", 2); prettyprint_node(buffer, parser, (yp_node_t *)((yp_string_concat_node_t *)node)->right); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_STRING_NODE: { + case YP_STRING_NODE: { yp_buffer_append_str(buffer, "StringNode(", 11); - if (((yp_string_node_t *)node)->opening_loc.start == NULL) { + char flags_buffer[12]; + snprintf(flags_buffer, sizeof(flags_buffer), "+%d", node->flags >> 2); + yp_buffer_append_str(buffer, flags_buffer, strlen(flags_buffer)); + yp_buffer_append_str(buffer, ", ", 2); if (((yp_string_node_t *)node)->opening_loc.start == NULL) { yp_buffer_append_str(buffer, "nil", 3); } else { prettyprint_location(buffer, parser, &((yp_string_node_t *)node)->opening_loc); @@ -1698,7 +1938,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_SUPER_NODE: { + case YP_SUPER_NODE: { yp_buffer_append_str(buffer, "SuperNode(", 10); prettyprint_location(buffer, parser, &((yp_super_node_t *)node)->keyword_loc); yp_buffer_append_str(buffer, ", ", 2); if (((yp_super_node_t *)node)->lparen_loc.start == NULL) { @@ -1724,7 +1964,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_SYMBOL_NODE: { + case YP_SYMBOL_NODE: { yp_buffer_append_str(buffer, "SymbolNode(", 11); if (((yp_symbol_node_t *)node)->opening_loc.start == NULL) { yp_buffer_append_str(buffer, "nil", 3); @@ -1747,12 +1987,12 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_TRUE_NODE: { + case YP_TRUE_NODE: { yp_buffer_append_str(buffer, "TrueNode(", 9); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_UNDEF_NODE: { + case YP_UNDEF_NODE: { yp_buffer_append_str(buffer, "UndefNode(", 10); yp_buffer_append_str(buffer, "[", 1); for (uint32_t index = 0; index < ((yp_undef_node_t *)node)->names.size; index++) { @@ -1764,7 +2004,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_UNLESS_NODE: { + case YP_UNLESS_NODE: { yp_buffer_append_str(buffer, "UnlessNode(", 11); prettyprint_location(buffer, parser, &((yp_unless_node_t *)node)->keyword_loc); yp_buffer_append_str(buffer, ", ", 2); prettyprint_node(buffer, parser, (yp_node_t *)((yp_unless_node_t *)node)->predicate); @@ -1786,7 +2026,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_UNTIL_NODE: { + case YP_UNTIL_NODE: { yp_buffer_append_str(buffer, "UntilNode(", 10); prettyprint_location(buffer, parser, &((yp_until_node_t *)node)->keyword_loc); yp_buffer_append_str(buffer, ", ", 2); if (((yp_until_node_t *)node)->closing_loc.start == NULL) { @@ -1801,12 +2041,12 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { prettyprint_node(buffer, parser, (yp_node_t *)((yp_until_node_t *)node)->statements); } yp_buffer_append_str(buffer, ", ", 2); char flags_buffer[12]; - snprintf(flags_buffer, sizeof(flags_buffer), "+%d", node->flags >> 1); + snprintf(flags_buffer, sizeof(flags_buffer), "+%d", node->flags >> 2); yp_buffer_append_str(buffer, flags_buffer, strlen(flags_buffer)); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_WHEN_NODE: { + case YP_WHEN_NODE: { yp_buffer_append_str(buffer, "WhenNode(", 9); prettyprint_location(buffer, parser, &((yp_when_node_t *)node)->keyword_loc); yp_buffer_append_str(buffer, ", ", 2); yp_buffer_append_str(buffer, "[", 1); @@ -1823,7 +2063,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_WHILE_NODE: { + case YP_WHILE_NODE: { yp_buffer_append_str(buffer, "WhileNode(", 10); prettyprint_location(buffer, parser, &((yp_while_node_t *)node)->keyword_loc); yp_buffer_append_str(buffer, ", ", 2); if (((yp_while_node_t *)node)->closing_loc.start == NULL) { @@ -1838,12 +2078,12 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { prettyprint_node(buffer, parser, (yp_node_t *)((yp_while_node_t *)node)->statements); } yp_buffer_append_str(buffer, ", ", 2); char flags_buffer[12]; - snprintf(flags_buffer, sizeof(flags_buffer), "+%d", node->flags >> 1); + snprintf(flags_buffer, sizeof(flags_buffer), "+%d", node->flags >> 2); yp_buffer_append_str(buffer, flags_buffer, strlen(flags_buffer)); yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_X_STRING_NODE: { + case YP_X_STRING_NODE: { yp_buffer_append_str(buffer, "XStringNode(", 12); prettyprint_location(buffer, parser, &((yp_x_string_node_t *)node)->opening_loc); yp_buffer_append_str(buffer, ", ", 2); prettyprint_location(buffer, parser, &((yp_x_string_node_t *)node)->content_loc); @@ -1854,7 +2094,7 @@ prettyprint_node(yp_buffer_t *buffer, yp_parser_t *parser, yp_node_t *node) { yp_buffer_append_str(buffer, ")", 1); break; } - case YP_NODE_YIELD_NODE: { + case YP_YIELD_NODE: { yp_buffer_append_str(buffer, "YieldNode(", 10); prettyprint_location(buffer, parser, &((yp_yield_node_t *)node)->keyword_loc); yp_buffer_append_str(buffer, ", ", 2); if (((yp_yield_node_t *)node)->lparen_loc.start == NULL) { diff --git a/src/main/c/yarp/src/serialize.c b/src/main/c/yarp/src/serialize.c index a83869f91c87..657447061b2a 100644 --- a/src/main/c/yarp/src/serialize.c +++ b/src/main/c/yarp/src/serialize.c @@ -65,27 +65,29 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { switch (YP_NODE_TYPE(node)) { // We do not need to serialize a ScopeNode ever as // it is not part of the AST - case YP_NODE_SCOPE_NODE: + case YP_SCOPE_NODE: return; - case YP_NODE_ALIAS_NODE: { - yp_serialize_node(parser, (yp_node_t *)((yp_alias_node_t *)node)->new_name, buffer); - yp_serialize_node(parser, (yp_node_t *)((yp_alias_node_t *)node)->old_name, buffer); - yp_serialize_location(parser, &((yp_alias_node_t *)node)->keyword_loc, buffer); + case YP_ALIAS_GLOBAL_VARIABLE_NODE: { + yp_serialize_node(parser, (yp_node_t *)((yp_alias_global_variable_node_t *)node)->new_name, buffer); + yp_serialize_node(parser, (yp_node_t *)((yp_alias_global_variable_node_t *)node)->old_name, buffer); break; } - case YP_NODE_ALTERNATION_PATTERN_NODE: { + case YP_ALIAS_METHOD_NODE: { + yp_serialize_node(parser, (yp_node_t *)((yp_alias_method_node_t *)node)->new_name, buffer); + yp_serialize_node(parser, (yp_node_t *)((yp_alias_method_node_t *)node)->old_name, buffer); + break; + } + case YP_ALTERNATION_PATTERN_NODE: { yp_serialize_node(parser, (yp_node_t *)((yp_alternation_pattern_node_t *)node)->left, buffer); yp_serialize_node(parser, (yp_node_t *)((yp_alternation_pattern_node_t *)node)->right, buffer); - yp_serialize_location(parser, &((yp_alternation_pattern_node_t *)node)->operator_loc, buffer); break; } - case YP_NODE_AND_NODE: { + case YP_AND_NODE: { yp_serialize_node(parser, (yp_node_t *)((yp_and_node_t *)node)->left, buffer); yp_serialize_node(parser, (yp_node_t *)((yp_and_node_t *)node)->right, buffer); - yp_serialize_location(parser, &((yp_and_node_t *)node)->operator_loc, buffer); break; } - case YP_NODE_ARGUMENTS_NODE: { + case YP_ARGUMENTS_NODE: { uint32_t arguments_size = yp_sizet_to_u32(((yp_arguments_node_t *)node)->arguments.size); yp_buffer_append_u32(buffer, arguments_size); for (uint32_t index = 0; index < arguments_size; index++) { @@ -93,27 +95,15 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { } break; } - case YP_NODE_ARRAY_NODE: { + case YP_ARRAY_NODE: { uint32_t elements_size = yp_sizet_to_u32(((yp_array_node_t *)node)->elements.size); yp_buffer_append_u32(buffer, elements_size); for (uint32_t index = 0; index < elements_size; index++) { yp_serialize_node(parser, (yp_node_t *) ((yp_array_node_t *)node)->elements.nodes[index], buffer); } - if (((yp_array_node_t *)node)->opening_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_array_node_t *)node)->opening_loc, buffer); - } - if (((yp_array_node_t *)node)->closing_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_array_node_t *)node)->closing_loc, buffer); - } break; } - case YP_NODE_ARRAY_PATTERN_NODE: { + case YP_ARRAY_PATTERN_NODE: { if (((yp_array_pattern_node_t *)node)->constant == NULL) { yp_buffer_append_u8(buffer, 0); } else { @@ -134,54 +124,29 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { for (uint32_t index = 0; index < posts_size; index++) { yp_serialize_node(parser, (yp_node_t *) ((yp_array_pattern_node_t *)node)->posts.nodes[index], buffer); } - if (((yp_array_pattern_node_t *)node)->opening_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_array_pattern_node_t *)node)->opening_loc, buffer); - } - if (((yp_array_pattern_node_t *)node)->closing_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_array_pattern_node_t *)node)->closing_loc, buffer); - } break; } - case YP_NODE_ASSOC_NODE: { + case YP_ASSOC_NODE: { yp_serialize_node(parser, (yp_node_t *)((yp_assoc_node_t *)node)->key, buffer); if (((yp_assoc_node_t *)node)->value == NULL) { yp_buffer_append_u8(buffer, 0); } else { yp_serialize_node(parser, (yp_node_t *)((yp_assoc_node_t *)node)->value, buffer); } - if (((yp_assoc_node_t *)node)->operator_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_assoc_node_t *)node)->operator_loc, buffer); - } break; } - case YP_NODE_ASSOC_SPLAT_NODE: { + case YP_ASSOC_SPLAT_NODE: { if (((yp_assoc_splat_node_t *)node)->value == NULL) { yp_buffer_append_u8(buffer, 0); } else { yp_serialize_node(parser, (yp_node_t *)((yp_assoc_splat_node_t *)node)->value, buffer); } - yp_serialize_location(parser, &((yp_assoc_splat_node_t *)node)->operator_loc, buffer); break; } - case YP_NODE_BACK_REFERENCE_READ_NODE: { + case YP_BACK_REFERENCE_READ_NODE: { break; } - case YP_NODE_BEGIN_NODE: { - if (((yp_begin_node_t *)node)->begin_keyword_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_begin_node_t *)node)->begin_keyword_loc, buffer); - } + case YP_BEGIN_NODE: { if (((yp_begin_node_t *)node)->statements == NULL) { yp_buffer_append_u8(buffer, 0); } else { @@ -202,24 +167,21 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { } else { yp_serialize_node(parser, (yp_node_t *)((yp_begin_node_t *)node)->ensure_clause, buffer); } - if (((yp_begin_node_t *)node)->end_keyword_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_begin_node_t *)node)->end_keyword_loc, buffer); - } break; } - case YP_NODE_BLOCK_ARGUMENT_NODE: { + case YP_BLOCK_ARGUMENT_NODE: { if (((yp_block_argument_node_t *)node)->expression == NULL) { yp_buffer_append_u8(buffer, 0); } else { yp_serialize_node(parser, (yp_node_t *)((yp_block_argument_node_t *)node)->expression, buffer); } - yp_serialize_location(parser, &((yp_block_argument_node_t *)node)->operator_loc, buffer); break; } - case YP_NODE_BLOCK_NODE: { + case YP_BLOCK_LOCAL_VARIABLE_NODE: { + yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_block_local_variable_node_t *)node)->name)); + break; + } + case YP_BLOCK_NODE: { uint32_t locals_size = yp_sizet_to_u32(((yp_block_node_t *)node)->locals.size); yp_buffer_append_u32(buffer, locals_size); for (uint32_t index = 0; index < locals_size; index++) { @@ -235,21 +197,13 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { } else { yp_serialize_node(parser, (yp_node_t *)((yp_block_node_t *)node)->body, buffer); } - yp_serialize_location(parser, &((yp_block_node_t *)node)->opening_loc, buffer); - yp_serialize_location(parser, &((yp_block_node_t *)node)->closing_loc, buffer); break; } - case YP_NODE_BLOCK_PARAMETER_NODE: { - if (((yp_block_parameter_node_t *)node)->name_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_block_parameter_node_t *)node)->name_loc, buffer); - } - yp_serialize_location(parser, &((yp_block_parameter_node_t *)node)->operator_loc, buffer); + case YP_BLOCK_PARAMETER_NODE: { + yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_block_parameter_node_t *)node)->name)); break; } - case YP_NODE_BLOCK_PARAMETERS_NODE: { + case YP_BLOCK_PARAMETERS_NODE: { if (((yp_block_parameters_node_t *)node)->parameters == NULL) { yp_buffer_append_u8(buffer, 0); } else { @@ -258,101 +212,96 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { uint32_t locals_size = yp_sizet_to_u32(((yp_block_parameters_node_t *)node)->locals.size); yp_buffer_append_u32(buffer, locals_size); for (uint32_t index = 0; index < locals_size; index++) { - yp_serialize_location(parser, &((yp_block_parameters_node_t *)node)->locals.locations[index], buffer); + yp_serialize_node(parser, (yp_node_t *) ((yp_block_parameters_node_t *)node)->locals.nodes[index], buffer); } - if (((yp_block_parameters_node_t *)node)->opening_loc.start == NULL) { + break; + } + case YP_BREAK_NODE: { + if (((yp_break_node_t *)node)->arguments == NULL) { yp_buffer_append_u8(buffer, 0); } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_block_parameters_node_t *)node)->opening_loc, buffer); + yp_serialize_node(parser, (yp_node_t *)((yp_break_node_t *)node)->arguments, buffer); } - if (((yp_block_parameters_node_t *)node)->closing_loc.start == NULL) { + break; + } + case YP_CALL_AND_WRITE_NODE: { + if (((yp_call_and_write_node_t *)node)->receiver == NULL) { yp_buffer_append_u8(buffer, 0); } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_block_parameters_node_t *)node)->closing_loc, buffer); + yp_serialize_node(parser, (yp_node_t *)((yp_call_and_write_node_t *)node)->receiver, buffer); } - break; - } - case YP_NODE_BREAK_NODE: { - if (((yp_break_node_t *)node)->arguments == NULL) { + if (((yp_call_and_write_node_t *)node)->arguments == NULL) { yp_buffer_append_u8(buffer, 0); } else { - yp_serialize_node(parser, (yp_node_t *)((yp_break_node_t *)node)->arguments, buffer); + yp_serialize_node(parser, (yp_node_t *)((yp_call_and_write_node_t *)node)->arguments, buffer); } - yp_serialize_location(parser, &((yp_break_node_t *)node)->keyword_loc, buffer); + yp_buffer_append_u32(buffer, node->flags >> 2); + yp_serialize_string(parser, &((yp_call_and_write_node_t *)node)->read_name, buffer); + yp_serialize_string(parser, &((yp_call_and_write_node_t *)node)->write_name, buffer); + yp_serialize_node(parser, (yp_node_t *)((yp_call_and_write_node_t *)node)->value, buffer); break; } - case YP_NODE_CALL_NODE: { + case YP_CALL_NODE: { if (((yp_call_node_t *)node)->receiver == NULL) { yp_buffer_append_u8(buffer, 0); } else { yp_serialize_node(parser, (yp_node_t *)((yp_call_node_t *)node)->receiver, buffer); } - if (((yp_call_node_t *)node)->operator_loc.start == NULL) { + if (((yp_call_node_t *)node)->arguments == NULL) { yp_buffer_append_u8(buffer, 0); } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_call_node_t *)node)->operator_loc, buffer); + yp_serialize_node(parser, (yp_node_t *)((yp_call_node_t *)node)->arguments, buffer); } - if (((yp_call_node_t *)node)->message_loc.start == NULL) { + if (((yp_call_node_t *)node)->block == NULL) { yp_buffer_append_u8(buffer, 0); } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_call_node_t *)node)->message_loc, buffer); + yp_serialize_node(parser, (yp_node_t *)((yp_call_node_t *)node)->block, buffer); } - if (((yp_call_node_t *)node)->opening_loc.start == NULL) { + yp_buffer_append_u32(buffer, node->flags >> 2); + yp_serialize_string(parser, &((yp_call_node_t *)node)->name, buffer); + break; + } + case YP_CALL_OPERATOR_WRITE_NODE: { + if (((yp_call_operator_write_node_t *)node)->receiver == NULL) { yp_buffer_append_u8(buffer, 0); } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_call_node_t *)node)->opening_loc, buffer); + yp_serialize_node(parser, (yp_node_t *)((yp_call_operator_write_node_t *)node)->receiver, buffer); } - if (((yp_call_node_t *)node)->arguments == NULL) { + if (((yp_call_operator_write_node_t *)node)->arguments == NULL) { yp_buffer_append_u8(buffer, 0); } else { - yp_serialize_node(parser, (yp_node_t *)((yp_call_node_t *)node)->arguments, buffer); + yp_serialize_node(parser, (yp_node_t *)((yp_call_operator_write_node_t *)node)->arguments, buffer); } - if (((yp_call_node_t *)node)->closing_loc.start == NULL) { + yp_buffer_append_u32(buffer, node->flags >> 2); + yp_serialize_string(parser, &((yp_call_operator_write_node_t *)node)->read_name, buffer); + yp_serialize_string(parser, &((yp_call_operator_write_node_t *)node)->write_name, buffer); + yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_call_operator_write_node_t *)node)->operator)); + yp_serialize_node(parser, (yp_node_t *)((yp_call_operator_write_node_t *)node)->value, buffer); + break; + } + case YP_CALL_OR_WRITE_NODE: { + if (((yp_call_or_write_node_t *)node)->receiver == NULL) { yp_buffer_append_u8(buffer, 0); } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_call_node_t *)node)->closing_loc, buffer); + yp_serialize_node(parser, (yp_node_t *)((yp_call_or_write_node_t *)node)->receiver, buffer); } - if (((yp_call_node_t *)node)->block == NULL) { + if (((yp_call_or_write_node_t *)node)->arguments == NULL) { yp_buffer_append_u8(buffer, 0); } else { - yp_serialize_node(parser, (yp_node_t *)((yp_call_node_t *)node)->block, buffer); + yp_serialize_node(parser, (yp_node_t *)((yp_call_or_write_node_t *)node)->arguments, buffer); } - yp_buffer_append_u32(buffer, node->flags >> 1); - yp_serialize_string(parser, &((yp_call_node_t *)node)->name, buffer); + yp_buffer_append_u32(buffer, node->flags >> 2); + yp_serialize_string(parser, &((yp_call_or_write_node_t *)node)->read_name, buffer); + yp_serialize_string(parser, &((yp_call_or_write_node_t *)node)->write_name, buffer); + yp_serialize_node(parser, (yp_node_t *)((yp_call_or_write_node_t *)node)->value, buffer); break; } - case YP_NODE_CALL_OPERATOR_AND_WRITE_NODE: { - yp_serialize_node(parser, (yp_node_t *)((yp_call_operator_and_write_node_t *)node)->target, buffer); - yp_serialize_location(parser, &((yp_call_operator_and_write_node_t *)node)->operator_loc, buffer); - yp_serialize_node(parser, (yp_node_t *)((yp_call_operator_and_write_node_t *)node)->value, buffer); - break; - } - case YP_NODE_CALL_OPERATOR_OR_WRITE_NODE: { - yp_serialize_node(parser, (yp_node_t *)((yp_call_operator_or_write_node_t *)node)->target, buffer); - yp_serialize_node(parser, (yp_node_t *)((yp_call_operator_or_write_node_t *)node)->value, buffer); - yp_serialize_location(parser, &((yp_call_operator_or_write_node_t *)node)->operator_loc, buffer); - break; - } - case YP_NODE_CALL_OPERATOR_WRITE_NODE: { - yp_serialize_node(parser, (yp_node_t *)((yp_call_operator_write_node_t *)node)->target, buffer); - yp_serialize_location(parser, &((yp_call_operator_write_node_t *)node)->operator_loc, buffer); - yp_serialize_node(parser, (yp_node_t *)((yp_call_operator_write_node_t *)node)->value, buffer); - yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_call_operator_write_node_t *)node)->operator)); - break; - } - case YP_NODE_CAPTURE_PATTERN_NODE: { + case YP_CAPTURE_PATTERN_NODE: { yp_serialize_node(parser, (yp_node_t *)((yp_capture_pattern_node_t *)node)->value, buffer); yp_serialize_node(parser, (yp_node_t *)((yp_capture_pattern_node_t *)node)->target, buffer); - yp_serialize_location(parser, &((yp_capture_pattern_node_t *)node)->operator_loc, buffer); break; } - case YP_NODE_CASE_NODE: { + case YP_CASE_NODE: { if (((yp_case_node_t *)node)->predicate == NULL) { yp_buffer_append_u8(buffer, 0); } else { @@ -368,24 +317,15 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { } else { yp_serialize_node(parser, (yp_node_t *)((yp_case_node_t *)node)->consequent, buffer); } - yp_serialize_location(parser, &((yp_case_node_t *)node)->case_keyword_loc, buffer); - yp_serialize_location(parser, &((yp_case_node_t *)node)->end_keyword_loc, buffer); break; } - case YP_NODE_CLASS_NODE: { + case YP_CLASS_NODE: { uint32_t locals_size = yp_sizet_to_u32(((yp_class_node_t *)node)->locals.size); yp_buffer_append_u32(buffer, locals_size); for (uint32_t index = 0; index < locals_size; index++) { yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_class_node_t *)node)->locals.ids[index])); } - yp_serialize_location(parser, &((yp_class_node_t *)node)->class_keyword_loc, buffer); yp_serialize_node(parser, (yp_node_t *)((yp_class_node_t *)node)->constant_path, buffer); - if (((yp_class_node_t *)node)->inheritance_operator_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_class_node_t *)node)->inheritance_operator_loc, buffer); - } if (((yp_class_node_t *)node)->superclass == NULL) { yp_buffer_append_u8(buffer, 0); } else { @@ -396,138 +336,112 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { } else { yp_serialize_node(parser, (yp_node_t *)((yp_class_node_t *)node)->body, buffer); } - yp_serialize_location(parser, &((yp_class_node_t *)node)->end_keyword_loc, buffer); - yp_serialize_string(parser, &((yp_class_node_t *)node)->name, buffer); + yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_class_node_t *)node)->name)); break; } - case YP_NODE_CLASS_VARIABLE_AND_WRITE_NODE: { + case YP_CLASS_VARIABLE_AND_WRITE_NODE: { yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_class_variable_and_write_node_t *)node)->name)); - yp_serialize_location(parser, &((yp_class_variable_and_write_node_t *)node)->name_loc, buffer); - yp_serialize_location(parser, &((yp_class_variable_and_write_node_t *)node)->operator_loc, buffer); yp_serialize_node(parser, (yp_node_t *)((yp_class_variable_and_write_node_t *)node)->value, buffer); break; } - case YP_NODE_CLASS_VARIABLE_OPERATOR_WRITE_NODE: { + case YP_CLASS_VARIABLE_OPERATOR_WRITE_NODE: { yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_class_variable_operator_write_node_t *)node)->name)); - yp_serialize_location(parser, &((yp_class_variable_operator_write_node_t *)node)->name_loc, buffer); - yp_serialize_location(parser, &((yp_class_variable_operator_write_node_t *)node)->operator_loc, buffer); yp_serialize_node(parser, (yp_node_t *)((yp_class_variable_operator_write_node_t *)node)->value, buffer); yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_class_variable_operator_write_node_t *)node)->operator)); break; } - case YP_NODE_CLASS_VARIABLE_OR_WRITE_NODE: { + case YP_CLASS_VARIABLE_OR_WRITE_NODE: { yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_class_variable_or_write_node_t *)node)->name)); - yp_serialize_location(parser, &((yp_class_variable_or_write_node_t *)node)->name_loc, buffer); - yp_serialize_location(parser, &((yp_class_variable_or_write_node_t *)node)->operator_loc, buffer); yp_serialize_node(parser, (yp_node_t *)((yp_class_variable_or_write_node_t *)node)->value, buffer); break; } - case YP_NODE_CLASS_VARIABLE_READ_NODE: { + case YP_CLASS_VARIABLE_READ_NODE: { yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_class_variable_read_node_t *)node)->name)); break; } - case YP_NODE_CLASS_VARIABLE_TARGET_NODE: { + case YP_CLASS_VARIABLE_TARGET_NODE: { yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_class_variable_target_node_t *)node)->name)); break; } - case YP_NODE_CLASS_VARIABLE_WRITE_NODE: { + case YP_CLASS_VARIABLE_WRITE_NODE: { yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_class_variable_write_node_t *)node)->name)); - yp_serialize_location(parser, &((yp_class_variable_write_node_t *)node)->name_loc, buffer); - if (((yp_class_variable_write_node_t *)node)->value == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_serialize_node(parser, (yp_node_t *)((yp_class_variable_write_node_t *)node)->value, buffer); - } - if (((yp_class_variable_write_node_t *)node)->operator_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_class_variable_write_node_t *)node)->operator_loc, buffer); - } + yp_serialize_node(parser, (yp_node_t *)((yp_class_variable_write_node_t *)node)->value, buffer); break; } - case YP_NODE_CONSTANT_AND_WRITE_NODE: { - yp_serialize_location(parser, &((yp_constant_and_write_node_t *)node)->name_loc, buffer); - yp_serialize_location(parser, &((yp_constant_and_write_node_t *)node)->operator_loc, buffer); + case YP_CONSTANT_AND_WRITE_NODE: { + yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_constant_and_write_node_t *)node)->name)); yp_serialize_node(parser, (yp_node_t *)((yp_constant_and_write_node_t *)node)->value, buffer); break; } - case YP_NODE_CONSTANT_OPERATOR_WRITE_NODE: { - yp_serialize_location(parser, &((yp_constant_operator_write_node_t *)node)->name_loc, buffer); - yp_serialize_location(parser, &((yp_constant_operator_write_node_t *)node)->operator_loc, buffer); + case YP_CONSTANT_OPERATOR_WRITE_NODE: { + yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_constant_operator_write_node_t *)node)->name)); yp_serialize_node(parser, (yp_node_t *)((yp_constant_operator_write_node_t *)node)->value, buffer); yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_constant_operator_write_node_t *)node)->operator)); break; } - case YP_NODE_CONSTANT_OR_WRITE_NODE: { - yp_serialize_location(parser, &((yp_constant_or_write_node_t *)node)->name_loc, buffer); - yp_serialize_location(parser, &((yp_constant_or_write_node_t *)node)->operator_loc, buffer); + case YP_CONSTANT_OR_WRITE_NODE: { + yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_constant_or_write_node_t *)node)->name)); yp_serialize_node(parser, (yp_node_t *)((yp_constant_or_write_node_t *)node)->value, buffer); break; } - case YP_NODE_CONSTANT_PATH_AND_WRITE_NODE: { + case YP_CONSTANT_PATH_AND_WRITE_NODE: { yp_serialize_node(parser, (yp_node_t *)((yp_constant_path_and_write_node_t *)node)->target, buffer); - yp_serialize_location(parser, &((yp_constant_path_and_write_node_t *)node)->operator_loc, buffer); yp_serialize_node(parser, (yp_node_t *)((yp_constant_path_and_write_node_t *)node)->value, buffer); break; } - case YP_NODE_CONSTANT_PATH_NODE: { + case YP_CONSTANT_PATH_NODE: { if (((yp_constant_path_node_t *)node)->parent == NULL) { yp_buffer_append_u8(buffer, 0); } else { yp_serialize_node(parser, (yp_node_t *)((yp_constant_path_node_t *)node)->parent, buffer); } yp_serialize_node(parser, (yp_node_t *)((yp_constant_path_node_t *)node)->child, buffer); - yp_serialize_location(parser, &((yp_constant_path_node_t *)node)->delimiter_loc, buffer); break; } - case YP_NODE_CONSTANT_PATH_OPERATOR_WRITE_NODE: { + case YP_CONSTANT_PATH_OPERATOR_WRITE_NODE: { yp_serialize_node(parser, (yp_node_t *)((yp_constant_path_operator_write_node_t *)node)->target, buffer); - yp_serialize_location(parser, &((yp_constant_path_operator_write_node_t *)node)->operator_loc, buffer); yp_serialize_node(parser, (yp_node_t *)((yp_constant_path_operator_write_node_t *)node)->value, buffer); yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_constant_path_operator_write_node_t *)node)->operator)); break; } - case YP_NODE_CONSTANT_PATH_OR_WRITE_NODE: { + case YP_CONSTANT_PATH_OR_WRITE_NODE: { yp_serialize_node(parser, (yp_node_t *)((yp_constant_path_or_write_node_t *)node)->target, buffer); - yp_serialize_location(parser, &((yp_constant_path_or_write_node_t *)node)->operator_loc, buffer); yp_serialize_node(parser, (yp_node_t *)((yp_constant_path_or_write_node_t *)node)->value, buffer); break; } - case YP_NODE_CONSTANT_PATH_TARGET_NODE: { + case YP_CONSTANT_PATH_TARGET_NODE: { if (((yp_constant_path_target_node_t *)node)->parent == NULL) { yp_buffer_append_u8(buffer, 0); } else { yp_serialize_node(parser, (yp_node_t *)((yp_constant_path_target_node_t *)node)->parent, buffer); } yp_serialize_node(parser, (yp_node_t *)((yp_constant_path_target_node_t *)node)->child, buffer); - yp_serialize_location(parser, &((yp_constant_path_target_node_t *)node)->delimiter_loc, buffer); break; } - case YP_NODE_CONSTANT_PATH_WRITE_NODE: { + case YP_CONSTANT_PATH_WRITE_NODE: { yp_serialize_node(parser, (yp_node_t *)((yp_constant_path_write_node_t *)node)->target, buffer); - yp_serialize_location(parser, &((yp_constant_path_write_node_t *)node)->operator_loc, buffer); yp_serialize_node(parser, (yp_node_t *)((yp_constant_path_write_node_t *)node)->value, buffer); break; } - case YP_NODE_CONSTANT_READ_NODE: { + case YP_CONSTANT_READ_NODE: { + yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_constant_read_node_t *)node)->name)); break; } - case YP_NODE_CONSTANT_TARGET_NODE: { + case YP_CONSTANT_TARGET_NODE: { + yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_constant_target_node_t *)node)->name)); break; } - case YP_NODE_CONSTANT_WRITE_NODE: { - yp_serialize_location(parser, &((yp_constant_write_node_t *)node)->name_loc, buffer); + case YP_CONSTANT_WRITE_NODE: { + yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_constant_write_node_t *)node)->name)); yp_serialize_node(parser, (yp_node_t *)((yp_constant_write_node_t *)node)->value, buffer); - yp_serialize_location(parser, &((yp_constant_write_node_t *)node)->operator_loc, buffer); break; } - case YP_NODE_DEF_NODE: { + case YP_DEF_NODE: { // serialize length // encoding of location u32s make us need to save this offset. size_t length_offset = buffer->length; yp_buffer_append_str(buffer, "\0\0\0\0", 4); /* consume 4 bytes, updated below */ - yp_serialize_location(parser, &((yp_def_node_t *)node)->name_loc, buffer); + yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_def_node_t *)node)->name)); if (((yp_def_node_t *)node)->receiver == NULL) { yp_buffer_append_u8(buffer, 0); } else { @@ -548,103 +462,47 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { for (uint32_t index = 0; index < locals_size; index++) { yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_def_node_t *)node)->locals.ids[index])); } - yp_serialize_location(parser, &((yp_def_node_t *)node)->def_keyword_loc, buffer); - if (((yp_def_node_t *)node)->operator_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_def_node_t *)node)->operator_loc, buffer); - } - if (((yp_def_node_t *)node)->lparen_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_def_node_t *)node)->lparen_loc, buffer); - } - if (((yp_def_node_t *)node)->rparen_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_def_node_t *)node)->rparen_loc, buffer); - } - if (((yp_def_node_t *)node)->equal_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_def_node_t *)node)->equal_loc, buffer); - } - if (((yp_def_node_t *)node)->end_keyword_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_def_node_t *)node)->end_keyword_loc, buffer); - } // serialize length uint32_t length = yp_sizet_to_u32(buffer->length - offset - sizeof(uint32_t)); memcpy(buffer->value + length_offset, &length, sizeof(uint32_t)); break; } - case YP_NODE_DEFINED_NODE: { - if (((yp_defined_node_t *)node)->lparen_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_defined_node_t *)node)->lparen_loc, buffer); - } + case YP_DEFINED_NODE: { yp_serialize_node(parser, (yp_node_t *)((yp_defined_node_t *)node)->value, buffer); - if (((yp_defined_node_t *)node)->rparen_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_defined_node_t *)node)->rparen_loc, buffer); - } - yp_serialize_location(parser, &((yp_defined_node_t *)node)->keyword_loc, buffer); break; } - case YP_NODE_ELSE_NODE: { - yp_serialize_location(parser, &((yp_else_node_t *)node)->else_keyword_loc, buffer); + case YP_ELSE_NODE: { if (((yp_else_node_t *)node)->statements == NULL) { yp_buffer_append_u8(buffer, 0); } else { yp_serialize_node(parser, (yp_node_t *)((yp_else_node_t *)node)->statements, buffer); } - if (((yp_else_node_t *)node)->end_keyword_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_else_node_t *)node)->end_keyword_loc, buffer); - } break; } - case YP_NODE_EMBEDDED_STATEMENTS_NODE: { - yp_serialize_location(parser, &((yp_embedded_statements_node_t *)node)->opening_loc, buffer); + case YP_EMBEDDED_STATEMENTS_NODE: { if (((yp_embedded_statements_node_t *)node)->statements == NULL) { yp_buffer_append_u8(buffer, 0); } else { yp_serialize_node(parser, (yp_node_t *)((yp_embedded_statements_node_t *)node)->statements, buffer); } - yp_serialize_location(parser, &((yp_embedded_statements_node_t *)node)->closing_loc, buffer); break; } - case YP_NODE_EMBEDDED_VARIABLE_NODE: { - yp_serialize_location(parser, &((yp_embedded_variable_node_t *)node)->operator_loc, buffer); + case YP_EMBEDDED_VARIABLE_NODE: { yp_serialize_node(parser, (yp_node_t *)((yp_embedded_variable_node_t *)node)->variable, buffer); break; } - case YP_NODE_ENSURE_NODE: { - yp_serialize_location(parser, &((yp_ensure_node_t *)node)->ensure_keyword_loc, buffer); + case YP_ENSURE_NODE: { if (((yp_ensure_node_t *)node)->statements == NULL) { yp_buffer_append_u8(buffer, 0); } else { yp_serialize_node(parser, (yp_node_t *)((yp_ensure_node_t *)node)->statements, buffer); } - yp_serialize_location(parser, &((yp_ensure_node_t *)node)->end_keyword_loc, buffer); break; } - case YP_NODE_FALSE_NODE: { + case YP_FALSE_NODE: { break; } - case YP_NODE_FIND_PATTERN_NODE: { + case YP_FIND_PATTERN_NODE: { if (((yp_find_pattern_node_t *)node)->constant == NULL) { yp_buffer_append_u8(buffer, 0); } else { @@ -657,21 +515,9 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { yp_serialize_node(parser, (yp_node_t *) ((yp_find_pattern_node_t *)node)->requireds.nodes[index], buffer); } yp_serialize_node(parser, (yp_node_t *)((yp_find_pattern_node_t *)node)->right, buffer); - if (((yp_find_pattern_node_t *)node)->opening_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_find_pattern_node_t *)node)->opening_loc, buffer); - } - if (((yp_find_pattern_node_t *)node)->closing_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_find_pattern_node_t *)node)->closing_loc, buffer); - } break; } - case YP_NODE_FLIP_FLOP_NODE: { + case YP_FLIP_FLOP_NODE: { if (((yp_flip_flop_node_t *)node)->left == NULL) { yp_buffer_append_u8(buffer, 0); } else { @@ -682,14 +528,13 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { } else { yp_serialize_node(parser, (yp_node_t *)((yp_flip_flop_node_t *)node)->right, buffer); } - yp_serialize_location(parser, &((yp_flip_flop_node_t *)node)->operator_loc, buffer); - yp_buffer_append_u32(buffer, node->flags >> 1); + yp_buffer_append_u32(buffer, node->flags >> 2); break; } - case YP_NODE_FLOAT_NODE: { + case YP_FLOAT_NODE: { break; } - case YP_NODE_FOR_NODE: { + case YP_FOR_NODE: { yp_serialize_node(parser, (yp_node_t *)((yp_for_node_t *)node)->index, buffer); yp_serialize_node(parser, (yp_node_t *)((yp_for_node_t *)node)->collection, buffer); if (((yp_for_node_t *)node)->statements == NULL) { @@ -697,24 +542,15 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { } else { yp_serialize_node(parser, (yp_node_t *)((yp_for_node_t *)node)->statements, buffer); } - yp_serialize_location(parser, &((yp_for_node_t *)node)->for_keyword_loc, buffer); - yp_serialize_location(parser, &((yp_for_node_t *)node)->in_keyword_loc, buffer); - if (((yp_for_node_t *)node)->do_keyword_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_for_node_t *)node)->do_keyword_loc, buffer); - } - yp_serialize_location(parser, &((yp_for_node_t *)node)->end_keyword_loc, buffer); break; } - case YP_NODE_FORWARDING_ARGUMENTS_NODE: { + case YP_FORWARDING_ARGUMENTS_NODE: { break; } - case YP_NODE_FORWARDING_PARAMETER_NODE: { + case YP_FORWARDING_PARAMETER_NODE: { break; } - case YP_NODE_FORWARDING_SUPER_NODE: { + case YP_FORWARDING_SUPER_NODE: { if (((yp_forwarding_super_node_t *)node)->block == NULL) { yp_buffer_append_u8(buffer, 0); } else { @@ -722,54 +558,44 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { } break; } - case YP_NODE_GLOBAL_VARIABLE_AND_WRITE_NODE: { + case YP_GLOBAL_VARIABLE_AND_WRITE_NODE: { yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_global_variable_and_write_node_t *)node)->name)); - yp_serialize_location(parser, &((yp_global_variable_and_write_node_t *)node)->name_loc, buffer); - yp_serialize_location(parser, &((yp_global_variable_and_write_node_t *)node)->operator_loc, buffer); yp_serialize_node(parser, (yp_node_t *)((yp_global_variable_and_write_node_t *)node)->value, buffer); break; } - case YP_NODE_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE: { + case YP_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE: { yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_global_variable_operator_write_node_t *)node)->name)); - yp_serialize_location(parser, &((yp_global_variable_operator_write_node_t *)node)->name_loc, buffer); - yp_serialize_location(parser, &((yp_global_variable_operator_write_node_t *)node)->operator_loc, buffer); yp_serialize_node(parser, (yp_node_t *)((yp_global_variable_operator_write_node_t *)node)->value, buffer); yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_global_variable_operator_write_node_t *)node)->operator)); break; } - case YP_NODE_GLOBAL_VARIABLE_OR_WRITE_NODE: { + case YP_GLOBAL_VARIABLE_OR_WRITE_NODE: { yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_global_variable_or_write_node_t *)node)->name)); - yp_serialize_location(parser, &((yp_global_variable_or_write_node_t *)node)->name_loc, buffer); - yp_serialize_location(parser, &((yp_global_variable_or_write_node_t *)node)->operator_loc, buffer); yp_serialize_node(parser, (yp_node_t *)((yp_global_variable_or_write_node_t *)node)->value, buffer); break; } - case YP_NODE_GLOBAL_VARIABLE_READ_NODE: { + case YP_GLOBAL_VARIABLE_READ_NODE: { yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_global_variable_read_node_t *)node)->name)); break; } - case YP_NODE_GLOBAL_VARIABLE_TARGET_NODE: { + case YP_GLOBAL_VARIABLE_TARGET_NODE: { yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_global_variable_target_node_t *)node)->name)); break; } - case YP_NODE_GLOBAL_VARIABLE_WRITE_NODE: { + case YP_GLOBAL_VARIABLE_WRITE_NODE: { yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_global_variable_write_node_t *)node)->name)); - yp_serialize_location(parser, &((yp_global_variable_write_node_t *)node)->name_loc, buffer); yp_serialize_node(parser, (yp_node_t *)((yp_global_variable_write_node_t *)node)->value, buffer); - yp_serialize_location(parser, &((yp_global_variable_write_node_t *)node)->operator_loc, buffer); break; } - case YP_NODE_HASH_NODE: { - yp_serialize_location(parser, &((yp_hash_node_t *)node)->opening_loc, buffer); + case YP_HASH_NODE: { uint32_t elements_size = yp_sizet_to_u32(((yp_hash_node_t *)node)->elements.size); yp_buffer_append_u32(buffer, elements_size); for (uint32_t index = 0; index < elements_size; index++) { yp_serialize_node(parser, (yp_node_t *) ((yp_hash_node_t *)node)->elements.nodes[index], buffer); } - yp_serialize_location(parser, &((yp_hash_node_t *)node)->closing_loc, buffer); break; } - case YP_NODE_HASH_PATTERN_NODE: { + case YP_HASH_PATTERN_NODE: { if (((yp_hash_pattern_node_t *)node)->constant == NULL) { yp_buffer_append_u8(buffer, 0); } else { @@ -785,27 +611,9 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { } else { yp_serialize_node(parser, (yp_node_t *)((yp_hash_pattern_node_t *)node)->kwrest, buffer); } - if (((yp_hash_pattern_node_t *)node)->opening_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_hash_pattern_node_t *)node)->opening_loc, buffer); - } - if (((yp_hash_pattern_node_t *)node)->closing_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_hash_pattern_node_t *)node)->closing_loc, buffer); - } break; } - case YP_NODE_IF_NODE: { - if (((yp_if_node_t *)node)->if_keyword_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_if_node_t *)node)->if_keyword_loc, buffer); - } + case YP_IF_NODE: { yp_serialize_node(parser, (yp_node_t *)((yp_if_node_t *)node)->predicate, buffer); if (((yp_if_node_t *)node)->statements == NULL) { yp_buffer_append_u8(buffer, 0); @@ -817,136 +625,101 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { } else { yp_serialize_node(parser, (yp_node_t *)((yp_if_node_t *)node)->consequent, buffer); } - if (((yp_if_node_t *)node)->end_keyword_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_if_node_t *)node)->end_keyword_loc, buffer); - } break; } - case YP_NODE_IMAGINARY_NODE: { + case YP_IMAGINARY_NODE: { yp_serialize_node(parser, (yp_node_t *)((yp_imaginary_node_t *)node)->numeric, buffer); break; } - case YP_NODE_IN_NODE: { + case YP_IMPLICIT_NODE: { + yp_serialize_node(parser, (yp_node_t *)((yp_implicit_node_t *)node)->value, buffer); + break; + } + case YP_IN_NODE: { yp_serialize_node(parser, (yp_node_t *)((yp_in_node_t *)node)->pattern, buffer); if (((yp_in_node_t *)node)->statements == NULL) { yp_buffer_append_u8(buffer, 0); } else { yp_serialize_node(parser, (yp_node_t *)((yp_in_node_t *)node)->statements, buffer); } - yp_serialize_location(parser, &((yp_in_node_t *)node)->in_loc, buffer); - if (((yp_in_node_t *)node)->then_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_in_node_t *)node)->then_loc, buffer); - } break; } - case YP_NODE_INSTANCE_VARIABLE_AND_WRITE_NODE: { + case YP_INSTANCE_VARIABLE_AND_WRITE_NODE: { yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_instance_variable_and_write_node_t *)node)->name)); - yp_serialize_location(parser, &((yp_instance_variable_and_write_node_t *)node)->name_loc, buffer); - yp_serialize_location(parser, &((yp_instance_variable_and_write_node_t *)node)->operator_loc, buffer); yp_serialize_node(parser, (yp_node_t *)((yp_instance_variable_and_write_node_t *)node)->value, buffer); break; } - case YP_NODE_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE: { + case YP_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE: { yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_instance_variable_operator_write_node_t *)node)->name)); - yp_serialize_location(parser, &((yp_instance_variable_operator_write_node_t *)node)->name_loc, buffer); - yp_serialize_location(parser, &((yp_instance_variable_operator_write_node_t *)node)->operator_loc, buffer); yp_serialize_node(parser, (yp_node_t *)((yp_instance_variable_operator_write_node_t *)node)->value, buffer); yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_instance_variable_operator_write_node_t *)node)->operator)); break; } - case YP_NODE_INSTANCE_VARIABLE_OR_WRITE_NODE: { + case YP_INSTANCE_VARIABLE_OR_WRITE_NODE: { yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_instance_variable_or_write_node_t *)node)->name)); - yp_serialize_location(parser, &((yp_instance_variable_or_write_node_t *)node)->name_loc, buffer); - yp_serialize_location(parser, &((yp_instance_variable_or_write_node_t *)node)->operator_loc, buffer); yp_serialize_node(parser, (yp_node_t *)((yp_instance_variable_or_write_node_t *)node)->value, buffer); break; } - case YP_NODE_INSTANCE_VARIABLE_READ_NODE: { + case YP_INSTANCE_VARIABLE_READ_NODE: { yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_instance_variable_read_node_t *)node)->name)); break; } - case YP_NODE_INSTANCE_VARIABLE_TARGET_NODE: { + case YP_INSTANCE_VARIABLE_TARGET_NODE: { yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_instance_variable_target_node_t *)node)->name)); break; } - case YP_NODE_INSTANCE_VARIABLE_WRITE_NODE: { + case YP_INSTANCE_VARIABLE_WRITE_NODE: { yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_instance_variable_write_node_t *)node)->name)); - yp_serialize_location(parser, &((yp_instance_variable_write_node_t *)node)->name_loc, buffer); yp_serialize_node(parser, (yp_node_t *)((yp_instance_variable_write_node_t *)node)->value, buffer); - yp_serialize_location(parser, &((yp_instance_variable_write_node_t *)node)->operator_loc, buffer); break; } - case YP_NODE_INTEGER_NODE: { + case YP_INTEGER_NODE: { + yp_buffer_append_u32(buffer, node->flags >> 2); + break; + } + case YP_INTERPOLATED_MATCH_LAST_LINE_NODE: { + uint32_t parts_size = yp_sizet_to_u32(((yp_interpolated_match_last_line_node_t *)node)->parts.size); + yp_buffer_append_u32(buffer, parts_size); + for (uint32_t index = 0; index < parts_size; index++) { + yp_serialize_node(parser, (yp_node_t *) ((yp_interpolated_match_last_line_node_t *)node)->parts.nodes[index], buffer); + } + yp_buffer_append_u32(buffer, node->flags >> 2); break; } - case YP_NODE_INTERPOLATED_REGULAR_EXPRESSION_NODE: { - yp_serialize_location(parser, &((yp_interpolated_regular_expression_node_t *)node)->opening_loc, buffer); + case YP_INTERPOLATED_REGULAR_EXPRESSION_NODE: { uint32_t parts_size = yp_sizet_to_u32(((yp_interpolated_regular_expression_node_t *)node)->parts.size); yp_buffer_append_u32(buffer, parts_size); for (uint32_t index = 0; index < parts_size; index++) { yp_serialize_node(parser, (yp_node_t *) ((yp_interpolated_regular_expression_node_t *)node)->parts.nodes[index], buffer); } - yp_serialize_location(parser, &((yp_interpolated_regular_expression_node_t *)node)->closing_loc, buffer); - yp_buffer_append_u32(buffer, node->flags >> 1); + yp_buffer_append_u32(buffer, node->flags >> 2); break; } - case YP_NODE_INTERPOLATED_STRING_NODE: { - if (((yp_interpolated_string_node_t *)node)->opening_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_interpolated_string_node_t *)node)->opening_loc, buffer); - } + case YP_INTERPOLATED_STRING_NODE: { uint32_t parts_size = yp_sizet_to_u32(((yp_interpolated_string_node_t *)node)->parts.size); yp_buffer_append_u32(buffer, parts_size); for (uint32_t index = 0; index < parts_size; index++) { yp_serialize_node(parser, (yp_node_t *) ((yp_interpolated_string_node_t *)node)->parts.nodes[index], buffer); } - if (((yp_interpolated_string_node_t *)node)->closing_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_interpolated_string_node_t *)node)->closing_loc, buffer); - } break; } - case YP_NODE_INTERPOLATED_SYMBOL_NODE: { - if (((yp_interpolated_symbol_node_t *)node)->opening_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_interpolated_symbol_node_t *)node)->opening_loc, buffer); - } + case YP_INTERPOLATED_SYMBOL_NODE: { uint32_t parts_size = yp_sizet_to_u32(((yp_interpolated_symbol_node_t *)node)->parts.size); yp_buffer_append_u32(buffer, parts_size); for (uint32_t index = 0; index < parts_size; index++) { yp_serialize_node(parser, (yp_node_t *) ((yp_interpolated_symbol_node_t *)node)->parts.nodes[index], buffer); } - if (((yp_interpolated_symbol_node_t *)node)->closing_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_interpolated_symbol_node_t *)node)->closing_loc, buffer); - } break; } - case YP_NODE_INTERPOLATED_X_STRING_NODE: { - yp_serialize_location(parser, &((yp_interpolated_x_string_node_t *)node)->opening_loc, buffer); + case YP_INTERPOLATED_X_STRING_NODE: { uint32_t parts_size = yp_sizet_to_u32(((yp_interpolated_x_string_node_t *)node)->parts.size); yp_buffer_append_u32(buffer, parts_size); for (uint32_t index = 0; index < parts_size; index++) { yp_serialize_node(parser, (yp_node_t *) ((yp_interpolated_x_string_node_t *)node)->parts.nodes[index], buffer); } - yp_serialize_location(parser, &((yp_interpolated_x_string_node_t *)node)->closing_loc, buffer); break; } - case YP_NODE_KEYWORD_HASH_NODE: { + case YP_KEYWORD_HASH_NODE: { uint32_t elements_size = yp_sizet_to_u32(((yp_keyword_hash_node_t *)node)->elements.size); yp_buffer_append_u32(buffer, elements_size); for (uint32_t index = 0; index < elements_size; index++) { @@ -954,8 +727,8 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { } break; } - case YP_NODE_KEYWORD_PARAMETER_NODE: { - yp_serialize_location(parser, &((yp_keyword_parameter_node_t *)node)->name_loc, buffer); + case YP_KEYWORD_PARAMETER_NODE: { + yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_keyword_parameter_node_t *)node)->name)); if (((yp_keyword_parameter_node_t *)node)->value == NULL) { yp_buffer_append_u8(buffer, 0); } else { @@ -963,25 +736,16 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { } break; } - case YP_NODE_KEYWORD_REST_PARAMETER_NODE: { - yp_serialize_location(parser, &((yp_keyword_rest_parameter_node_t *)node)->operator_loc, buffer); - if (((yp_keyword_rest_parameter_node_t *)node)->name_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_keyword_rest_parameter_node_t *)node)->name_loc, buffer); - } + case YP_KEYWORD_REST_PARAMETER_NODE: { + yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_keyword_rest_parameter_node_t *)node)->name)); break; } - case YP_NODE_LAMBDA_NODE: { + case YP_LAMBDA_NODE: { uint32_t locals_size = yp_sizet_to_u32(((yp_lambda_node_t *)node)->locals.size); yp_buffer_append_u32(buffer, locals_size); for (uint32_t index = 0; index < locals_size; index++) { yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_lambda_node_t *)node)->locals.ids[index])); } - yp_serialize_location(parser, &((yp_lambda_node_t *)node)->operator_loc, buffer); - yp_serialize_location(parser, &((yp_lambda_node_t *)node)->opening_loc, buffer); - yp_serialize_location(parser, &((yp_lambda_node_t *)node)->closing_loc, buffer); if (((yp_lambda_node_t *)node)->parameters == NULL) { yp_buffer_append_u8(buffer, 0); } else { @@ -994,147 +758,130 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { } break; } - case YP_NODE_LOCAL_VARIABLE_AND_WRITE_NODE: { - yp_serialize_location(parser, &((yp_local_variable_and_write_node_t *)node)->name_loc, buffer); - yp_serialize_location(parser, &((yp_local_variable_and_write_node_t *)node)->operator_loc, buffer); + case YP_LOCAL_VARIABLE_AND_WRITE_NODE: { yp_serialize_node(parser, (yp_node_t *)((yp_local_variable_and_write_node_t *)node)->value, buffer); yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_local_variable_and_write_node_t *)node)->name)); yp_buffer_append_u32(buffer, ((yp_local_variable_and_write_node_t *)node)->depth); break; } - case YP_NODE_LOCAL_VARIABLE_OPERATOR_WRITE_NODE: { - yp_serialize_location(parser, &((yp_local_variable_operator_write_node_t *)node)->name_loc, buffer); - yp_serialize_location(parser, &((yp_local_variable_operator_write_node_t *)node)->operator_loc, buffer); + case YP_LOCAL_VARIABLE_OPERATOR_WRITE_NODE: { yp_serialize_node(parser, (yp_node_t *)((yp_local_variable_operator_write_node_t *)node)->value, buffer); yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_local_variable_operator_write_node_t *)node)->name)); yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_local_variable_operator_write_node_t *)node)->operator)); yp_buffer_append_u32(buffer, ((yp_local_variable_operator_write_node_t *)node)->depth); break; } - case YP_NODE_LOCAL_VARIABLE_OR_WRITE_NODE: { - yp_serialize_location(parser, &((yp_local_variable_or_write_node_t *)node)->name_loc, buffer); - yp_serialize_location(parser, &((yp_local_variable_or_write_node_t *)node)->operator_loc, buffer); + case YP_LOCAL_VARIABLE_OR_WRITE_NODE: { yp_serialize_node(parser, (yp_node_t *)((yp_local_variable_or_write_node_t *)node)->value, buffer); yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_local_variable_or_write_node_t *)node)->name)); yp_buffer_append_u32(buffer, ((yp_local_variable_or_write_node_t *)node)->depth); break; } - case YP_NODE_LOCAL_VARIABLE_READ_NODE: { + case YP_LOCAL_VARIABLE_READ_NODE: { yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_local_variable_read_node_t *)node)->name)); yp_buffer_append_u32(buffer, ((yp_local_variable_read_node_t *)node)->depth); break; } - case YP_NODE_LOCAL_VARIABLE_TARGET_NODE: { + case YP_LOCAL_VARIABLE_TARGET_NODE: { yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_local_variable_target_node_t *)node)->name)); yp_buffer_append_u32(buffer, ((yp_local_variable_target_node_t *)node)->depth); break; } - case YP_NODE_LOCAL_VARIABLE_WRITE_NODE: { + case YP_LOCAL_VARIABLE_WRITE_NODE: { yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_local_variable_write_node_t *)node)->name)); yp_buffer_append_u32(buffer, ((yp_local_variable_write_node_t *)node)->depth); - yp_serialize_location(parser, &((yp_local_variable_write_node_t *)node)->name_loc, buffer); yp_serialize_node(parser, (yp_node_t *)((yp_local_variable_write_node_t *)node)->value, buffer); - yp_serialize_location(parser, &((yp_local_variable_write_node_t *)node)->operator_loc, buffer); break; } - case YP_NODE_MATCH_PREDICATE_NODE: { + case YP_MATCH_LAST_LINE_NODE: { + yp_serialize_location(parser, &((yp_match_last_line_node_t *)node)->content_loc, buffer); + yp_serialize_string(parser, &((yp_match_last_line_node_t *)node)->unescaped, buffer); + yp_buffer_append_u32(buffer, node->flags >> 2); + break; + } + case YP_MATCH_PREDICATE_NODE: { yp_serialize_node(parser, (yp_node_t *)((yp_match_predicate_node_t *)node)->value, buffer); yp_serialize_node(parser, (yp_node_t *)((yp_match_predicate_node_t *)node)->pattern, buffer); - yp_serialize_location(parser, &((yp_match_predicate_node_t *)node)->operator_loc, buffer); break; } - case YP_NODE_MATCH_REQUIRED_NODE: { + case YP_MATCH_REQUIRED_NODE: { yp_serialize_node(parser, (yp_node_t *)((yp_match_required_node_t *)node)->value, buffer); yp_serialize_node(parser, (yp_node_t *)((yp_match_required_node_t *)node)->pattern, buffer); - yp_serialize_location(parser, &((yp_match_required_node_t *)node)->operator_loc, buffer); break; } - case YP_NODE_MISSING_NODE: { + case YP_MATCH_WRITE_NODE: { + yp_serialize_node(parser, (yp_node_t *)((yp_match_write_node_t *)node)->call, buffer); + uint32_t locals_size = yp_sizet_to_u32(((yp_match_write_node_t *)node)->locals.size); + yp_buffer_append_u32(buffer, locals_size); + for (uint32_t index = 0; index < locals_size; index++) { + yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_match_write_node_t *)node)->locals.ids[index])); + } + break; + } + case YP_MISSING_NODE: { break; } - case YP_NODE_MODULE_NODE: { + case YP_MODULE_NODE: { uint32_t locals_size = yp_sizet_to_u32(((yp_module_node_t *)node)->locals.size); yp_buffer_append_u32(buffer, locals_size); for (uint32_t index = 0; index < locals_size; index++) { yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_module_node_t *)node)->locals.ids[index])); } - yp_serialize_location(parser, &((yp_module_node_t *)node)->module_keyword_loc, buffer); yp_serialize_node(parser, (yp_node_t *)((yp_module_node_t *)node)->constant_path, buffer); if (((yp_module_node_t *)node)->body == NULL) { yp_buffer_append_u8(buffer, 0); } else { yp_serialize_node(parser, (yp_node_t *)((yp_module_node_t *)node)->body, buffer); } - yp_serialize_location(parser, &((yp_module_node_t *)node)->end_keyword_loc, buffer); - yp_serialize_string(parser, &((yp_module_node_t *)node)->name, buffer); + yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_module_node_t *)node)->name)); + break; + } + case YP_MULTI_TARGET_NODE: { + uint32_t targets_size = yp_sizet_to_u32(((yp_multi_target_node_t *)node)->targets.size); + yp_buffer_append_u32(buffer, targets_size); + for (uint32_t index = 0; index < targets_size; index++) { + yp_serialize_node(parser, (yp_node_t *) ((yp_multi_target_node_t *)node)->targets.nodes[index], buffer); + } break; } - case YP_NODE_MULTI_WRITE_NODE: { + case YP_MULTI_WRITE_NODE: { uint32_t targets_size = yp_sizet_to_u32(((yp_multi_write_node_t *)node)->targets.size); yp_buffer_append_u32(buffer, targets_size); for (uint32_t index = 0; index < targets_size; index++) { yp_serialize_node(parser, (yp_node_t *) ((yp_multi_write_node_t *)node)->targets.nodes[index], buffer); } - if (((yp_multi_write_node_t *)node)->operator_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_multi_write_node_t *)node)->operator_loc, buffer); - } - if (((yp_multi_write_node_t *)node)->value == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_serialize_node(parser, (yp_node_t *)((yp_multi_write_node_t *)node)->value, buffer); - } - if (((yp_multi_write_node_t *)node)->lparen_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_multi_write_node_t *)node)->lparen_loc, buffer); - } - if (((yp_multi_write_node_t *)node)->rparen_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_multi_write_node_t *)node)->rparen_loc, buffer); - } + yp_serialize_node(parser, (yp_node_t *)((yp_multi_write_node_t *)node)->value, buffer); break; } - case YP_NODE_NEXT_NODE: { + case YP_NEXT_NODE: { if (((yp_next_node_t *)node)->arguments == NULL) { yp_buffer_append_u8(buffer, 0); } else { yp_serialize_node(parser, (yp_node_t *)((yp_next_node_t *)node)->arguments, buffer); } - yp_serialize_location(parser, &((yp_next_node_t *)node)->keyword_loc, buffer); break; } - case YP_NODE_NIL_NODE: { + case YP_NIL_NODE: { break; } - case YP_NODE_NO_KEYWORDS_PARAMETER_NODE: { - yp_serialize_location(parser, &((yp_no_keywords_parameter_node_t *)node)->operator_loc, buffer); - yp_serialize_location(parser, &((yp_no_keywords_parameter_node_t *)node)->keyword_loc, buffer); + case YP_NO_KEYWORDS_PARAMETER_NODE: { break; } - case YP_NODE_NUMBERED_REFERENCE_READ_NODE: { + case YP_NUMBERED_REFERENCE_READ_NODE: { yp_buffer_append_u32(buffer, ((yp_numbered_reference_read_node_t *)node)->number); break; } - case YP_NODE_OPTIONAL_PARAMETER_NODE: { + case YP_OPTIONAL_PARAMETER_NODE: { yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_optional_parameter_node_t *)node)->name)); - yp_serialize_location(parser, &((yp_optional_parameter_node_t *)node)->name_loc, buffer); - yp_serialize_location(parser, &((yp_optional_parameter_node_t *)node)->operator_loc, buffer); yp_serialize_node(parser, (yp_node_t *)((yp_optional_parameter_node_t *)node)->value, buffer); break; } - case YP_NODE_OR_NODE: { + case YP_OR_NODE: { yp_serialize_node(parser, (yp_node_t *)((yp_or_node_t *)node)->left, buffer); yp_serialize_node(parser, (yp_node_t *)((yp_or_node_t *)node)->right, buffer); - yp_serialize_location(parser, &((yp_or_node_t *)node)->operator_loc, buffer); break; } - case YP_NODE_PARAMETERS_NODE: { + case YP_PARAMETERS_NODE: { uint32_t requireds_size = yp_sizet_to_u32(((yp_parameters_node_t *)node)->requireds.size); yp_buffer_append_u32(buffer, requireds_size); for (uint32_t index = 0; index < requireds_size; index++) { @@ -1145,16 +892,16 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { for (uint32_t index = 0; index < optionals_size; index++) { yp_serialize_node(parser, (yp_node_t *) ((yp_parameters_node_t *)node)->optionals.nodes[index], buffer); } - uint32_t posts_size = yp_sizet_to_u32(((yp_parameters_node_t *)node)->posts.size); - yp_buffer_append_u32(buffer, posts_size); - for (uint32_t index = 0; index < posts_size; index++) { - yp_serialize_node(parser, (yp_node_t *) ((yp_parameters_node_t *)node)->posts.nodes[index], buffer); - } if (((yp_parameters_node_t *)node)->rest == NULL) { yp_buffer_append_u8(buffer, 0); } else { yp_serialize_node(parser, (yp_node_t *)((yp_parameters_node_t *)node)->rest, buffer); } + uint32_t posts_size = yp_sizet_to_u32(((yp_parameters_node_t *)node)->posts.size); + yp_buffer_append_u32(buffer, posts_size); + for (uint32_t index = 0; index < posts_size; index++) { + yp_serialize_node(parser, (yp_node_t *) ((yp_parameters_node_t *)node)->posts.nodes[index], buffer); + } uint32_t keywords_size = yp_sizet_to_u32(((yp_parameters_node_t *)node)->keywords.size); yp_buffer_append_u32(buffer, keywords_size); for (uint32_t index = 0; index < keywords_size; index++) { @@ -1172,51 +919,39 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { } break; } - case YP_NODE_PARENTHESES_NODE: { + case YP_PARENTHESES_NODE: { if (((yp_parentheses_node_t *)node)->body == NULL) { yp_buffer_append_u8(buffer, 0); } else { yp_serialize_node(parser, (yp_node_t *)((yp_parentheses_node_t *)node)->body, buffer); } - yp_serialize_location(parser, &((yp_parentheses_node_t *)node)->opening_loc, buffer); - yp_serialize_location(parser, &((yp_parentheses_node_t *)node)->closing_loc, buffer); break; } - case YP_NODE_PINNED_EXPRESSION_NODE: { + case YP_PINNED_EXPRESSION_NODE: { yp_serialize_node(parser, (yp_node_t *)((yp_pinned_expression_node_t *)node)->expression, buffer); - yp_serialize_location(parser, &((yp_pinned_expression_node_t *)node)->operator_loc, buffer); - yp_serialize_location(parser, &((yp_pinned_expression_node_t *)node)->lparen_loc, buffer); - yp_serialize_location(parser, &((yp_pinned_expression_node_t *)node)->rparen_loc, buffer); break; } - case YP_NODE_PINNED_VARIABLE_NODE: { + case YP_PINNED_VARIABLE_NODE: { yp_serialize_node(parser, (yp_node_t *)((yp_pinned_variable_node_t *)node)->variable, buffer); - yp_serialize_location(parser, &((yp_pinned_variable_node_t *)node)->operator_loc, buffer); break; } - case YP_NODE_POST_EXECUTION_NODE: { + case YP_POST_EXECUTION_NODE: { if (((yp_post_execution_node_t *)node)->statements == NULL) { yp_buffer_append_u8(buffer, 0); } else { yp_serialize_node(parser, (yp_node_t *)((yp_post_execution_node_t *)node)->statements, buffer); } - yp_serialize_location(parser, &((yp_post_execution_node_t *)node)->keyword_loc, buffer); - yp_serialize_location(parser, &((yp_post_execution_node_t *)node)->opening_loc, buffer); - yp_serialize_location(parser, &((yp_post_execution_node_t *)node)->closing_loc, buffer); break; } - case YP_NODE_PRE_EXECUTION_NODE: { + case YP_PRE_EXECUTION_NODE: { if (((yp_pre_execution_node_t *)node)->statements == NULL) { yp_buffer_append_u8(buffer, 0); } else { yp_serialize_node(parser, (yp_node_t *)((yp_pre_execution_node_t *)node)->statements, buffer); } - yp_serialize_location(parser, &((yp_pre_execution_node_t *)node)->keyword_loc, buffer); - yp_serialize_location(parser, &((yp_pre_execution_node_t *)node)->opening_loc, buffer); - yp_serialize_location(parser, &((yp_pre_execution_node_t *)node)->closing_loc, buffer); break; } - case YP_NODE_PROGRAM_NODE: { + case YP_PROGRAM_NODE: { uint32_t locals_size = yp_sizet_to_u32(((yp_program_node_t *)node)->locals.size); yp_buffer_append_u32(buffer, locals_size); for (uint32_t index = 0; index < locals_size; index++) { @@ -1225,7 +960,7 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { yp_serialize_node(parser, (yp_node_t *)((yp_program_node_t *)node)->statements, buffer); break; } - case YP_NODE_RANGE_NODE: { + case YP_RANGE_NODE: { if (((yp_range_node_t *)node)->left == NULL) { yp_buffer_append_u8(buffer, 0); } else { @@ -1236,58 +971,45 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { } else { yp_serialize_node(parser, (yp_node_t *)((yp_range_node_t *)node)->right, buffer); } - yp_serialize_location(parser, &((yp_range_node_t *)node)->operator_loc, buffer); - yp_buffer_append_u32(buffer, node->flags >> 1); + yp_buffer_append_u32(buffer, node->flags >> 2); break; } - case YP_NODE_RATIONAL_NODE: { + case YP_RATIONAL_NODE: { yp_serialize_node(parser, (yp_node_t *)((yp_rational_node_t *)node)->numeric, buffer); break; } - case YP_NODE_REDO_NODE: { + case YP_REDO_NODE: { break; } - case YP_NODE_REGULAR_EXPRESSION_NODE: { - yp_serialize_location(parser, &((yp_regular_expression_node_t *)node)->opening_loc, buffer); + case YP_REGULAR_EXPRESSION_NODE: { yp_serialize_location(parser, &((yp_regular_expression_node_t *)node)->content_loc, buffer); - yp_serialize_location(parser, &((yp_regular_expression_node_t *)node)->closing_loc, buffer); yp_serialize_string(parser, &((yp_regular_expression_node_t *)node)->unescaped, buffer); - yp_buffer_append_u32(buffer, node->flags >> 1); + yp_buffer_append_u32(buffer, node->flags >> 2); break; } - case YP_NODE_REQUIRED_DESTRUCTURED_PARAMETER_NODE: { + case YP_REQUIRED_DESTRUCTURED_PARAMETER_NODE: { uint32_t parameters_size = yp_sizet_to_u32(((yp_required_destructured_parameter_node_t *)node)->parameters.size); yp_buffer_append_u32(buffer, parameters_size); for (uint32_t index = 0; index < parameters_size; index++) { yp_serialize_node(parser, (yp_node_t *) ((yp_required_destructured_parameter_node_t *)node)->parameters.nodes[index], buffer); } - yp_serialize_location(parser, &((yp_required_destructured_parameter_node_t *)node)->opening_loc, buffer); - yp_serialize_location(parser, &((yp_required_destructured_parameter_node_t *)node)->closing_loc, buffer); break; } - case YP_NODE_REQUIRED_PARAMETER_NODE: { + case YP_REQUIRED_PARAMETER_NODE: { yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_required_parameter_node_t *)node)->name)); break; } - case YP_NODE_RESCUE_MODIFIER_NODE: { + case YP_RESCUE_MODIFIER_NODE: { yp_serialize_node(parser, (yp_node_t *)((yp_rescue_modifier_node_t *)node)->expression, buffer); - yp_serialize_location(parser, &((yp_rescue_modifier_node_t *)node)->keyword_loc, buffer); yp_serialize_node(parser, (yp_node_t *)((yp_rescue_modifier_node_t *)node)->rescue_expression, buffer); break; } - case YP_NODE_RESCUE_NODE: { - yp_serialize_location(parser, &((yp_rescue_node_t *)node)->keyword_loc, buffer); + case YP_RESCUE_NODE: { uint32_t exceptions_size = yp_sizet_to_u32(((yp_rescue_node_t *)node)->exceptions.size); yp_buffer_append_u32(buffer, exceptions_size); for (uint32_t index = 0; index < exceptions_size; index++) { yp_serialize_node(parser, (yp_node_t *) ((yp_rescue_node_t *)node)->exceptions.nodes[index], buffer); } - if (((yp_rescue_node_t *)node)->operator_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_rescue_node_t *)node)->operator_loc, buffer); - } if (((yp_rescue_node_t *)node)->reference == NULL) { yp_buffer_append_u8(buffer, 0); } else { @@ -1305,21 +1027,14 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { } break; } - case YP_NODE_REST_PARAMETER_NODE: { - yp_serialize_location(parser, &((yp_rest_parameter_node_t *)node)->operator_loc, buffer); - if (((yp_rest_parameter_node_t *)node)->name_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_rest_parameter_node_t *)node)->name_loc, buffer); - } + case YP_REST_PARAMETER_NODE: { + yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_rest_parameter_node_t *)node)->name)); break; } - case YP_NODE_RETRY_NODE: { + case YP_RETRY_NODE: { break; } - case YP_NODE_RETURN_NODE: { - yp_serialize_location(parser, &((yp_return_node_t *)node)->keyword_loc, buffer); + case YP_RETURN_NODE: { if (((yp_return_node_t *)node)->arguments == NULL) { yp_buffer_append_u8(buffer, 0); } else { @@ -1327,38 +1042,34 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { } break; } - case YP_NODE_SELF_NODE: { + case YP_SELF_NODE: { break; } - case YP_NODE_SINGLETON_CLASS_NODE: { + case YP_SINGLETON_CLASS_NODE: { uint32_t locals_size = yp_sizet_to_u32(((yp_singleton_class_node_t *)node)->locals.size); yp_buffer_append_u32(buffer, locals_size); for (uint32_t index = 0; index < locals_size; index++) { yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_singleton_class_node_t *)node)->locals.ids[index])); } - yp_serialize_location(parser, &((yp_singleton_class_node_t *)node)->class_keyword_loc, buffer); - yp_serialize_location(parser, &((yp_singleton_class_node_t *)node)->operator_loc, buffer); yp_serialize_node(parser, (yp_node_t *)((yp_singleton_class_node_t *)node)->expression, buffer); if (((yp_singleton_class_node_t *)node)->body == NULL) { yp_buffer_append_u8(buffer, 0); } else { yp_serialize_node(parser, (yp_node_t *)((yp_singleton_class_node_t *)node)->body, buffer); } - yp_serialize_location(parser, &((yp_singleton_class_node_t *)node)->end_keyword_loc, buffer); break; } - case YP_NODE_SOURCE_ENCODING_NODE: { + case YP_SOURCE_ENCODING_NODE: { break; } - case YP_NODE_SOURCE_FILE_NODE: { + case YP_SOURCE_FILE_NODE: { yp_serialize_string(parser, &((yp_source_file_node_t *)node)->filepath, buffer); break; } - case YP_NODE_SOURCE_LINE_NODE: { + case YP_SOURCE_LINE_NODE: { break; } - case YP_NODE_SPLAT_NODE: { - yp_serialize_location(parser, &((yp_splat_node_t *)node)->operator_loc, buffer); + case YP_SPLAT_NODE: { if (((yp_splat_node_t *)node)->expression == NULL) { yp_buffer_append_u8(buffer, 0); } else { @@ -1366,7 +1077,7 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { } break; } - case YP_NODE_STATEMENTS_NODE: { + case YP_STATEMENTS_NODE: { uint32_t body_size = yp_sizet_to_u32(((yp_statements_node_t *)node)->body.size); yp_buffer_append_u32(buffer, body_size); for (uint32_t index = 0; index < body_size; index++) { @@ -1374,12 +1085,13 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { } break; } - case YP_NODE_STRING_CONCAT_NODE: { + case YP_STRING_CONCAT_NODE: { yp_serialize_node(parser, (yp_node_t *)((yp_string_concat_node_t *)node)->left, buffer); yp_serialize_node(parser, (yp_node_t *)((yp_string_concat_node_t *)node)->right, buffer); break; } - case YP_NODE_STRING_NODE: { + case YP_STRING_NODE: { + yp_buffer_append_u32(buffer, node->flags >> 2); if (((yp_string_node_t *)node)->opening_loc.start == NULL) { yp_buffer_append_u8(buffer, 0); } else { @@ -1387,34 +1099,15 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { yp_serialize_location(parser, &((yp_string_node_t *)node)->opening_loc, buffer); } yp_serialize_location(parser, &((yp_string_node_t *)node)->content_loc, buffer); - if (((yp_string_node_t *)node)->closing_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_string_node_t *)node)->closing_loc, buffer); - } yp_serialize_string(parser, &((yp_string_node_t *)node)->unescaped, buffer); break; } - case YP_NODE_SUPER_NODE: { - yp_serialize_location(parser, &((yp_super_node_t *)node)->keyword_loc, buffer); - if (((yp_super_node_t *)node)->lparen_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_super_node_t *)node)->lparen_loc, buffer); - } + case YP_SUPER_NODE: { if (((yp_super_node_t *)node)->arguments == NULL) { yp_buffer_append_u8(buffer, 0); } else { yp_serialize_node(parser, (yp_node_t *)((yp_super_node_t *)node)->arguments, buffer); } - if (((yp_super_node_t *)node)->rparen_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_super_node_t *)node)->rparen_loc, buffer); - } if (((yp_super_node_t *)node)->block == NULL) { yp_buffer_append_u8(buffer, 0); } else { @@ -1422,42 +1115,22 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { } break; } - case YP_NODE_SYMBOL_NODE: { - if (((yp_symbol_node_t *)node)->opening_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_symbol_node_t *)node)->opening_loc, buffer); - } - if (((yp_symbol_node_t *)node)->value_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_symbol_node_t *)node)->value_loc, buffer); - } - if (((yp_symbol_node_t *)node)->closing_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_symbol_node_t *)node)->closing_loc, buffer); - } + case YP_SYMBOL_NODE: { yp_serialize_string(parser, &((yp_symbol_node_t *)node)->unescaped, buffer); break; } - case YP_NODE_TRUE_NODE: { + case YP_TRUE_NODE: { break; } - case YP_NODE_UNDEF_NODE: { + case YP_UNDEF_NODE: { uint32_t names_size = yp_sizet_to_u32(((yp_undef_node_t *)node)->names.size); yp_buffer_append_u32(buffer, names_size); for (uint32_t index = 0; index < names_size; index++) { yp_serialize_node(parser, (yp_node_t *) ((yp_undef_node_t *)node)->names.nodes[index], buffer); } - yp_serialize_location(parser, &((yp_undef_node_t *)node)->keyword_loc, buffer); break; } - case YP_NODE_UNLESS_NODE: { - yp_serialize_location(parser, &((yp_unless_node_t *)node)->keyword_loc, buffer); + case YP_UNLESS_NODE: { yp_serialize_node(parser, (yp_node_t *)((yp_unless_node_t *)node)->predicate, buffer); if (((yp_unless_node_t *)node)->statements == NULL) { yp_buffer_append_u8(buffer, 0); @@ -1469,33 +1142,19 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { } else { yp_serialize_node(parser, (yp_node_t *)((yp_unless_node_t *)node)->consequent, buffer); } - if (((yp_unless_node_t *)node)->end_keyword_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_unless_node_t *)node)->end_keyword_loc, buffer); - } break; } - case YP_NODE_UNTIL_NODE: { - yp_serialize_location(parser, &((yp_until_node_t *)node)->keyword_loc, buffer); - if (((yp_until_node_t *)node)->closing_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_until_node_t *)node)->closing_loc, buffer); - } + case YP_UNTIL_NODE: { yp_serialize_node(parser, (yp_node_t *)((yp_until_node_t *)node)->predicate, buffer); if (((yp_until_node_t *)node)->statements == NULL) { yp_buffer_append_u8(buffer, 0); } else { yp_serialize_node(parser, (yp_node_t *)((yp_until_node_t *)node)->statements, buffer); } - yp_buffer_append_u32(buffer, node->flags >> 1); + yp_buffer_append_u32(buffer, node->flags >> 2); break; } - case YP_NODE_WHEN_NODE: { - yp_serialize_location(parser, &((yp_when_node_t *)node)->keyword_loc, buffer); + case YP_WHEN_NODE: { uint32_t conditions_size = yp_sizet_to_u32(((yp_when_node_t *)node)->conditions.size); yp_buffer_append_u32(buffer, conditions_size); for (uint32_t index = 0; index < conditions_size; index++) { @@ -1508,49 +1167,26 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { } break; } - case YP_NODE_WHILE_NODE: { - yp_serialize_location(parser, &((yp_while_node_t *)node)->keyword_loc, buffer); - if (((yp_while_node_t *)node)->closing_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_while_node_t *)node)->closing_loc, buffer); - } + case YP_WHILE_NODE: { yp_serialize_node(parser, (yp_node_t *)((yp_while_node_t *)node)->predicate, buffer); if (((yp_while_node_t *)node)->statements == NULL) { yp_buffer_append_u8(buffer, 0); } else { yp_serialize_node(parser, (yp_node_t *)((yp_while_node_t *)node)->statements, buffer); } - yp_buffer_append_u32(buffer, node->flags >> 1); + yp_buffer_append_u32(buffer, node->flags >> 2); break; } - case YP_NODE_X_STRING_NODE: { - yp_serialize_location(parser, &((yp_x_string_node_t *)node)->opening_loc, buffer); - yp_serialize_location(parser, &((yp_x_string_node_t *)node)->content_loc, buffer); - yp_serialize_location(parser, &((yp_x_string_node_t *)node)->closing_loc, buffer); + case YP_X_STRING_NODE: { yp_serialize_string(parser, &((yp_x_string_node_t *)node)->unescaped, buffer); break; } - case YP_NODE_YIELD_NODE: { - yp_serialize_location(parser, &((yp_yield_node_t *)node)->keyword_loc, buffer); - if (((yp_yield_node_t *)node)->lparen_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_yield_node_t *)node)->lparen_loc, buffer); - } + case YP_YIELD_NODE: { if (((yp_yield_node_t *)node)->arguments == NULL) { yp_buffer_append_u8(buffer, 0); } else { yp_serialize_node(parser, (yp_node_t *)((yp_yield_node_t *)node)->arguments, buffer); } - if (((yp_yield_node_t *)node)->rparen_loc.start == NULL) { - yp_buffer_append_u8(buffer, 0); - } else { - yp_buffer_append_u8(buffer, 1); - yp_serialize_location(parser, &((yp_yield_node_t *)node)->rparen_loc, buffer); - } break; } } @@ -1605,7 +1241,7 @@ yp_serialize_encoding(yp_encoding_t *encoding, yp_buffer_t *buffer) { yp_buffer_append_str(buffer, encoding->name, encoding_length); } -#line 181 "serialize.c.erb" +#line 179 "serialize.c.erb" void yp_serialize_content(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { yp_serialize_encoding(&parser->encoding, buffer); @@ -1619,7 +1255,7 @@ yp_serialize_content(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) yp_buffer_append_zeroes(buffer, 4); // Next, encode the length of the constant pool. - yp_buffer_append_u32(buffer, yp_sizet_to_u32(parser->constant_pool.size)); + yp_buffer_append_u32(buffer, parser->constant_pool.size); // Now we're going to serialize the content of the node. yp_serialize_node(parser, node, buffer); @@ -1634,18 +1270,37 @@ yp_serialize_content(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) yp_buffer_append_zeroes(buffer, parser->constant_pool.size * 8); yp_constant_t *constant; - for (size_t index = 0; index < parser->constant_pool.capacity; index++) { + for (uint32_t index = 0; index < parser->constant_pool.capacity; index++) { constant = &parser->constant_pool.constants[index]; // If we find a constant at this index, serialize it at the correct // index in the buffer. if (constant->id != 0) { - size_t buffer_offset = offset + ((constant->id - 1) * 8); + size_t buffer_offset = offset + ((((size_t) constant->id) - 1) * 8); - uint32_t source_offset = yp_ptrdifft_to_u32(constant->start - parser->start); - uint32_t constant_length = yp_sizet_to_u32(constant->length); + if (constant->owned) { + // Since this is an owned constant, we are going to write its + // contents into the buffer after the constant pool. So + // effectively in place of the source offset, we have a buffer + // offset. We will add a leading 1 to indicate that this is a + // buffer offset. + uint32_t content_offset = yp_sizet_to_u32(buffer->length); + uint32_t owned_mask = (uint32_t) (1 << 31); + + assert(content_offset < owned_mask); + content_offset |= owned_mask; - memcpy(buffer->value + buffer_offset, &source_offset, 4); + memcpy(buffer->value + buffer_offset, &content_offset, 4); + yp_buffer_append_bytes(buffer, constant->start, constant->length); + } else { + // Since this is a shared constant, we are going to write its + // source offset directly into the buffer. + uint32_t source_offset = yp_ptrdifft_to_u32(constant->start - parser->start); + memcpy(buffer->value + buffer_offset, &source_offset, 4); + } + + // Now we can write the length of the constant into the buffer. + uint32_t constant_length = yp_sizet_to_u32(constant->length); memcpy(buffer->value + buffer_offset + 4, &constant_length, 4); } } diff --git a/src/main/c/yarp/src/unescape.c b/src/main/c/yarp/src/unescape.c index 830c5996ae38..6ecb8f49c4a3 100644 --- a/src/main/c/yarp/src/unescape.c +++ b/src/main/c/yarp/src/unescape.c @@ -94,7 +94,7 @@ static inline size_t unescape_hexadecimal(const uint8_t *backslash, uint8_t *value, const uint8_t *end, yp_list_t *error_list) { *value = 0; if (backslash + 2 >= end || !yp_char_is_hexadecimal_digit(backslash[2])) { - if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 2, "Invalid hex escape."); + if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 2, YP_ERR_ESCAPE_INVALID_HEXADECIMAL); return 2; } *value = unescape_hexadecimal_digit(backslash[2]); @@ -157,7 +157,7 @@ unescape_unicode_write(uint8_t *dest, uint32_t value, const uint8_t *start, cons // If we get here, then the value is too big. This is an error, but we don't // want to just crash, so instead we'll add an error to the error list and put // in a replacement character instead. - if (error_list) yp_diagnostic_list_append(error_list, start, end, "Invalid Unicode escape sequence."); + if (error_list) yp_diagnostic_list_append(error_list, start, end, YP_ERR_ESCAPE_INVALID_UNICODE); dest[0] = 0xEF; dest[1] = 0xBF; dest[2] = 0xBD; @@ -235,7 +235,7 @@ unescape( // \unnnn Unicode character, where nnnn is exactly 4 hexadecimal digits ([0-9a-fA-F]) case 'u': { if ((flags & YP_UNESCAPE_FLAG_CONTROL) | (flags & YP_UNESCAPE_FLAG_META)) { - if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 2, "Unicode escape sequence cannot be used with control or meta flags."); + if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 2, YP_ERR_ESCAPE_INVALID_UNICODE_CM_FLAGS); return backslash + 2; } @@ -252,11 +252,11 @@ unescape( // \u{nnnn} character literal allows only 1-6 hexadecimal digits if (hexadecimal_length > 6) { - if (error_list) yp_diagnostic_list_append(error_list, unicode_cursor, unicode_cursor + hexadecimal_length, "invalid Unicode escape."); + if (error_list) yp_diagnostic_list_append(error_list, unicode_cursor, unicode_cursor + hexadecimal_length, YP_ERR_ESCAPE_INVALID_UNICODE_LONG); } // there are not hexadecimal characters else if (hexadecimal_length == 0) { - if (error_list) yp_diagnostic_list_append(error_list, unicode_cursor, unicode_cursor + hexadecimal_length, "unterminated Unicode escape"); + if (error_list) yp_diagnostic_list_append(error_list, unicode_cursor, unicode_cursor + hexadecimal_length, YP_ERR_ESCAPE_INVALID_UNICODE); return unicode_cursor; } @@ -277,13 +277,13 @@ unescape( // ?\u{nnnn} character literal should contain only one codepoint and cannot be like ?\u{nnnn mmmm} if (flags & YP_UNESCAPE_FLAG_EXPECT_SINGLE && codepoints_count > 1) { - if (error_list) yp_diagnostic_list_append(error_list, extra_codepoints_start, unicode_cursor - 1, "Multiple codepoints at single character literal"); + if (error_list) yp_diagnostic_list_append(error_list, extra_codepoints_start, unicode_cursor - 1, YP_ERR_ESCAPE_INVALID_UNICODE_LITERAL); } if (unicode_cursor < end && *unicode_cursor == '}') { unicode_cursor++; } else { - if (error_list) yp_diagnostic_list_append(error_list, backslash, unicode_cursor, "invalid Unicode escape."); + if (error_list) yp_diagnostic_list_append(error_list, backslash, unicode_cursor, YP_ERR_ESCAPE_INVALID_UNICODE_TERM); } return unicode_cursor; @@ -298,7 +298,7 @@ unescape( return backslash + 6; } - if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 2, "Invalid Unicode escape sequence"); + if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 2, YP_ERR_ESCAPE_INVALID_UNICODE); return backslash + 2; } // \c\M-x meta control character, where x is an ASCII printable character @@ -306,12 +306,12 @@ unescape( // \cx control character, where x is an ASCII printable character case 'c': if (backslash + 2 >= end) { - if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 1, "Invalid control escape sequence"); + if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 1, YP_ERR_ESCAPE_INVALID_CONTROL); return end; } if (flags & YP_UNESCAPE_FLAG_CONTROL) { - if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 1, "Control escape sequence cannot be doubled."); + if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 1, YP_ERR_ESCAPE_INVALID_CONTROL_REPEAT); return backslash + 2; } @@ -325,7 +325,7 @@ unescape( return backslash + 3; default: { if (!char_is_ascii_printable(backslash[2])) { - if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 1, "Invalid control escape sequence"); + if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 1, YP_ERR_ESCAPE_INVALID_CONTROL); return backslash + 2; } @@ -339,17 +339,17 @@ unescape( // \C-? delete, ASCII 7Fh (DEL) case 'C': if (backslash + 3 >= end) { - if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 1, "Invalid control escape sequence"); + if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 1, YP_ERR_ESCAPE_INVALID_CONTROL); return end; } if (flags & YP_UNESCAPE_FLAG_CONTROL) { - if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 1, "Control escape sequence cannot be doubled."); + if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 1, YP_ERR_ESCAPE_INVALID_CONTROL_REPEAT); return backslash + 2; } if (backslash[2] != '-') { - if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 1, "Invalid control escape sequence"); + if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 1, YP_ERR_ESCAPE_INVALID_CONTROL); return backslash + 2; } @@ -363,7 +363,7 @@ unescape( return backslash + 4; default: if (!char_is_ascii_printable(backslash[3])) { - if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 2, "Invalid control escape sequence"); + if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 2, YP_ERR_ESCAPE_INVALID_CONTROL); return backslash + 2; } @@ -377,17 +377,17 @@ unescape( // \M-x meta character, where x is an ASCII printable character case 'M': { if (backslash + 3 >= end) { - if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 1, "Invalid control escape sequence"); + if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 1, YP_ERR_ESCAPE_INVALID_META); return end; } if (flags & YP_UNESCAPE_FLAG_META) { - if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 2, "Meta escape sequence cannot be doubled."); + if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 2, YP_ERR_ESCAPE_INVALID_META_REPEAT); return backslash + 2; } if (backslash[2] != '-') { - if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 2, "Invalid meta escape sequence"); + if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 2, YP_ERR_ESCAPE_INVALID_META); return backslash + 2; } @@ -402,7 +402,7 @@ unescape( return backslash + 4; } - if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 2, "Invalid meta escape sequence"); + if (error_list) yp_diagnostic_list_append(error_list, backslash, backslash + 2, YP_ERR_ESCAPE_INVALID_META); return backslash + 3; } // \n @@ -474,7 +474,7 @@ yp_unescape_manipulate_string_or_char_literal(yp_parser_t *parser, yp_string_t * // within the string. uint8_t *allocated = malloc(string->length); if (allocated == NULL) { - yp_diagnostic_list_append(&parser->error_list, string->source, string->source + string->length, "Failed to allocate memory for unescaping."); + yp_diagnostic_list_append(&parser->error_list, string->source, string->source + string->length, YP_ERR_MALLOC_FAILED); return; } @@ -509,7 +509,17 @@ yp_unescape_manipulate_string_or_char_literal(yp_parser_t *parser, yp_string_t * cursor = backslash + 2; break; default: - if (unescape_type == YP_UNESCAPE_MINIMAL) { + if (unescape_type == YP_UNESCAPE_WHITESPACE) { + if (backslash[1] == '\r' && backslash[2] == '\n') { + cursor = backslash + 2; + break; + } + if (yp_strspn_whitespace(backslash + 1, 1)) { + cursor = backslash + 1; + break; + } + } + if (unescape_type == YP_UNESCAPE_WHITESPACE || unescape_type == YP_UNESCAPE_MINIMAL) { // In this case we're escaping something that doesn't need escaping. dest[dest_length++] = '\\'; cursor = backslash + 1; @@ -579,7 +589,16 @@ yp_unescape_calculate_difference(yp_parser_t *parser, const uint8_t *backslash, case '\'': return 2; default: { - if (unescape_type == YP_UNESCAPE_MINIMAL) { + if (unescape_type == YP_UNESCAPE_WHITESPACE) { + if (backslash[1] == '\r' && backslash[2] == '\n') { + return 2; + } + size_t whitespace = yp_strspn_whitespace(backslash + 1, 1); + if (whitespace > 0) { + return whitespace; + } + } + if (unescape_type == YP_UNESCAPE_WHITESPACE || unescape_type == YP_UNESCAPE_MINIMAL) { return 1 + yp_char_width(parser, backslash + 1, parser->end); } diff --git a/src/main/c/yarp/src/util/yp_char.c b/src/main/c/yarp/src/util/yp_char.c index e9f1ef45c209..42c3896626bf 100644 --- a/src/main/c/yarp/src/util/yp_char.c +++ b/src/main/c/yarp/src/util/yp_char.c @@ -75,7 +75,7 @@ yp_strspn_whitespace(const uint8_t *string, ptrdiff_t length) { // whitespace while also tracking the location of each newline. Disallows // searching past the given maximum number of characters. size_t -yp_strspn_whitespace_newlines(const uint8_t *string, ptrdiff_t length, yp_newline_list_t *newline_list, bool stop_at_newline) { +yp_strspn_whitespace_newlines(const uint8_t *string, ptrdiff_t length, yp_newline_list_t *newline_list) { if (length <= 0) return 0; size_t size = 0; @@ -83,12 +83,7 @@ yp_strspn_whitespace_newlines(const uint8_t *string, ptrdiff_t length, yp_newlin while (size < maximum && (yp_byte_table[string[size]] & YP_CHAR_BIT_WHITESPACE)) { if (string[size] == '\n') { - if (stop_at_newline) { - return size + 1; - } - else { - yp_newline_list_append(newline_list, string + size); - } + yp_newline_list_append(newline_list, string + size); } size++; @@ -128,6 +123,9 @@ yp_char_is_inline_whitespace(const uint8_t b) { return yp_char_is_char_kind(b, YP_CHAR_BIT_INLINE_WHITESPACE); } +// Scan through the string and return the number of characters at the start of +// the string that match the given kind. Disallows searching past the given +// maximum number of characters. static inline size_t yp_strspn_number_kind(const uint8_t *string, ptrdiff_t length, uint8_t kind) { if (length <= 0) return 0; @@ -139,20 +137,57 @@ yp_strspn_number_kind(const uint8_t *string, ptrdiff_t length, uint8_t kind) { return size; } +// Scan through the string and return the number of characters at the start of +// the string that match the given kind. Disallows searching past the given +// maximum number of characters. +// +// Additionally, report the location of the last invalid underscore character +// found in the string through the out invalid parameter. +static inline size_t +yp_strspn_number_kind_underscores(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid, uint8_t kind) { + if (length <= 0) return 0; + + size_t size = 0; + size_t maximum = (size_t) length; + + bool underscore = false; + while (size < maximum && (yp_number_table[string[size]] & kind)) { + if (string[size] == '_') { + if (underscore) *invalid = string + size; + underscore = true; + } else { + underscore = false; + } + + size++; + } + + if (string[size - 1] == '_') *invalid = string + size - 1; + return size; +} + // Returns the number of characters at the start of the string that are binary // digits or underscores. Disallows searching past the given maximum number of // characters. +// +// If multiple underscores are found in a row or if an underscore is +// found at the end of the number, then the invalid pointer is set to the index +// of the first invalid underscore. size_t -yp_strspn_binary_number(const uint8_t *string, ptrdiff_t length) { - return yp_strspn_number_kind(string, length, YP_NUMBER_BIT_BINARY_NUMBER); +yp_strspn_binary_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid) { + return yp_strspn_number_kind_underscores(string, length, invalid, YP_NUMBER_BIT_BINARY_NUMBER); } // Returns the number of characters at the start of the string that are octal -// digits or underscores. Disallows searching past the given maximum number of +// digits or underscores. Disallows searching past the given maximum number of // characters. +// +// If multiple underscores are found in a row or if an underscore is +// found at the end of the number, then the invalid pointer is set to the index +// of the first invalid underscore. size_t -yp_strspn_octal_number(const uint8_t *string, ptrdiff_t length) { - return yp_strspn_number_kind(string, length, YP_NUMBER_BIT_OCTAL_NUMBER); +yp_strspn_octal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid) { + return yp_strspn_number_kind_underscores(string, length, invalid, YP_NUMBER_BIT_OCTAL_NUMBER); } // Returns the number of characters at the start of the string that are decimal @@ -165,9 +200,13 @@ yp_strspn_decimal_digit(const uint8_t *string, ptrdiff_t length) { // Returns the number of characters at the start of the string that are decimal // digits or underscores. Disallows searching past the given maximum number of // characters. +// +// If multiple underscores are found in a row or if an underscore is +// found at the end of the number, then the invalid pointer is set to the index +// of the first invalid underscore. size_t -yp_strspn_decimal_number(const uint8_t *string, ptrdiff_t length) { - return yp_strspn_number_kind(string, length, YP_NUMBER_BIT_DECIMAL_NUMBER); +yp_strspn_decimal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid) { + return yp_strspn_number_kind_underscores(string, length, invalid, YP_NUMBER_BIT_DECIMAL_NUMBER); } // Returns the number of characters at the start of the string that are @@ -181,9 +220,13 @@ yp_strspn_hexadecimal_digit(const uint8_t *string, ptrdiff_t length) { // Returns the number of characters at the start of the string that are // hexadecimal digits or underscores. Disallows searching past the given maximum // number of characters. +// +// If multiple underscores are found in a row or if an underscore is +// found at the end of the number, then the invalid pointer is set to the index +// of the first invalid underscore. size_t -yp_strspn_hexadecimal_number(const uint8_t *string, ptrdiff_t length) { - return yp_strspn_number_kind(string, length, YP_NUMBER_BIT_HEXADECIMAL_NUMBER); +yp_strspn_hexadecimal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid) { + return yp_strspn_number_kind_underscores(string, length, invalid, YP_NUMBER_BIT_HEXADECIMAL_NUMBER); } static inline bool diff --git a/src/main/c/yarp/src/util/yp_constant_pool.c b/src/main/c/yarp/src/util/yp_constant_pool.c index 3ad241a9d1bb..18376dce8221 100644 --- a/src/main/c/yarp/src/util/yp_constant_pool.c +++ b/src/main/c/yarp/src/util/yp_constant_pool.c @@ -47,10 +47,10 @@ yp_constant_id_list_free(yp_constant_id_list_t *list) { // A relatively simple hash function (djb2) that is used to hash strings. We are // optimizing here for simplicity and speed. -static inline size_t +static inline uint32_t yp_constant_pool_hash(const uint8_t *start, size_t length) { // This is a prime number used as the initial value for the hash function. - size_t value = 5381; + uint32_t value = 5381; for (size_t index = 0; index < length; index++) { value = ((value << 5) + value) + start[index]; @@ -59,28 +59,58 @@ yp_constant_pool_hash(const uint8_t *start, size_t length) { return value; } +// https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 +static uint32_t +next_power_of_two(uint32_t v) { + // Avoid underflow in subtraction on next line. + if (v == 0) { + // 1 is the nearest power of 2 to 0 (2^0) + return 1; + } + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + return v; +} + +#ifndef NDEBUG +static bool +is_power_of_two(uint32_t size) { + return (size & (size - 1)) == 0; +} +#endif + // Resize a constant pool to a given capacity. static inline bool yp_constant_pool_resize(yp_constant_pool_t *pool) { - size_t next_capacity = pool->capacity * 2; + assert(is_power_of_two(pool->capacity)); + + uint32_t next_capacity = pool->capacity * 2; + if (next_capacity < pool->capacity) return false; + + const uint32_t mask = next_capacity - 1; yp_constant_t *next_constants = calloc(next_capacity, sizeof(yp_constant_t)); if (next_constants == NULL) return false; // For each constant in the current constant pool, rehash the content, find // the index in the next constant pool, and insert it. - for (size_t index = 0; index < pool->capacity; index++) { + for (uint32_t index = 0; index < pool->capacity; index++) { yp_constant_t *constant = &pool->constants[index]; // If an id is set on this constant, then we know we have content here. // In this case we need to insert it into the next constant pool. if (constant->id != 0) { - size_t next_index = constant->hash % next_capacity; + uint32_t next_index = constant->hash & mask; // This implements linear scanning to find the next available slot // in case this index is already taken. We don't need to bother // comparing the values since we know that the hash is unique. while (next_constants[next_index].id != 0) { - next_index = (next_index + 1) % next_capacity; + next_index = (next_index + 1) & mask; } // Here we copy over the entire constant, which includes the id so @@ -97,7 +127,11 @@ yp_constant_pool_resize(yp_constant_pool_t *pool) { // Initialize a new constant pool with a given capacity. bool -yp_constant_pool_init(yp_constant_pool_t *pool, size_t capacity) { +yp_constant_pool_init(yp_constant_pool_t *pool, uint32_t capacity) { + const uint32_t maximum = (~((uint32_t) 0)); + if (capacity >= ((maximum / 2) + 1)) return false; + + capacity = next_power_of_two(capacity); pool->constants = calloc(capacity, sizeof(yp_constant_t)); if (pool->constants == NULL) return false; @@ -106,16 +140,18 @@ yp_constant_pool_init(yp_constant_pool_t *pool, size_t capacity) { return true; } -// Insert a constant into a constant pool. Returns the id of the constant, or 0 -// if any potential calls to resize fail. -yp_constant_id_t -yp_constant_pool_insert(yp_constant_pool_t *pool, const uint8_t *start, size_t length) { +// Insert a constant into a constant pool and return its index in the pool. +static inline yp_constant_id_t +yp_constant_pool_insert(yp_constant_pool_t *pool, const uint8_t *start, size_t length, bool owned) { if (pool->size >= (pool->capacity / 4 * 3)) { if (!yp_constant_pool_resize(pool)) return 0; } - size_t hash = yp_constant_pool_hash(start, length); - size_t index = hash % pool->capacity; + assert(is_power_of_two(pool->capacity)); + const uint32_t mask = pool->capacity - 1; + + uint32_t hash = yp_constant_pool_hash(start, length); + uint32_t index = hash & mask; yp_constant_t *constant; while (constant = &pool->constants[index], constant->id != 0) { @@ -123,25 +159,72 @@ yp_constant_pool_insert(yp_constant_pool_t *pool, const uint8_t *start, size_t l // same as the content we are trying to insert. If it is, then we can // return the id of the existing constant. if ((constant->length == length) && memcmp(constant->start, start, length) == 0) { - return pool->constants[index].id; + // Since we have found a match, we need to check if this is + // attempting to insert a shared or an owned constant. We want to + // prefer shared constants since they don't require allocations. + if (owned) { + // If we're attempting to insert an owned constant and we have + // an existing constant, then either way we don't want the given + // memory. Either it's duplicated with the existing constant or + // it's not necessary because we have a shared version. + free((void *) start); + } else if (constant->owned) { + // If we're attempting to insert a shared constant and the + // existing constant is owned, then we can free the owned + // constant and replace it with the shared constant. + free((void *) constant->start); + constant->start = start; + constant->owned = false; + } + + return constant->id; } - index = (index + 1) % pool->capacity; + index = (index + 1) & mask; } - yp_constant_id_t id = (yp_constant_id_t)++pool->size; - pool->constants[index] = (yp_constant_t) { - .id = id, + pool->size++; + assert(pool->size < ((uint32_t) (1 << 31))); + + *constant = (yp_constant_t) { + .id = (unsigned int) (pool->size & 0x7FFFFFFF), + .owned = owned, .start = start, .length = length, .hash = hash }; - return id; + return constant->id; +} + +// Insert a constant into a constant pool. Returns the id of the constant, or 0 +// if any potential calls to resize fail. +yp_constant_id_t +yp_constant_pool_insert_shared(yp_constant_pool_t *pool, const uint8_t *start, size_t length) { + return yp_constant_pool_insert(pool, start, length, false); +} + +// Insert a constant into a constant pool from memory that is now owned by the +// constant pool. Returns the id of the constant, or 0 if any potential calls to +// resize fail. +yp_constant_id_t +yp_constant_pool_insert_owned(yp_constant_pool_t *pool, const uint8_t *start, size_t length) { + return yp_constant_pool_insert(pool, start, length, true); } // Free the memory associated with a constant pool. void yp_constant_pool_free(yp_constant_pool_t *pool) { + // For each constant in the current constant pool, free the contents if the + // contents are owned. + for (uint32_t index = 0; index < pool->capacity; index++) { + yp_constant_t *constant = &pool->constants[index]; + + // If an id is set on this constant, then we know we have content here. + if (constant->id != 0 && constant->owned) { + free((void *) constant->start); + } + } + free(pool->constants); } diff --git a/src/main/c/yarp/src/yarp.c b/src/main/c/yarp/src/yarp.c index 45c26471bbb9..ddaecc2c8446 100644 --- a/src/main/c/yarp/src/yarp.c +++ b/src/main/c/yarp/src/yarp.c @@ -428,7 +428,13 @@ debug_lex_state_set(yp_parser_t *parser, yp_lex_state_t state, char const * call // Retrieve the constant pool id for the given location. static inline yp_constant_id_t yp_parser_constant_id_location(yp_parser_t *parser, const uint8_t *start, const uint8_t *end) { - return yp_constant_pool_insert(&parser->constant_pool, start, (size_t) (end - start)); + return yp_constant_pool_insert_shared(&parser->constant_pool, start, (size_t) (end - start)); +} + +// Retrieve the constant pool id for the given string. +static inline yp_constant_id_t +yp_parser_constant_id_owned(yp_parser_t *parser, const uint8_t *start, size_t length) { + return yp_constant_pool_insert_owned(&parser->constant_pool, start, length); } // Retrieve the constant pool id for the given token. @@ -437,48 +443,79 @@ yp_parser_constant_id_token(yp_parser_t *parser, const yp_token_t *token) { return yp_parser_constant_id_location(parser, token->start, token->end); } -// Mark any range nodes in this subtree as flipflops. +// Retrieve the constant pool id for the given token. If the token is not +// provided, then return 0. +static inline yp_constant_id_t +yp_parser_optional_constant_id_token(yp_parser_t *parser, const yp_token_t *token) { + return token->type == YP_TOKEN_NOT_PROVIDED ? 0 : yp_parser_constant_id_token(parser, token); +} + +// The predicate of conditional nodes can change what would otherwise be regular +// nodes into specialized nodes. For example: +// +// if foo .. bar => RangeNode becomes FlipFlopNode +// if foo and bar .. baz => RangeNode becomes FlipFlopNode +// if /foo/ => RegularExpressionNode becomes MatchLastLineNode +// if /foo #{bar}/ => InterpolatedRegularExpressionNode becomes InterpolatedMatchLastLineNode +// static void -yp_flip_flop(yp_node_t *node) { +yp_conditional_predicate(yp_node_t *node) { switch (YP_NODE_TYPE(node)) { - case YP_NODE_AND_NODE: { + case YP_AND_NODE: { yp_and_node_t *cast = (yp_and_node_t *) node; - yp_flip_flop(cast->left); - yp_flip_flop(cast->right); + yp_conditional_predicate(cast->left); + yp_conditional_predicate(cast->right); break; } - case YP_NODE_OR_NODE: { + case YP_OR_NODE: { yp_or_node_t *cast = (yp_or_node_t *) node; - yp_flip_flop(cast->left); - yp_flip_flop(cast->right); + yp_conditional_predicate(cast->left); + yp_conditional_predicate(cast->right); break; } - case YP_NODE_PARENTHESES_NODE: { + case YP_PARENTHESES_NODE: { yp_parentheses_node_t *cast = (yp_parentheses_node_t *) node; - if ((cast->body != NULL) && YP_NODE_TYPE_P(cast->body, YP_NODE_STATEMENTS_NODE)) { + if ((cast->body != NULL) && YP_NODE_TYPE_P(cast->body, YP_STATEMENTS_NODE)) { yp_statements_node_t *statements = (yp_statements_node_t *) cast->body; - if (statements->body.size == 1) yp_flip_flop(statements->body.nodes[0]); + if (statements->body.size == 1) yp_conditional_predicate(statements->body.nodes[0]); } break; } - case YP_NODE_RANGE_NODE: { + case YP_RANGE_NODE: { yp_range_node_t *cast = (yp_range_node_t *) node; if (cast->left) { - yp_flip_flop(cast->left); + yp_conditional_predicate(cast->left); } if (cast->right) { - yp_flip_flop(cast->right); + yp_conditional_predicate(cast->right); } // Here we change the range node into a flip flop node. We can do // this since the nodes are exactly the same except for the type. + // We're only asserting against the size when we should probably + // assert against the entire layout, but we'll assume tests will + // catch this. assert(sizeof(yp_range_node_t) == sizeof(yp_flip_flop_node_t)); - node->type = YP_NODE_FLIP_FLOP_NODE; + node->type = YP_FLIP_FLOP_NODE; break; } + case YP_REGULAR_EXPRESSION_NODE: + // Here we change the regular expression node into a match last line + // node. We can do this since the nodes are exactly the same except + // for the type. + assert(sizeof(yp_regular_expression_node_t) == sizeof(yp_match_last_line_node_t)); + node->type = YP_MATCH_LAST_LINE_NODE; + break; + case YP_INTERPOLATED_REGULAR_EXPRESSION_NODE: + // Here we change the interpolated regular expression node into an + // interpolated match last line node. We can do this since the nodes + // are exactly the same except for the type. + assert(sizeof(yp_interpolated_regular_expression_node_t) == sizeof(yp_interpolated_match_last_line_node_t)); + node->type = YP_INTERPOLATED_MATCH_LAST_LINE_NODE; + break; default: break; } @@ -503,7 +540,6 @@ not_provided(yp_parser_t *parser) { #define YP_LOCATION_NODE_BASE_VALUE(node) ((yp_location_t) { .start = (node)->base.location.start, .end = (node)->base.location.end }) #define YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE ((yp_location_t) { .start = NULL, .end = NULL }) #define YP_OPTIONAL_LOCATION_TOKEN_VALUE(token) ((token)->type == YP_TOKEN_NOT_PROVIDED ? YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE : YP_LOCATION_TOKEN_VALUE(token)) -#define YP_TOKEN_NOT_PROVIDED_VALUE(parser) ((yp_token_t) { .type = YP_TOKEN_NOT_PROVIDED, .start = (parser)->start, .end = (parser)->start }) // This is a special out parameter to the parse_arguments_list function that // includes opening and closing parentheses in addition to the arguments since @@ -513,11 +549,7 @@ typedef struct { yp_location_t opening_loc; yp_arguments_node_t *arguments; yp_location_t closing_loc; - yp_block_node_t *block; - - // This boolean is used to tell if there is an implicit block (i.e., an - // argument passed with an & operator). - bool implicit_block; + yp_node_t *block; } yp_arguments_t; #define YP_EMPTY_ARGUMENTS ((yp_arguments_t) { \ @@ -525,21 +557,37 @@ typedef struct { .arguments = NULL, \ .closing_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE, \ .block = NULL, \ - .implicit_block = false \ }) -// Check that the set of arguments parsed for a given node is valid. This means -// checking that we don't have both an implicit and explicit block. +// Check that we're not about to attempt to attach a brace block to a call that +// has arguments without parentheses. static void -yp_arguments_validate(yp_parser_t *parser, yp_arguments_t *arguments) { - if (arguments->block != NULL && arguments->implicit_block) { - yp_diagnostic_list_append( - &parser->error_list, - arguments->block->base.location.start, - arguments->block->base.location.end, - "both block arg and actual block given" - ); +yp_arguments_validate_block(yp_parser_t *parser, yp_arguments_t *arguments, yp_block_node_t *block) { + // First, check that we have arguments and that we don't have a closing + // location for them. + if (arguments->arguments == NULL || arguments->closing_loc.start != NULL) { + return; + } + + // Next, check that we don't have a single parentheses argument. This would + // look like: + // + // foo (1) {} + // + // In this case, it's actually okay for the block to be attached to the + // call, even though it looks like it's attached to the argument. + if (arguments->arguments->arguments.size == 1 && YP_NODE_TYPE_P(arguments->arguments->arguments.nodes[0], YP_PARENTHESES_NODE)) { + return; } + + // If we didn't hit a case before this check, then at this point we need to + // add a syntax error. + yp_diagnostic_list_append( + &parser->error_list, + block->base.location.start, + block->base.location.end, + YP_ERR_ARGUMENT_UNEXPECTED_BLOCK + ); } /******************************************************************************/ @@ -549,7 +597,7 @@ yp_arguments_validate(yp_parser_t *parser, yp_arguments_t *arguments) { // Generate a scope node from the given node. void yp_scope_node_init(yp_node_t *node, yp_scope_node_t *scope) { - scope->base.type = YP_NODE_SCOPE_NODE; + scope->base.type = YP_SCOPE_NODE; scope->base.location.start = node->location.start; scope->base.location.end = node->location.end; @@ -558,46 +606,46 @@ yp_scope_node_init(yp_node_t *node, yp_scope_node_t *scope) { yp_constant_id_list_init(&scope->locals); switch (YP_NODE_TYPE(node)) { - case YP_NODE_BLOCK_NODE: { + case YP_BLOCK_NODE: { yp_block_node_t *cast = (yp_block_node_t *) node; if (cast->parameters) scope->parameters = cast->parameters->parameters; scope->body = cast->body; scope->locals = cast->locals; break; } - case YP_NODE_CLASS_NODE: { + case YP_CLASS_NODE: { yp_class_node_t *cast = (yp_class_node_t *) node; scope->body = cast->body; scope->locals = cast->locals; break; } - case YP_NODE_DEF_NODE: { + case YP_DEF_NODE: { yp_def_node_t *cast = (yp_def_node_t *) node; scope->parameters = cast->parameters; scope->body = cast->body; scope->locals = cast->locals; break; } - case YP_NODE_LAMBDA_NODE: { + case YP_LAMBDA_NODE: { yp_lambda_node_t *cast = (yp_lambda_node_t *) node; if (cast->parameters) scope->parameters = cast->parameters->parameters; scope->body = cast->body; scope->locals = cast->locals; break; } - case YP_NODE_MODULE_NODE: { + case YP_MODULE_NODE: { yp_module_node_t *cast = (yp_module_node_t *) node; scope->body = cast->body; scope->locals = cast->locals; break; } - case YP_NODE_PROGRAM_NODE: { + case YP_PROGRAM_NODE: { yp_program_node_t *cast = (yp_program_node_t *) node; scope->body = (yp_node_t *) cast->statements; scope->locals = cast->locals; break; } - case YP_NODE_SINGLETON_CLASS_NODE: { + case YP_SINGLETON_CLASS_NODE: { yp_singleton_class_node_t *cast = (yp_singleton_class_node_t *) node; scope->body = cast->body; scope->locals = cast->locals; @@ -631,14 +679,14 @@ parse_decimal_number(yp_parser_t *parser, const uint8_t *start, const uint8_t *e unsigned long value = strtoul(digits, &endptr, 10); if ((digits == endptr) || (*endptr != '\0') || (errno == ERANGE)) { - yp_diagnostic_list_append(&parser->error_list, start, end, "invalid decimal number"); + yp_diagnostic_list_append(&parser->error_list, start, end, YP_ERR_INVALID_NUMBER_DECIMAL); value = UINT32_MAX; } free(digits); if (value > UINT32_MAX) { - yp_diagnostic_list_append(&parser->error_list, start, end, "invalid decimal number"); + yp_diagnostic_list_append(&parser->error_list, start, end, YP_ERR_INVALID_NUMBER_DECIMAL); value = UINT32_MAX; } @@ -695,19 +743,41 @@ yp_alloc_node(YP_ATTRIBUTE_UNUSED yp_parser_t *parser, size_t size) { static yp_missing_node_t * yp_missing_node_create(yp_parser_t *parser, const uint8_t *start, const uint8_t *end) { yp_missing_node_t *node = YP_ALLOC_NODE(parser, yp_missing_node_t); - *node = (yp_missing_node_t) {{ .type = YP_NODE_MISSING_NODE, .location = { .start = start, .end = end } }}; + *node = (yp_missing_node_t) {{ .type = YP_MISSING_NODE, .location = { .start = start, .end = end } }}; + return node; +} + +// Allocate and initialize a new AliasGlobalVariableNode node. +static yp_alias_global_variable_node_t * +yp_alias_global_variable_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t *new_name, yp_node_t *old_name) { + assert(keyword->type == YP_TOKEN_KEYWORD_ALIAS); + yp_alias_global_variable_node_t *node = YP_ALLOC_NODE(parser, yp_alias_global_variable_node_t); + + *node = (yp_alias_global_variable_node_t) { + { + .type = YP_ALIAS_GLOBAL_VARIABLE_NODE, + .location = { + .start = keyword->start, + .end = old_name->location.end + }, + }, + .new_name = new_name, + .old_name = old_name, + .keyword_loc = YP_LOCATION_TOKEN_VALUE(keyword) + }; + return node; } -// Allocate and initialize a new alias node. -static yp_alias_node_t * -yp_alias_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t *new_name, yp_node_t *old_name) { +// Allocate and initialize a new AliasMethodNode node. +static yp_alias_method_node_t * +yp_alias_method_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t *new_name, yp_node_t *old_name) { assert(keyword->type == YP_TOKEN_KEYWORD_ALIAS); - yp_alias_node_t *node = YP_ALLOC_NODE(parser, yp_alias_node_t); + yp_alias_method_node_t *node = YP_ALLOC_NODE(parser, yp_alias_method_node_t); - *node = (yp_alias_node_t) { + *node = (yp_alias_method_node_t) { { - .type = YP_NODE_ALIAS_NODE, + .type = YP_ALIAS_METHOD_NODE, .location = { .start = keyword->start, .end = old_name->location.end @@ -728,7 +798,7 @@ yp_alternation_pattern_node_create(yp_parser_t *parser, yp_node_t *left, yp_node *node = (yp_alternation_pattern_node_t) { { - .type = YP_NODE_ALTERNATION_PATTERN_NODE, + .type = YP_ALTERNATION_PATTERN_NODE, .location = { .start = left->location.start, .end = right->location.end @@ -749,7 +819,7 @@ yp_and_node_create(yp_parser_t *parser, yp_node_t *left, const yp_token_t *opera *node = (yp_and_node_t) { { - .type = YP_NODE_AND_NODE, + .type = YP_AND_NODE, .location = { .start = left->location.start, .end = right->location.end @@ -770,7 +840,7 @@ yp_arguments_node_create(yp_parser_t *parser) { *node = (yp_arguments_node_t) { { - .type = YP_NODE_ARGUMENTS_NODE, + .type = YP_ARGUMENTS_NODE, .location = YP_LOCATION_NULL_VALUE(parser) }, .arguments = YP_EMPTY_NODE_LIST @@ -803,11 +873,8 @@ yp_array_node_create(yp_parser_t *parser, const yp_token_t *opening) { *node = (yp_array_node_t) { { - .type = YP_NODE_ARRAY_NODE, - .location = { - .start = opening->start, - .end = opening->end - }, + .type = YP_ARRAY_NODE, + .location = YP_LOCATION_TOKEN_VALUE(opening) }, .opening_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(opening), .closing_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(opening), @@ -849,7 +916,7 @@ yp_array_pattern_node_node_list_create(yp_parser_t *parser, yp_node_list_t *node *node = (yp_array_pattern_node_t) { { - .type = YP_NODE_ARRAY_PATTERN_NODE, + .type = YP_ARRAY_PATTERN_NODE, .location = { .start = nodes->nodes[0]->location.start, .end = nodes->nodes[nodes->size - 1]->location.end @@ -869,7 +936,7 @@ yp_array_pattern_node_node_list_create(yp_parser_t *parser, yp_node_list_t *node for (size_t index = 0; index < nodes->size; index++) { yp_node_t *child = nodes->nodes[index]; - if (!found_rest && YP_NODE_TYPE_P(child, YP_NODE_SPLAT_NODE)) { + if (!found_rest && YP_NODE_TYPE_P(child, YP_SPLAT_NODE)) { node->rest = child; found_rest = true; } else if (found_rest) { @@ -889,7 +956,7 @@ yp_array_pattern_node_rest_create(yp_parser_t *parser, yp_node_t *rest) { *node = (yp_array_pattern_node_t) { { - .type = YP_NODE_ARRAY_PATTERN_NODE, + .type = YP_ARRAY_PATTERN_NODE, .location = rest->location, }, .constant = NULL, @@ -911,7 +978,7 @@ yp_array_pattern_node_constant_create(yp_parser_t *parser, yp_node_t *constant, *node = (yp_array_pattern_node_t) { { - .type = YP_NODE_ARRAY_PATTERN_NODE, + .type = YP_ARRAY_PATTERN_NODE, .location = { .start = constant->location.start, .end = closing->end @@ -936,7 +1003,7 @@ yp_array_pattern_node_empty_create(yp_parser_t *parser, const yp_token_t *openin *node = (yp_array_pattern_node_t) { { - .type = YP_NODE_ARRAY_PATTERN_NODE, + .type = YP_ARRAY_PATTERN_NODE, .location = { .start = opening->start, .end = closing->end @@ -974,7 +1041,7 @@ yp_assoc_node_create(yp_parser_t *parser, yp_node_t *key, const yp_token_t *oper *node = (yp_assoc_node_t) { { - .type = YP_NODE_ASSOC_NODE, + .type = YP_ASSOC_NODE, .location = { .start = key->location.start, .end = end @@ -996,7 +1063,7 @@ yp_assoc_splat_node_create(yp_parser_t *parser, yp_node_t *value, const yp_token *node = (yp_assoc_splat_node_t) { { - .type = YP_NODE_ASSOC_SPLAT_NODE, + .type = YP_ASSOC_SPLAT_NODE, .location = { .start = operator->start, .end = value == NULL ? operator->end : value->location.end @@ -1017,7 +1084,7 @@ yp_back_reference_read_node_create(yp_parser_t *parser, const yp_token_t *name) *node = (yp_back_reference_read_node_t) { { - .type = YP_NODE_BACK_REFERENCE_READ_NODE, + .type = YP_BACK_REFERENCE_READ_NODE, .location = YP_LOCATION_TOKEN_VALUE(name), } }; @@ -1032,7 +1099,7 @@ yp_begin_node_create(yp_parser_t *parser, const yp_token_t *begin_keyword, yp_st *node = (yp_begin_node_t) { { - .type = YP_NODE_BEGIN_NODE, + .type = YP_BEGIN_NODE, .location = { .start = begin_keyword->start, .end = statements == NULL ? begin_keyword->end : statements->base.location.end @@ -1087,7 +1154,7 @@ yp_block_argument_node_create(yp_parser_t *parser, const yp_token_t *operator, y *node = (yp_block_argument_node_t) { { - .type = YP_NODE_BLOCK_ARGUMENT_NODE, + .type = YP_BLOCK_ARGUMENT_NODE, .location = { .start = operator->start, .end = expression == NULL ? operator->end : expression->location.end @@ -1107,7 +1174,7 @@ yp_block_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const y *node = (yp_block_node_t) { { - .type = YP_NODE_BLOCK_NODE, + .type = YP_BLOCK_NODE, .location = { .start = opening->start, .end = closing->end }, }, .locals = *locals, @@ -1128,12 +1195,13 @@ yp_block_parameter_node_create(yp_parser_t *parser, const yp_token_t *name, cons *node = (yp_block_parameter_node_t) { { - .type = YP_NODE_BLOCK_PARAMETER_NODE, + .type = YP_BLOCK_PARAMETER_NODE, .location = { .start = operator->start, .end = (name->type == YP_TOKEN_NOT_PROVIDED ? operator->end : name->end) }, }, + .name = yp_parser_optional_constant_id_token(parser, name), .name_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(name), .operator_loc = YP_LOCATION_TOKEN_VALUE(operator) }; @@ -1166,7 +1234,7 @@ yp_block_parameters_node_create(yp_parser_t *parser, yp_parameters_node_t *param *node = (yp_block_parameters_node_t) { { - .type = YP_NODE_BLOCK_PARAMETERS_NODE, + .type = YP_BLOCK_PARAMETERS_NODE, .location = { .start = start, .end = end @@ -1174,8 +1242,8 @@ yp_block_parameters_node_create(yp_parser_t *parser, yp_parameters_node_t *param }, .parameters = parameters, .opening_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(opening), - .closing_loc = { .start = NULL, .end = NULL }, - .locals = YP_EMPTY_LOCATION_LIST + .closing_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE, + .locals = YP_EMPTY_NODE_LIST }; return node; @@ -1190,14 +1258,30 @@ yp_block_parameters_node_closing_set(yp_block_parameters_node_t *node, const yp_ node->closing_loc = YP_LOCATION_TOKEN_VALUE(closing); } +// Allocate and initialize a new BlockLocalVariableNode node. +static yp_block_local_variable_node_t * +yp_block_local_variable_node_create(yp_parser_t *parser, const yp_token_t *name) { + assert(name->type == YP_TOKEN_IDENTIFIER || name->type == YP_TOKEN_MISSING); + yp_block_local_variable_node_t *node = YP_ALLOC_NODE(parser, yp_block_local_variable_node_t); + + *node = (yp_block_local_variable_node_t) { + { + .type = YP_BLOCK_LOCAL_VARIABLE_NODE, + .location = YP_LOCATION_TOKEN_VALUE(name), + }, + .name = yp_parser_constant_id_token(parser, name) + }; + + return node; +} + // Append a new block-local variable to a BlockParametersNode node. static void -yp_block_parameters_node_append_local(yp_block_parameters_node_t *node, const yp_token_t *local) { - assert(local->type == YP_TOKEN_IDENTIFIER || local->type == YP_TOKEN_MISSING); +yp_block_parameters_node_append_local(yp_block_parameters_node_t *node, const yp_block_local_variable_node_t *local) { + yp_node_list_append(&node->locals, (yp_node_t *) local); - yp_location_list_append(&node->locals, local); - if (node->base.location.start == NULL) node->base.location.start = local->start; - node->base.location.end = local->end; + if (node->base.location.start == NULL) node->base.location.start = local->base.location.start; + node->base.location.end = local->base.location.end; } // Allocate and initialize a new BreakNode node. @@ -1208,7 +1292,7 @@ yp_break_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_argument *node = (yp_break_node_t) { { - .type = YP_NODE_BREAK_NODE, + .type = YP_BREAK_NODE, .location = { .start = keyword->start, .end = (arguments == NULL ? keyword->end : arguments->base.location.end) @@ -1230,11 +1314,11 @@ yp_call_node_create(yp_parser_t *parser) { *node = (yp_call_node_t) { { - .type = YP_NODE_CALL_NODE, + .type = YP_CALL_NODE, .location = YP_LOCATION_NULL_VALUE(parser), }, .receiver = NULL, - .operator_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE, + .call_operator_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE, .message_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE, .opening_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE, .arguments = NULL, @@ -1253,7 +1337,7 @@ yp_call_node_aref_create(yp_parser_t *parser, yp_node_t *receiver, yp_arguments_ node->base.location.start = receiver->location.start; if (arguments->block != NULL) { - node->base.location.end = arguments->block->base.location.end; + node->base.location.end = arguments->block->location.end; } else { node->base.location.end = arguments->closing_loc.end; } @@ -1297,7 +1381,7 @@ yp_call_node_call_create(yp_parser_t *parser, yp_node_t *receiver, yp_token_t *o node->base.location.start = receiver->location.start; if (arguments->block != NULL) { - node->base.location.end = arguments->block->base.location.end; + node->base.location.end = arguments->block->location.end; } else if (arguments->closing_loc.start != NULL) { node->base.location.end = arguments->closing_loc.end; } else if (arguments->arguments != NULL) { @@ -1307,7 +1391,7 @@ yp_call_node_call_create(yp_parser_t *parser, yp_node_t *receiver, yp_token_t *o } node->receiver = receiver; - node->operator_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(operator); + node->call_operator_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(operator); node->message_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(message); node->opening_loc = arguments->opening_loc; node->arguments = arguments->arguments; @@ -1330,7 +1414,7 @@ yp_call_node_fcall_create(yp_parser_t *parser, yp_token_t *message, yp_arguments node->base.location.start = message->start; if (arguments->block != NULL) { - node->base.location.end = arguments->block->base.location.end; + node->base.location.end = arguments->block->location.end; } else if (arguments->closing_loc.start != NULL) { node->base.location.end = arguments->closing_loc.end; } else if (arguments->arguments != NULL) { @@ -1378,13 +1462,13 @@ yp_call_node_shorthand_create(yp_parser_t *parser, yp_node_t *receiver, yp_token node->base.location.start = receiver->location.start; if (arguments->block != NULL) { - node->base.location.end = arguments->block->base.location.end; + node->base.location.end = arguments->block->location.end; } else { node->base.location.end = arguments->closing_loc.end; } node->receiver = receiver; - node->operator_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(operator); + node->call_operator_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(operator); node->opening_loc = arguments->opening_loc; node->arguments = arguments->arguments; node->closing_loc = arguments->closing_loc; @@ -1419,9 +1503,7 @@ static yp_call_node_t * yp_call_node_variable_call_create(yp_parser_t *parser, yp_token_t *message) { yp_call_node_t *node = yp_call_node_create(parser); - node->base.location.start = message->start; - node->base.location.end = message->end; - + node->base.location = YP_LOCATION_TOKEN_VALUE(message); node->message_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(message); yp_string_shared_init(&node->name, message->start, message->end); @@ -1435,69 +1517,133 @@ yp_call_node_variable_call_p(yp_call_node_t *node) { return node->base.flags & YP_CALL_NODE_FLAGS_VARIABLE_CALL; } -// Allocate and initialize a new CallOperatorAndWriteNode node. -static yp_call_operator_and_write_node_t * -yp_call_operator_and_write_node_create(yp_parser_t *parser, yp_call_node_t *target, const yp_token_t *operator, yp_node_t *value) { +// Initialize the read name by reading the write name and chopping off the '='. +static void +yp_call_write_read_name_init(yp_string_t *read_name, yp_string_t *write_name) { + if (write_name->length >= 1) { + size_t length = write_name->length - 1; + + void *memory = malloc(length); + memcpy(memory, write_name->source, length); + + yp_string_owned_init(read_name, (uint8_t *) memory, length); + } else { + // We can get here if the message was missing because of a syntax error. + yp_string_constant_init(read_name, "", 0); + } +} + +// Allocate and initialize a new CallAndWriteNode node. +static yp_call_and_write_node_t * +yp_call_and_write_node_create(yp_parser_t *parser, yp_call_node_t *target, const yp_token_t *operator, yp_node_t *value) { + assert(target->block == NULL); assert(operator->type == YP_TOKEN_AMPERSAND_AMPERSAND_EQUAL); - yp_call_operator_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_call_operator_and_write_node_t); + yp_call_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_call_and_write_node_t); - *node = (yp_call_operator_and_write_node_t) { + *node = (yp_call_and_write_node_t) { { - .type = YP_NODE_CALL_OPERATOR_AND_WRITE_NODE, + .type = YP_CALL_AND_WRITE_NODE, + .flags = target->base.flags, .location = { .start = target->base.location.start, .end = value->location.end } }, - .target = target, + .receiver = target->receiver, + .call_operator_loc = target->call_operator_loc, + .message_loc = target->message_loc, + .opening_loc = target->opening_loc, + .arguments = target->arguments, + .closing_loc = target->closing_loc, + .read_name = YP_EMPTY_STRING, + .write_name = target->name, .operator_loc = YP_LOCATION_TOKEN_VALUE(operator), .value = value }; + yp_call_write_read_name_init(&node->read_name, &node->write_name); + + // Here we're going to free the target, since it is no longer necessary. + // However, we don't want to call `yp_node_destroy` because we want to keep + // around all of its children since we just reused them. + free(target); + return node; } // Allocate a new CallOperatorWriteNode node. static yp_call_operator_write_node_t * yp_call_operator_write_node_create(yp_parser_t *parser, yp_call_node_t *target, const yp_token_t *operator, yp_node_t *value) { + assert(target->block == NULL); yp_call_operator_write_node_t *node = YP_ALLOC_NODE(parser, yp_call_operator_write_node_t); *node = (yp_call_operator_write_node_t) { { - .type = YP_NODE_CALL_OPERATOR_WRITE_NODE, + .type = YP_CALL_OPERATOR_WRITE_NODE, + .flags = target->base.flags, .location = { .start = target->base.location.start, .end = value->location.end } }, - .target = target, + .receiver = target->receiver, + .call_operator_loc = target->call_operator_loc, + .message_loc = target->message_loc, + .opening_loc = target->opening_loc, + .arguments = target->arguments, + .closing_loc = target->closing_loc, + .read_name = YP_EMPTY_STRING, + .write_name = target->name, + .operator = yp_parser_constant_id_location(parser, operator->start, operator->end - 1), .operator_loc = YP_LOCATION_TOKEN_VALUE(operator), - .value = value, - .operator = yp_parser_constant_id_location(parser, operator->start, operator->end - 1) + .value = value }; + yp_call_write_read_name_init(&node->read_name, &node->write_name); + + // Here we're going to free the target, since it is no longer necessary. + // However, we don't want to call `yp_node_destroy` because we want to keep + // around all of its children since we just reused them. + free(target); + return node; } // Allocate and initialize a new CallOperatorOrWriteNode node. -static yp_call_operator_or_write_node_t * -yp_call_operator_or_write_node_create(yp_parser_t *parser, yp_call_node_t *target, const yp_token_t *operator, yp_node_t *value) { +static yp_call_or_write_node_t * +yp_call_or_write_node_create(yp_parser_t *parser, yp_call_node_t *target, const yp_token_t *operator, yp_node_t *value) { + assert(target->block == NULL); assert(operator->type == YP_TOKEN_PIPE_PIPE_EQUAL); - yp_call_operator_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_call_operator_or_write_node_t); + yp_call_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_call_or_write_node_t); - *node = (yp_call_operator_or_write_node_t) { + *node = (yp_call_or_write_node_t) { { - .type = YP_NODE_CALL_OPERATOR_OR_WRITE_NODE, + .type = YP_CALL_OR_WRITE_NODE, + .flags = target->base.flags, .location = { .start = target->base.location.start, .end = value->location.end } }, - .target = target, + .receiver = target->receiver, + .call_operator_loc = target->call_operator_loc, + .message_loc = target->message_loc, + .opening_loc = target->opening_loc, + .arguments = target->arguments, + .closing_loc = target->closing_loc, + .read_name = YP_EMPTY_STRING, + .write_name = target->name, .operator_loc = YP_LOCATION_TOKEN_VALUE(operator), .value = value }; + yp_call_write_read_name_init(&node->read_name, &node->write_name); + + // Here we're going to free the target, since it is no longer necessary. + // However, we don't want to call `yp_node_destroy` because we want to keep + // around all of its children since we just reused them. + free(target); + return node; } @@ -1508,7 +1654,7 @@ yp_capture_pattern_node_create(yp_parser_t *parser, yp_node_t *value, yp_node_t *node = (yp_capture_pattern_node_t) { { - .type = YP_NODE_CAPTURE_PATTERN_NODE, + .type = YP_CAPTURE_PATTERN_NODE, .location = { .start = value->location.start, .end = target->location.end @@ -1529,7 +1675,7 @@ yp_case_node_create(yp_parser_t *parser, const yp_token_t *case_keyword, yp_node *node = (yp_case_node_t) { { - .type = YP_NODE_CASE_NODE, + .type = YP_CASE_NODE, .location = { .start = case_keyword->start, .end = end_keyword->end @@ -1548,7 +1694,7 @@ yp_case_node_create(yp_parser_t *parser, const yp_token_t *case_keyword, yp_node // Append a new condition to a CaseNode node. static void yp_case_node_condition_append(yp_case_node_t *node, yp_node_t *condition) { - assert(YP_NODE_TYPE_P(condition, YP_NODE_WHEN_NODE) || YP_NODE_TYPE_P(condition, YP_NODE_IN_NODE)); + assert(YP_NODE_TYPE_P(condition, YP_WHEN_NODE) || YP_NODE_TYPE_P(condition, YP_IN_NODE)); yp_node_list_append(&node->conditions, condition); node->base.location.end = condition->location.end; @@ -1575,7 +1721,7 @@ yp_class_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const y *node = (yp_class_node_t) { { - .type = YP_NODE_CLASS_NODE, + .type = YP_CLASS_NODE, .location = { .start = class_keyword->start, .end = end_keyword->end }, }, .locals = *locals, @@ -1585,10 +1731,9 @@ yp_class_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const y .superclass = superclass, .body = body, .end_keyword_loc = YP_LOCATION_TOKEN_VALUE(end_keyword), - .name = YP_EMPTY_STRING + .name = yp_parser_constant_id_token(parser, name) }; - yp_string_shared_init(&node->name, name->start, name->end); return node; } @@ -1600,7 +1745,7 @@ yp_class_variable_and_write_node_create(yp_parser_t *parser, yp_class_variable_r *node = (yp_class_variable_and_write_node_t) { { - .type = YP_NODE_CLASS_VARIABLE_AND_WRITE_NODE, + .type = YP_CLASS_VARIABLE_AND_WRITE_NODE, .location = { .start = target->base.location.start, .end = value->location.end @@ -1622,7 +1767,7 @@ yp_class_variable_operator_write_node_create(yp_parser_t *parser, yp_class_varia *node = (yp_class_variable_operator_write_node_t) { { - .type = YP_NODE_CLASS_VARIABLE_OPERATOR_WRITE_NODE, + .type = YP_CLASS_VARIABLE_OPERATOR_WRITE_NODE, .location = { .start = target->base.location.start, .end = value->location.end @@ -1646,7 +1791,7 @@ yp_class_variable_or_write_node_create(yp_parser_t *parser, yp_class_variable_re *node = (yp_class_variable_or_write_node_t) { { - .type = YP_NODE_CLASS_VARIABLE_OR_WRITE_NODE, + .type = YP_CLASS_VARIABLE_OR_WRITE_NODE, .location = { .start = target->base.location.start, .end = value->location.end @@ -1669,10 +1814,10 @@ yp_class_variable_read_node_create(yp_parser_t *parser, const yp_token_t *token) *node = (yp_class_variable_read_node_t) { { - .type = YP_NODE_CLASS_VARIABLE_READ_NODE, + .type = YP_CLASS_VARIABLE_READ_NODE, .location = YP_LOCATION_TOKEN_VALUE(token) }, - .name = yp_parser_constant_id_location(parser, token->start, token->end) + .name = yp_parser_constant_id_token(parser, token) }; return node; @@ -1685,7 +1830,7 @@ yp_class_variable_write_node_create(yp_parser_t *parser, yp_class_variable_read_ *node = (yp_class_variable_write_node_t) { { - .type = YP_NODE_CLASS_VARIABLE_WRITE_NODE, + .type = YP_CLASS_VARIABLE_WRITE_NODE, .location = { .start = read_node->base.location.start, .end = value->location.end @@ -1708,7 +1853,7 @@ yp_constant_path_and_write_node_create(yp_parser_t *parser, yp_constant_path_nod *node = (yp_constant_path_and_write_node_t) { { - .type = YP_NODE_CONSTANT_PATH_AND_WRITE_NODE, + .type = YP_CONSTANT_PATH_AND_WRITE_NODE, .location = { .start = target->base.location.start, .end = value->location.end @@ -1729,7 +1874,7 @@ yp_constant_path_operator_write_node_create(yp_parser_t *parser, yp_constant_pat *node = (yp_constant_path_operator_write_node_t) { { - .type = YP_NODE_CONSTANT_PATH_OPERATOR_WRITE_NODE, + .type = YP_CONSTANT_PATH_OPERATOR_WRITE_NODE, .location = { .start = target->base.location.start, .end = value->location.end @@ -1752,7 +1897,7 @@ yp_constant_path_or_write_node_create(yp_parser_t *parser, yp_constant_path_node *node = (yp_constant_path_or_write_node_t) { { - .type = YP_NODE_CONSTANT_PATH_OR_WRITE_NODE, + .type = YP_CONSTANT_PATH_OR_WRITE_NODE, .location = { .start = target->base.location.start, .end = value->location.end @@ -1773,7 +1918,7 @@ yp_constant_path_node_create(yp_parser_t *parser, yp_node_t *parent, const yp_to *node = (yp_constant_path_node_t) { { - .type = YP_NODE_CONSTANT_PATH_NODE, + .type = YP_CONSTANT_PATH_NODE, .location = { .start = parent == NULL ? delimiter->start : parent->location.start, .end = child->location.end @@ -1794,7 +1939,7 @@ yp_constant_path_write_node_create(yp_parser_t *parser, yp_constant_path_node_t *node = (yp_constant_path_write_node_t) { { - .type = YP_NODE_CONSTANT_PATH_WRITE_NODE, + .type = YP_CONSTANT_PATH_WRITE_NODE, .location = { .start = target->base.location.start, .end = value->location.end @@ -1810,20 +1955,20 @@ yp_constant_path_write_node_create(yp_parser_t *parser, yp_constant_path_node_t // Allocate and initialize a new ConstantAndWriteNode node. static yp_constant_and_write_node_t * -yp_constant_and_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) { - assert(YP_NODE_TYPE_P(target, YP_NODE_CONSTANT_READ_NODE)); +yp_constant_and_write_node_create(yp_parser_t *parser, yp_constant_read_node_t *target, const yp_token_t *operator, yp_node_t *value) { assert(operator->type == YP_TOKEN_AMPERSAND_AMPERSAND_EQUAL); yp_constant_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_constant_and_write_node_t); *node = (yp_constant_and_write_node_t) { { - .type = YP_NODE_CONSTANT_AND_WRITE_NODE, + .type = YP_CONSTANT_AND_WRITE_NODE, .location = { - .start = target->location.start, + .start = target->base.location.start, .end = value->location.end } }, - .name_loc = target->location, + .name = target->name, + .name_loc = target->base.location, .operator_loc = YP_LOCATION_TOKEN_VALUE(operator), .value = value }; @@ -1833,18 +1978,19 @@ yp_constant_and_write_node_create(yp_parser_t *parser, yp_node_t *target, const // Allocate and initialize a new ConstantOperatorWriteNode node. static yp_constant_operator_write_node_t * -yp_constant_operator_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) { +yp_constant_operator_write_node_create(yp_parser_t *parser, yp_constant_read_node_t *target, const yp_token_t *operator, yp_node_t *value) { yp_constant_operator_write_node_t *node = YP_ALLOC_NODE(parser, yp_constant_operator_write_node_t); *node = (yp_constant_operator_write_node_t) { { - .type = YP_NODE_CONSTANT_OPERATOR_WRITE_NODE, + .type = YP_CONSTANT_OPERATOR_WRITE_NODE, .location = { - .start = target->location.start, + .start = target->base.location.start, .end = value->location.end } }, - .name_loc = target->location, + .name = target->name, + .name_loc = target->base.location, .operator_loc = YP_LOCATION_TOKEN_VALUE(operator), .value = value, .operator = yp_parser_constant_id_location(parser, operator->start, operator->end - 1) @@ -1855,20 +2001,20 @@ yp_constant_operator_write_node_create(yp_parser_t *parser, yp_node_t *target, c // Allocate and initialize a new ConstantOrWriteNode node. static yp_constant_or_write_node_t * -yp_constant_or_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) { - assert(YP_NODE_TYPE_P(target, YP_NODE_CONSTANT_READ_NODE)); +yp_constant_or_write_node_create(yp_parser_t *parser, yp_constant_read_node_t *target, const yp_token_t *operator, yp_node_t *value) { assert(operator->type == YP_TOKEN_PIPE_PIPE_EQUAL); yp_constant_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_constant_or_write_node_t); *node = (yp_constant_or_write_node_t) { { - .type = YP_NODE_CONSTANT_OR_WRITE_NODE, + .type = YP_CONSTANT_OR_WRITE_NODE, .location = { - .start = target->location.start, + .start = target->base.location.start, .end = value->location.end } }, - .name_loc = target->location, + .name = target->name, + .name_loc = target->base.location, .operator_loc = YP_LOCATION_TOKEN_VALUE(operator), .value = value }; @@ -1880,26 +2026,34 @@ yp_constant_or_write_node_create(yp_parser_t *parser, yp_node_t *target, const y static yp_constant_read_node_t * yp_constant_read_node_create(yp_parser_t *parser, const yp_token_t *name) { assert(name->type == YP_TOKEN_CONSTANT || name->type == YP_TOKEN_MISSING); - yp_constant_read_node_t *node = YP_ALLOC_NODE(parser, yp_constant_read_node_t); - *node = (yp_constant_read_node_t) {{ .type = YP_NODE_CONSTANT_READ_NODE, .location = YP_LOCATION_TOKEN_VALUE(name) }}; + + *node = (yp_constant_read_node_t) { + { + .type = YP_CONSTANT_READ_NODE, + .location = YP_LOCATION_TOKEN_VALUE(name) + }, + .name = yp_parser_constant_id_token(parser, name) + }; + return node; } // Allocate a new ConstantWriteNode node. static yp_constant_write_node_t * -yp_constant_write_node_create(yp_parser_t *parser, yp_location_t *name_loc, const yp_token_t *operator, yp_node_t *value) { +yp_constant_write_node_create(yp_parser_t *parser, yp_constant_read_node_t *target, const yp_token_t *operator, yp_node_t *value) { yp_constant_write_node_t *node = YP_ALLOC_NODE(parser, yp_constant_write_node_t); *node = (yp_constant_write_node_t) { { - .type = YP_NODE_CONSTANT_WRITE_NODE, + .type = YP_CONSTANT_WRITE_NODE, .location = { - .start = name_loc->start, + .start = target->base.location.start, .end = value->location.end - }, + } }, - .name_loc = *name_loc, + .name = target->name, + .name_loc = target->base.location, .operator_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(operator), .value = value }; @@ -1934,9 +2088,10 @@ yp_def_node_create( *node = (yp_def_node_t) { { - .type = YP_NODE_DEF_NODE, + .type = YP_DEF_NODE, .location = { .start = def_keyword->start, .end = end }, }, + .name = yp_parser_constant_id_token(parser, name), .name_loc = YP_LOCATION_TOKEN_VALUE(name), .receiver = receiver, .parameters = parameters, @@ -1960,7 +2115,7 @@ yp_defined_node_create(yp_parser_t *parser, const yp_token_t *lparen, yp_node_t *node = (yp_defined_node_t) { { - .type = YP_NODE_DEFINED_NODE, + .type = YP_DEFINED_NODE, .location = { .start = keyword_loc->start, .end = (rparen->type == YP_TOKEN_NOT_PROVIDED ? value->location.end : rparen->end) @@ -1988,7 +2143,7 @@ yp_else_node_create(yp_parser_t *parser, const yp_token_t *else_keyword, yp_stat *node = (yp_else_node_t) { { - .type = YP_NODE_ELSE_NODE, + .type = YP_ELSE_NODE, .location = { .start = else_keyword->start, .end = end, @@ -2009,7 +2164,7 @@ yp_embedded_statements_node_create(yp_parser_t *parser, const yp_token_t *openin *node = (yp_embedded_statements_node_t) { { - .type = YP_NODE_EMBEDDED_STATEMENTS_NODE, + .type = YP_EMBEDDED_STATEMENTS_NODE, .location = { .start = opening->start, .end = closing->end @@ -2030,7 +2185,7 @@ yp_embedded_variable_node_create(yp_parser_t *parser, const yp_token_t *operator *node = (yp_embedded_variable_node_t) { { - .type = YP_NODE_EMBEDDED_VARIABLE_NODE, + .type = YP_EMBEDDED_VARIABLE_NODE, .location = { .start = operator->start, .end = variable->location.end @@ -2050,7 +2205,7 @@ yp_ensure_node_create(yp_parser_t *parser, const yp_token_t *ensure_keyword, yp_ *node = (yp_ensure_node_t) { { - .type = YP_NODE_ENSURE_NODE, + .type = YP_ENSURE_NODE, .location = { .start = ensure_keyword->start, .end = end_keyword->end @@ -2069,7 +2224,13 @@ static yp_false_node_t * yp_false_node_create(yp_parser_t *parser, const yp_token_t *token) { assert(token->type == YP_TOKEN_KEYWORD_FALSE); yp_false_node_t *node = YP_ALLOC_NODE(parser, yp_false_node_t); - *node = (yp_false_node_t) {{ .type = YP_NODE_FALSE_NODE, .location = YP_LOCATION_TOKEN_VALUE(token) }}; + + *node = (yp_false_node_t) {{ + .type = YP_FALSE_NODE, + .flags = YP_NODE_FLAG_STATIC_LITERAL, + .location = YP_LOCATION_TOKEN_VALUE(token) + }}; + return node; } @@ -2090,7 +2251,7 @@ yp_find_pattern_node_create(yp_parser_t *parser, yp_node_list_t *nodes) { *node = (yp_find_pattern_node_t) { { - .type = YP_NODE_FIND_PATTERN_NODE, + .type = YP_FIND_PATTERN_NODE, .location = { .start = left->location.start, .end = right->location.end, @@ -2119,7 +2280,13 @@ static yp_float_node_t * yp_float_node_create(yp_parser_t *parser, const yp_token_t *token) { assert(token->type == YP_TOKEN_FLOAT); yp_float_node_t *node = YP_ALLOC_NODE(parser, yp_float_node_t); - *node = (yp_float_node_t) {{ .type = YP_NODE_FLOAT_NODE, .location = YP_LOCATION_TOKEN_VALUE(token) }}; + + *node = (yp_float_node_t) {{ + .type = YP_FLOAT_NODE, + .flags = YP_NODE_FLAG_STATIC_LITERAL, + .location = YP_LOCATION_TOKEN_VALUE(token) + }}; + return node; } @@ -2131,7 +2298,8 @@ yp_float_node_imaginary_create(yp_parser_t *parser, const yp_token_t *token) { yp_imaginary_node_t *node = YP_ALLOC_NODE(parser, yp_imaginary_node_t); *node = (yp_imaginary_node_t) { { - .type = YP_NODE_IMAGINARY_NODE, + .type = YP_IMAGINARY_NODE, + .flags = YP_NODE_FLAG_STATIC_LITERAL, .location = YP_LOCATION_TOKEN_VALUE(token) }, .numeric = (yp_node_t *) yp_float_node_create(parser, &((yp_token_t) { @@ -2152,7 +2320,8 @@ yp_float_node_rational_create(yp_parser_t *parser, const yp_token_t *token) { yp_rational_node_t *node = YP_ALLOC_NODE(parser, yp_rational_node_t); *node = (yp_rational_node_t) { { - .type = YP_NODE_RATIONAL_NODE, + .type = YP_RATIONAL_NODE, + .flags = YP_NODE_FLAG_STATIC_LITERAL, .location = YP_LOCATION_TOKEN_VALUE(token) }, .numeric = (yp_node_t *) yp_float_node_create(parser, &((yp_token_t) { @@ -2173,7 +2342,8 @@ yp_float_node_rational_imaginary_create(yp_parser_t *parser, const yp_token_t *t yp_imaginary_node_t *node = YP_ALLOC_NODE(parser, yp_imaginary_node_t); *node = (yp_imaginary_node_t) { { - .type = YP_NODE_IMAGINARY_NODE, + .type = YP_IMAGINARY_NODE, + .flags = YP_NODE_FLAG_STATIC_LITERAL, .location = YP_LOCATION_TOKEN_VALUE(token) }, .numeric = (yp_node_t *) yp_float_node_rational_create(parser, &((yp_token_t) { @@ -2202,7 +2372,7 @@ yp_for_node_create( *node = (yp_for_node_t) { { - .type = YP_NODE_FOR_NODE, + .type = YP_FOR_NODE, .location = { .start = for_keyword->start, .end = end_keyword->end @@ -2225,7 +2395,7 @@ static yp_forwarding_arguments_node_t * yp_forwarding_arguments_node_create(yp_parser_t *parser, const yp_token_t *token) { assert(token->type == YP_TOKEN_UDOT_DOT_DOT); yp_forwarding_arguments_node_t *node = YP_ALLOC_NODE(parser, yp_forwarding_arguments_node_t); - *node = (yp_forwarding_arguments_node_t) {{ .type = YP_NODE_FORWARDING_ARGUMENTS_NODE, .location = YP_LOCATION_TOKEN_VALUE(token) }}; + *node = (yp_forwarding_arguments_node_t) {{ .type = YP_FORWARDING_ARGUMENTS_NODE, .location = YP_LOCATION_TOKEN_VALUE(token) }}; return node; } @@ -2234,25 +2404,31 @@ static yp_forwarding_parameter_node_t * yp_forwarding_parameter_node_create(yp_parser_t *parser, const yp_token_t *token) { assert(token->type == YP_TOKEN_UDOT_DOT_DOT); yp_forwarding_parameter_node_t *node = YP_ALLOC_NODE(parser, yp_forwarding_parameter_node_t); - *node = (yp_forwarding_parameter_node_t) {{ .type = YP_NODE_FORWARDING_PARAMETER_NODE, .location = YP_LOCATION_TOKEN_VALUE(token) }}; + *node = (yp_forwarding_parameter_node_t) {{ .type = YP_FORWARDING_PARAMETER_NODE, .location = YP_LOCATION_TOKEN_VALUE(token) }}; return node; } // Allocate and initialize a new ForwardingSuper node. static yp_forwarding_super_node_t * yp_forwarding_super_node_create(yp_parser_t *parser, const yp_token_t *token, yp_arguments_t *arguments) { + assert(arguments->block == NULL || YP_NODE_TYPE_P(arguments->block, YP_BLOCK_NODE)); assert(token->type == YP_TOKEN_KEYWORD_SUPER); yp_forwarding_super_node_t *node = YP_ALLOC_NODE(parser, yp_forwarding_super_node_t); + yp_block_node_t *block = NULL; + if (arguments->block != NULL) { + block = (yp_block_node_t *) arguments->block; + } + *node = (yp_forwarding_super_node_t) { { - .type = YP_NODE_FORWARDING_SUPER_NODE, + .type = YP_FORWARDING_SUPER_NODE, .location = { .start = token->start, - .end = arguments->block != NULL ? arguments->block->base.location.end : token->end + .end = block != NULL ? block->base.location.end : token->end }, }, - .block = arguments->block + .block = block }; return node; @@ -2266,7 +2442,7 @@ yp_hash_pattern_node_empty_create(yp_parser_t *parser, const yp_token_t *opening *node = (yp_hash_pattern_node_t) { { - .type = YP_NODE_HASH_PATTERN_NODE, + .type = YP_HASH_PATTERN_NODE, .location = { .start = opening->start, .end = closing->end @@ -2289,7 +2465,7 @@ yp_hash_pattern_node_node_list_create(yp_parser_t *parser, yp_node_list_t *assoc *node = (yp_hash_pattern_node_t) { { - .type = YP_NODE_HASH_PATTERN_NODE, + .type = YP_HASH_PATTERN_NODE, .location = { .start = assocs->nodes[0]->location.start, .end = assocs->nodes[assocs->size - 1]->location.end @@ -2313,11 +2489,11 @@ yp_hash_pattern_node_node_list_create(yp_parser_t *parser, yp_node_list_t *assoc // Retrieve the name from a node that will become a global variable write node. static yp_constant_id_t yp_global_variable_write_name(yp_parser_t *parser, yp_node_t *target) { - if (YP_NODE_TYPE_P(target, YP_NODE_GLOBAL_VARIABLE_READ_NODE)) { + if (YP_NODE_TYPE_P(target, YP_GLOBAL_VARIABLE_READ_NODE)) { return ((yp_global_variable_read_node_t *) target)->name; } - assert(YP_NODE_TYPE_P(target, YP_NODE_BACK_REFERENCE_READ_NODE) || YP_NODE_TYPE_P(target, YP_NODE_NUMBERED_REFERENCE_READ_NODE)); + assert(YP_NODE_TYPE_P(target, YP_BACK_REFERENCE_READ_NODE) || YP_NODE_TYPE_P(target, YP_NUMBERED_REFERENCE_READ_NODE)); // This will only ever happen in the event of a syntax error, but we // still need to provide something for the node. @@ -2332,7 +2508,7 @@ yp_global_variable_and_write_node_create(yp_parser_t *parser, yp_node_t *target, *node = (yp_global_variable_and_write_node_t) { { - .type = YP_NODE_GLOBAL_VARIABLE_AND_WRITE_NODE, + .type = YP_GLOBAL_VARIABLE_AND_WRITE_NODE, .location = { .start = target->location.start, .end = value->location.end @@ -2354,7 +2530,7 @@ yp_global_variable_operator_write_node_create(yp_parser_t *parser, yp_node_t *ta *node = (yp_global_variable_operator_write_node_t) { { - .type = YP_NODE_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE, + .type = YP_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE, .location = { .start = target->location.start, .end = value->location.end @@ -2378,7 +2554,7 @@ yp_global_variable_or_write_node_create(yp_parser_t *parser, yp_node_t *target, *node = (yp_global_variable_or_write_node_t) { { - .type = YP_NODE_GLOBAL_VARIABLE_OR_WRITE_NODE, + .type = YP_GLOBAL_VARIABLE_OR_WRITE_NODE, .location = { .start = target->location.start, .end = value->location.end @@ -2400,10 +2576,10 @@ yp_global_variable_read_node_create(yp_parser_t *parser, const yp_token_t *name) *node = (yp_global_variable_read_node_t) { { - .type = YP_NODE_GLOBAL_VARIABLE_READ_NODE, + .type = YP_GLOBAL_VARIABLE_READ_NODE, .location = YP_LOCATION_TOKEN_VALUE(name), }, - .name = yp_parser_constant_id_location(parser, name->start, name->end) + .name = yp_parser_constant_id_token(parser, name) }; return node; @@ -2416,7 +2592,7 @@ yp_global_variable_write_node_create(yp_parser_t *parser, yp_node_t *target, con *node = (yp_global_variable_write_node_t) { { - .type = YP_NODE_GLOBAL_VARIABLE_WRITE_NODE, + .type = YP_GLOBAL_VARIABLE_WRITE_NODE, .location = { .start = target->location.start, .end = value->location.end @@ -2439,11 +2615,8 @@ yp_hash_node_create(yp_parser_t *parser, const yp_token_t *opening) { *node = (yp_hash_node_t) { { - .type = YP_NODE_HASH_NODE, - .location = { - .start = opening->start, - .end = opening->end - }, + .type = YP_HASH_NODE, + .location = YP_LOCATION_TOKEN_VALUE(opening) }, .opening_loc = YP_LOCATION_TOKEN_VALUE(opening), .closing_loc = YP_LOCATION_NULL_VALUE(parser), @@ -2473,7 +2646,7 @@ yp_if_node_create(yp_parser_t *parser, yp_node_t *consequent, const yp_token_t *end_keyword ) { - yp_flip_flop(predicate); + yp_conditional_predicate(predicate); yp_if_node_t *node = YP_ALLOC_NODE(parser, yp_if_node_t); const uint8_t *end; @@ -2489,7 +2662,7 @@ yp_if_node_create(yp_parser_t *parser, *node = (yp_if_node_t) { { - .type = YP_NODE_IF_NODE, + .type = YP_IF_NODE, .flags = YP_NODE_FLAG_NEWLINE, .location = { .start = if_keyword->start, @@ -2509,7 +2682,7 @@ yp_if_node_create(yp_parser_t *parser, // Allocate and initialize new IfNode node in the modifier form. static yp_if_node_t * yp_if_node_modifier_create(yp_parser_t *parser, yp_node_t *statement, const yp_token_t *if_keyword, yp_node_t *predicate) { - yp_flip_flop(predicate); + yp_conditional_predicate(predicate); yp_if_node_t *node = YP_ALLOC_NODE(parser, yp_if_node_t); yp_statements_node_t *statements = yp_statements_node_create(parser); @@ -2517,7 +2690,7 @@ yp_if_node_modifier_create(yp_parser_t *parser, yp_node_t *statement, const yp_t *node = (yp_if_node_t) { { - .type = YP_NODE_IF_NODE, + .type = YP_IF_NODE, .flags = YP_NODE_FLAG_NEWLINE, .location = { .start = statement->location.start, @@ -2537,7 +2710,7 @@ yp_if_node_modifier_create(yp_parser_t *parser, yp_node_t *statement, const yp_t // Allocate and initialize an if node from a ternary expression. static yp_if_node_t * yp_if_node_ternary_create(yp_parser_t *parser, yp_node_t *predicate, yp_node_t *true_expression, const yp_token_t *colon, yp_node_t *false_expression) { - yp_flip_flop(predicate); + yp_conditional_predicate(predicate); yp_statements_node_t *if_statements = yp_statements_node_create(parser); yp_statements_node_body_append(if_statements, true_expression); @@ -2552,7 +2725,7 @@ yp_if_node_ternary_create(yp_parser_t *parser, yp_node_t *predicate, yp_node_t * *node = (yp_if_node_t) { { - .type = YP_NODE_IF_NODE, + .type = YP_IF_NODE, .flags = YP_NODE_FLAG_NEWLINE, .location = { .start = predicate->location.start, @@ -2582,27 +2755,50 @@ yp_else_node_end_keyword_loc_set(yp_else_node_t *node, const yp_token_t *keyword node->end_keyword_loc = YP_LOCATION_TOKEN_VALUE(keyword); } +// Allocate and initialize a new ImplicitNode node. +static yp_implicit_node_t * +yp_implicit_node_create(yp_parser_t *parser, yp_node_t *value) { + yp_implicit_node_t *node = YP_ALLOC_NODE(parser, yp_implicit_node_t); + + *node = (yp_implicit_node_t) { + { + .type = YP_IMPLICIT_NODE, + .location = value->location + }, + .value = value + }; + + return node; +} + // Allocate and initialize a new IntegerNode node. static yp_integer_node_t * -yp_integer_node_create(yp_parser_t *parser, const yp_token_t *token) { +yp_integer_node_create(yp_parser_t *parser, yp_node_flags_t base, const yp_token_t *token) { assert(token->type == YP_TOKEN_INTEGER); yp_integer_node_t *node = YP_ALLOC_NODE(parser, yp_integer_node_t); - *node = (yp_integer_node_t) {{ .type = YP_NODE_INTEGER_NODE, .location = YP_LOCATION_TOKEN_VALUE(token) }}; + + *node = (yp_integer_node_t) {{ + .type = YP_INTEGER_NODE, + .flags = base | YP_NODE_FLAG_STATIC_LITERAL, + .location = YP_LOCATION_TOKEN_VALUE(token) + }}; + return node; } // Allocate and initialize a new IntegerNode node from an INTEGER_IMAGINARY token. static yp_imaginary_node_t * -yp_integer_node_imaginary_create(yp_parser_t *parser, const yp_token_t *token) { +yp_integer_node_imaginary_create(yp_parser_t *parser, yp_node_flags_t base, const yp_token_t *token) { assert(token->type == YP_TOKEN_INTEGER_IMAGINARY); yp_imaginary_node_t *node = YP_ALLOC_NODE(parser, yp_imaginary_node_t); *node = (yp_imaginary_node_t) { { - .type = YP_NODE_IMAGINARY_NODE, + .type = YP_IMAGINARY_NODE, + .flags = YP_NODE_FLAG_STATIC_LITERAL, .location = YP_LOCATION_TOKEN_VALUE(token) }, - .numeric = (yp_node_t *) yp_integer_node_create(parser, &((yp_token_t) { + .numeric = (yp_node_t *) yp_integer_node_create(parser, base, &((yp_token_t) { .type = YP_TOKEN_INTEGER, .start = token->start, .end = token->end - 1 @@ -2614,16 +2810,17 @@ yp_integer_node_imaginary_create(yp_parser_t *parser, const yp_token_t *token) { // Allocate and initialize a new IntegerNode node from an INTEGER_RATIONAL token. static yp_rational_node_t * -yp_integer_node_rational_create(yp_parser_t *parser, const yp_token_t *token) { +yp_integer_node_rational_create(yp_parser_t *parser, yp_node_flags_t base, const yp_token_t *token) { assert(token->type == YP_TOKEN_INTEGER_RATIONAL); yp_rational_node_t *node = YP_ALLOC_NODE(parser, yp_rational_node_t); *node = (yp_rational_node_t) { { - .type = YP_NODE_RATIONAL_NODE, + .type = YP_RATIONAL_NODE, + .flags = YP_NODE_FLAG_STATIC_LITERAL, .location = YP_LOCATION_TOKEN_VALUE(token) }, - .numeric = (yp_node_t *) yp_integer_node_create(parser, &((yp_token_t) { + .numeric = (yp_node_t *) yp_integer_node_create(parser, base, &((yp_token_t) { .type = YP_TOKEN_INTEGER, .start = token->start, .end = token->end - 1 @@ -2635,16 +2832,17 @@ yp_integer_node_rational_create(yp_parser_t *parser, const yp_token_t *token) { // Allocate and initialize a new IntegerNode node from an INTEGER_RATIONAL_IMAGINARY token. static yp_imaginary_node_t * -yp_integer_node_rational_imaginary_create(yp_parser_t *parser, const yp_token_t *token) { +yp_integer_node_rational_imaginary_create(yp_parser_t *parser, yp_node_flags_t base, const yp_token_t *token) { assert(token->type == YP_TOKEN_INTEGER_RATIONAL_IMAGINARY); yp_imaginary_node_t *node = YP_ALLOC_NODE(parser, yp_imaginary_node_t); *node = (yp_imaginary_node_t) { { - .type = YP_NODE_IMAGINARY_NODE, + .type = YP_IMAGINARY_NODE, + .flags = YP_NODE_FLAG_STATIC_LITERAL, .location = YP_LOCATION_TOKEN_VALUE(token) }, - .numeric = (yp_node_t *) yp_integer_node_rational_create(parser, &((yp_token_t) { + .numeric = (yp_node_t *) yp_integer_node_rational_create(parser, base, &((yp_token_t) { .type = YP_TOKEN_INTEGER_RATIONAL, .start = token->start, .end = token->end - 1 @@ -2670,7 +2868,7 @@ yp_in_node_create(yp_parser_t *parser, yp_node_t *pattern, yp_statements_node_t *node = (yp_in_node_t) { { - .type = YP_NODE_IN_NODE, + .type = YP_IN_NODE, .location = { .start = in_keyword->start, .end = end @@ -2693,7 +2891,7 @@ yp_instance_variable_and_write_node_create(yp_parser_t *parser, yp_instance_vari *node = (yp_instance_variable_and_write_node_t) { { - .type = YP_NODE_INSTANCE_VARIABLE_AND_WRITE_NODE, + .type = YP_INSTANCE_VARIABLE_AND_WRITE_NODE, .location = { .start = target->base.location.start, .end = value->location.end @@ -2715,7 +2913,7 @@ yp_instance_variable_operator_write_node_create(yp_parser_t *parser, yp_instance *node = (yp_instance_variable_operator_write_node_t) { { - .type = YP_NODE_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE, + .type = YP_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE, .location = { .start = target->base.location.start, .end = value->location.end @@ -2739,7 +2937,7 @@ yp_instance_variable_or_write_node_create(yp_parser_t *parser, yp_instance_varia *node = (yp_instance_variable_or_write_node_t) { { - .type = YP_NODE_INSTANCE_VARIABLE_OR_WRITE_NODE, + .type = YP_INSTANCE_VARIABLE_OR_WRITE_NODE, .location = { .start = target->base.location.start, .end = value->location.end @@ -2762,10 +2960,10 @@ yp_instance_variable_read_node_create(yp_parser_t *parser, const yp_token_t *tok *node = (yp_instance_variable_read_node_t) { { - .type = YP_NODE_INSTANCE_VARIABLE_READ_NODE, + .type = YP_INSTANCE_VARIABLE_READ_NODE, .location = YP_LOCATION_TOKEN_VALUE(token) }, - .name = yp_parser_constant_id_location(parser, token->start, token->end) + .name = yp_parser_constant_id_token(parser, token) }; return node; @@ -2777,7 +2975,7 @@ yp_instance_variable_write_node_create(yp_parser_t *parser, yp_instance_variable yp_instance_variable_write_node_t *node = YP_ALLOC_NODE(parser, yp_instance_variable_write_node_t); *node = (yp_instance_variable_write_node_t) { { - .type = YP_NODE_INSTANCE_VARIABLE_WRITE_NODE, + .type = YP_INSTANCE_VARIABLE_WRITE_NODE, .location = { .start = read_node->base.location.start, .end = value->location.end @@ -2799,7 +2997,7 @@ yp_interpolated_regular_expression_node_create(yp_parser_t *parser, const yp_tok *node = (yp_interpolated_regular_expression_node_t) { { - .type = YP_NODE_INTERPOLATED_REGULAR_EXPRESSION_NODE, + .type = YP_INTERPOLATED_REGULAR_EXPRESSION_NODE, .location = { .start = opening->start, .end = NULL, @@ -2838,7 +3036,7 @@ yp_interpolated_string_node_create(yp_parser_t *parser, const yp_token_t *openin *node = (yp_interpolated_string_node_t) { { - .type = YP_NODE_INTERPOLATED_STRING_NODE, + .type = YP_INTERPOLATED_STRING_NODE, .location = { .start = opening->start, .end = closing->end, @@ -2877,7 +3075,7 @@ yp_interpolated_symbol_node_create(yp_parser_t *parser, const yp_token_t *openin *node = (yp_interpolated_symbol_node_t) { { - .type = YP_NODE_INTERPOLATED_SYMBOL_NODE, + .type = YP_INTERPOLATED_SYMBOL_NODE, .location = { .start = opening->start, .end = closing->end, @@ -2908,7 +3106,7 @@ yp_interpolated_xstring_node_create(yp_parser_t *parser, const yp_token_t *openi *node = (yp_interpolated_x_string_node_t) { { - .type = YP_NODE_INTERPOLATED_X_STRING_NODE, + .type = YP_INTERPOLATED_X_STRING_NODE, .location = { .start = opening->start, .end = closing->end @@ -2941,11 +3139,8 @@ yp_keyword_hash_node_create(yp_parser_t *parser) { *node = (yp_keyword_hash_node_t) { .base = { - .type = YP_NODE_KEYWORD_HASH_NODE, - .location = { - .start = NULL, - .end = NULL - }, + .type = YP_KEYWORD_HASH_NODE, + .location = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE }, .elements = YP_EMPTY_NODE_LIST }; @@ -2970,12 +3165,13 @@ yp_keyword_parameter_node_create(yp_parser_t *parser, const yp_token_t *name, yp *node = (yp_keyword_parameter_node_t) { { - .type = YP_NODE_KEYWORD_PARAMETER_NODE, + .type = YP_KEYWORD_PARAMETER_NODE, .location = { .start = name->start, .end = value == NULL ? name->end : value->location.end }, }, + .name = yp_parser_constant_id_location(parser, name->start, name->end - 1), .name_loc = YP_LOCATION_TOKEN_VALUE(name), .value = value }; @@ -2990,14 +3186,15 @@ yp_keyword_rest_parameter_node_create(yp_parser_t *parser, const yp_token_t *ope *node = (yp_keyword_rest_parameter_node_t) { { - .type = YP_NODE_KEYWORD_REST_PARAMETER_NODE, + .type = YP_KEYWORD_REST_PARAMETER_NODE, .location = { .start = operator->start, .end = (name->type == YP_TOKEN_NOT_PROVIDED ? operator->end : name->end) }, }, - .operator_loc = YP_LOCATION_TOKEN_VALUE(operator), - .name_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(name) + .name = yp_parser_optional_constant_id_token(parser, name), + .name_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(name), + .operator_loc = YP_LOCATION_TOKEN_VALUE(operator) }; return node; @@ -3018,7 +3215,7 @@ yp_lambda_node_create( *node = (yp_lambda_node_t) { { - .type = YP_NODE_LAMBDA_NODE, + .type = YP_LAMBDA_NODE, .location = { .start = operator->start, .end = closing->end @@ -3038,13 +3235,13 @@ yp_lambda_node_create( // Allocate and initialize a new LocalVariableAndWriteNode node. static yp_local_variable_and_write_node_t * yp_local_variable_and_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value, yp_constant_id_t name, uint32_t depth) { - assert(YP_NODE_TYPE_P(target, YP_NODE_LOCAL_VARIABLE_READ_NODE) || YP_NODE_TYPE_P(target, YP_NODE_CALL_NODE)); + assert(YP_NODE_TYPE_P(target, YP_LOCAL_VARIABLE_READ_NODE) || YP_NODE_TYPE_P(target, YP_CALL_NODE)); assert(operator->type == YP_TOKEN_AMPERSAND_AMPERSAND_EQUAL); yp_local_variable_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_local_variable_and_write_node_t); *node = (yp_local_variable_and_write_node_t) { { - .type = YP_NODE_LOCAL_VARIABLE_AND_WRITE_NODE, + .type = YP_LOCAL_VARIABLE_AND_WRITE_NODE, .location = { .start = target->location.start, .end = value->location.end @@ -3067,7 +3264,7 @@ yp_local_variable_operator_write_node_create(yp_parser_t *parser, yp_node_t *tar *node = (yp_local_variable_operator_write_node_t) { { - .type = YP_NODE_LOCAL_VARIABLE_OPERATOR_WRITE_NODE, + .type = YP_LOCAL_VARIABLE_OPERATOR_WRITE_NODE, .location = { .start = target->location.start, .end = value->location.end @@ -3087,13 +3284,13 @@ yp_local_variable_operator_write_node_create(yp_parser_t *parser, yp_node_t *tar // Allocate and initialize a new LocalVariableOrWriteNode node. static yp_local_variable_or_write_node_t * yp_local_variable_or_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value, yp_constant_id_t name, uint32_t depth) { - assert(YP_NODE_TYPE_P(target, YP_NODE_LOCAL_VARIABLE_READ_NODE) || YP_NODE_TYPE_P(target, YP_NODE_CALL_NODE)); + assert(YP_NODE_TYPE_P(target, YP_LOCAL_VARIABLE_READ_NODE) || YP_NODE_TYPE_P(target, YP_CALL_NODE)); assert(operator->type == YP_TOKEN_PIPE_PIPE_EQUAL); yp_local_variable_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_local_variable_or_write_node_t); *node = (yp_local_variable_or_write_node_t) { { - .type = YP_NODE_LOCAL_VARIABLE_OR_WRITE_NODE, + .type = YP_LOCAL_VARIABLE_OR_WRITE_NODE, .location = { .start = target->location.start, .end = value->location.end @@ -3116,7 +3313,7 @@ yp_local_variable_read_node_create(yp_parser_t *parser, const yp_token_t *name, *node = (yp_local_variable_read_node_t) { { - .type = YP_NODE_LOCAL_VARIABLE_READ_NODE, + .type = YP_LOCAL_VARIABLE_READ_NODE, .location = YP_LOCATION_TOKEN_VALUE(name) }, .name = yp_parser_constant_id_token(parser, name), @@ -3133,7 +3330,7 @@ yp_local_variable_write_node_create(yp_parser_t *parser, yp_constant_id_t name, *node = (yp_local_variable_write_node_t) { { - .type = YP_NODE_LOCAL_VARIABLE_WRITE_NODE, + .type = YP_LOCAL_VARIABLE_WRITE_NODE, .location = { .start = name_loc->start, .end = value->location.end @@ -3156,7 +3353,7 @@ yp_local_variable_target_node_create(yp_parser_t *parser, const yp_token_t *name *node = (yp_local_variable_target_node_t) { { - .type = YP_NODE_LOCAL_VARIABLE_TARGET_NODE, + .type = YP_LOCAL_VARIABLE_TARGET_NODE, .location = YP_LOCATION_TOKEN_VALUE(name) }, .name = yp_parser_constant_id_token(parser, name), @@ -3173,7 +3370,7 @@ yp_match_predicate_node_create(yp_parser_t *parser, yp_node_t *value, yp_node_t *node = (yp_match_predicate_node_t) { { - .type = YP_NODE_MATCH_PREDICATE_NODE, + .type = YP_MATCH_PREDICATE_NODE, .location = { .start = value->location.start, .end = pattern->location.end @@ -3194,7 +3391,7 @@ yp_match_required_node_create(yp_parser_t *parser, yp_node_t *value, yp_node_t * *node = (yp_match_required_node_t) { { - .type = YP_NODE_MATCH_REQUIRED_NODE, + .type = YP_MATCH_REQUIRED_NODE, .location = { .start = value->location.start, .end = pattern->location.end @@ -3208,6 +3405,23 @@ yp_match_required_node_create(yp_parser_t *parser, yp_node_t *value, yp_node_t * return node; } +// Allocate and initialize a new MatchWriteNode node. +static yp_match_write_node_t * +yp_match_write_node_create(yp_parser_t *parser, yp_call_node_t *call) { + yp_match_write_node_t *node = YP_ALLOC_NODE(parser, yp_match_write_node_t); + + *node = (yp_match_write_node_t) { + { + .type = YP_MATCH_WRITE_NODE, + .location = call->base.location + }, + .call = call + }; + + yp_constant_id_list_init(&node->locals); + return node; +} + // Allocate a new ModuleNode node. static yp_module_node_t * yp_module_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const yp_token_t *module_keyword, yp_node_t *constant_path, const yp_token_t *name, yp_node_t *body, const yp_token_t *end_keyword) { @@ -3215,7 +3429,7 @@ yp_module_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const *node = (yp_module_node_t) { { - .type = YP_NODE_MODULE_NODE, + .type = YP_MODULE_NODE, .location = { .start = module_keyword->start, .end = end_keyword->end @@ -3226,39 +3440,33 @@ yp_module_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const .constant_path = constant_path, .body = body, .end_keyword_loc = YP_LOCATION_TOKEN_VALUE(end_keyword), - .name = YP_EMPTY_STRING + .name = yp_parser_constant_id_token(parser, name) }; - yp_string_shared_init(&node->name, name->start, name->end); return node; } -// Allocate a new MultiWriteNode node. -static yp_multi_write_node_t * -yp_multi_write_node_create(yp_parser_t *parser, const yp_token_t *operator, yp_node_t *value, const yp_location_t *lparen_loc, const yp_location_t *rparen_loc) { - yp_multi_write_node_t *node = YP_ALLOC_NODE(parser, yp_multi_write_node_t); +// Allocate and initialize new MultiTargetNode node. +static yp_multi_target_node_t * +yp_multi_target_node_create(yp_parser_t *parser) { + yp_multi_target_node_t *node = YP_ALLOC_NODE(parser, yp_multi_target_node_t); - *node = (yp_multi_write_node_t) { + *node = (yp_multi_target_node_t) { { - .type = YP_NODE_MULTI_WRITE_NODE, - .location = { - .start = lparen_loc->start, - .end = value == NULL ? rparen_loc->end : value->location.end - }, + .type = YP_MULTI_TARGET_NODE, + .location = { .start = NULL, .end = NULL } }, - .operator_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(operator), - .value = value, - .lparen_loc = *lparen_loc, - .rparen_loc = *rparen_loc, - .targets = YP_EMPTY_NODE_LIST + .targets = YP_EMPTY_NODE_LIST, + .lparen_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE, + .rparen_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE }; return node; } -// Append a target to a MultiWriteNode node. +// Append a target to a MultiTargetNode node. static void -yp_multi_write_node_targets_append(yp_multi_write_node_t *node, yp_node_t *target) { +yp_multi_target_node_targets_append(yp_multi_target_node_t *node, yp_node_t *target) { yp_node_list_append(&node->targets, target); if (node->base.location.start == NULL || (node->base.location.start > target->location.start)) { @@ -3270,9 +3478,31 @@ yp_multi_write_node_targets_append(yp_multi_write_node_t *node, yp_node_t *targe } } -static inline void -yp_multi_write_node_operator_loc_set(yp_multi_write_node_t *node, const yp_token_t *operator) { - node->operator_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(operator); +// Allocate a new MultiWriteNode node. +static yp_multi_write_node_t * +yp_multi_write_node_create(yp_parser_t *parser, yp_multi_target_node_t *target, const yp_token_t *operator, yp_node_t *value) { + yp_multi_write_node_t *node = YP_ALLOC_NODE(parser, yp_multi_write_node_t); + + *node = (yp_multi_write_node_t) { + { + .type = YP_MULTI_WRITE_NODE, + .location = { + .start = target->base.location.start, + .end = value->location.end + } + }, + .targets = target->targets, + .lparen_loc = target->lparen_loc, + .rparen_loc = target->rparen_loc, + .operator_loc = YP_LOCATION_TOKEN_VALUE(operator), + .value = value + }; + + // Explicitly do not call yp_node_destroy here because we want to keep + // around all of the information within the MultiWriteNode node. + free(target); + + return node; } // Allocate and initialize a new NextNode node. @@ -3283,7 +3513,7 @@ yp_next_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_arguments *node = (yp_next_node_t) { { - .type = YP_NODE_NEXT_NODE, + .type = YP_NEXT_NODE, .location = { .start = keyword->start, .end = (arguments == NULL ? keyword->end : arguments->base.location.end) @@ -3302,7 +3532,12 @@ yp_nil_node_create(yp_parser_t *parser, const yp_token_t *token) { assert(token->type == YP_TOKEN_KEYWORD_NIL); yp_nil_node_t *node = YP_ALLOC_NODE(parser, yp_nil_node_t); - *node = (yp_nil_node_t) {{ .type = YP_NODE_NIL_NODE, .location = YP_LOCATION_TOKEN_VALUE(token) }}; + *node = (yp_nil_node_t) {{ + .type = YP_NIL_NODE, + .flags = YP_NODE_FLAG_STATIC_LITERAL, + .location = YP_LOCATION_TOKEN_VALUE(token) + }}; + return node; } @@ -3315,7 +3550,7 @@ yp_no_keywords_parameter_node_create(yp_parser_t *parser, const yp_token_t *oper *node = (yp_no_keywords_parameter_node_t) { { - .type = YP_NODE_NO_KEYWORDS_PARAMETER_NODE, + .type = YP_NO_KEYWORDS_PARAMETER_NODE, .location = { .start = operator->start, .end = keyword->end @@ -3336,7 +3571,7 @@ yp_numbered_reference_read_node_create(yp_parser_t *parser, const yp_token_t *na *node = (yp_numbered_reference_read_node_t) { { - .type = YP_NODE_NUMBERED_REFERENCE_READ_NODE, + .type = YP_NUMBERED_REFERENCE_READ_NODE, .location = YP_LOCATION_TOKEN_VALUE(name), }, .number = parse_decimal_number(parser, name->start + 1, name->end) @@ -3352,7 +3587,7 @@ yp_optional_parameter_node_create(yp_parser_t *parser, const yp_token_t *name, c *node = (yp_optional_parameter_node_t) { { - .type = YP_NODE_OPTIONAL_PARAMETER_NODE, + .type = YP_OPTIONAL_PARAMETER_NODE, .location = { .start = name->start, .end = value->location.end @@ -3374,7 +3609,7 @@ yp_or_node_create(yp_parser_t *parser, yp_node_t *left, const yp_token_t *operat *node = (yp_or_node_t) { { - .type = YP_NODE_OR_NODE, + .type = YP_OR_NODE, .location = { .start = left->location.start, .end = right->location.end @@ -3395,8 +3630,8 @@ yp_parameters_node_create(yp_parser_t *parser) { *node = (yp_parameters_node_t) { { - .type = YP_NODE_PARAMETERS_NODE, - .location = { .start = parser->current.start, .end = parser->current.start }, + .type = YP_PARAMETERS_NODE, + .location = YP_LOCATION_TOKEN_VALUE(&parser->current) }, .rest = NULL, .keyword_rest = NULL, @@ -3485,7 +3720,7 @@ yp_program_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, yp_st *node = (yp_program_node_t) { { - .type = YP_NODE_PROGRAM_NODE, + .type = YP_PROGRAM_NODE, .location = { .start = statements == NULL ? parser->start : statements->base.location.start, .end = statements == NULL ? parser->end : statements->base.location.end @@ -3505,7 +3740,7 @@ yp_parentheses_node_create(yp_parser_t *parser, const yp_token_t *opening, yp_no *node = (yp_parentheses_node_t) { { - .type = YP_NODE_PARENTHESES_NODE, + .type = YP_PARENTHESES_NODE, .location = { .start = opening->start, .end = closing->end @@ -3526,7 +3761,7 @@ yp_pinned_expression_node_create(yp_parser_t *parser, yp_node_t *expression, con *node = (yp_pinned_expression_node_t) { { - .type = YP_NODE_PINNED_EXPRESSION_NODE, + .type = YP_PINNED_EXPRESSION_NODE, .location = { .start = operator->start, .end = rparen->end @@ -3548,7 +3783,7 @@ yp_pinned_variable_node_create(yp_parser_t *parser, const yp_token_t *operator, *node = (yp_pinned_variable_node_t) { { - .type = YP_NODE_PINNED_VARIABLE_NODE, + .type = YP_PINNED_VARIABLE_NODE, .location = { .start = operator->start, .end = variable->location.end @@ -3568,7 +3803,7 @@ yp_post_execution_node_create(yp_parser_t *parser, const yp_token_t *keyword, co *node = (yp_post_execution_node_t) { { - .type = YP_NODE_POST_EXECUTION_NODE, + .type = YP_POST_EXECUTION_NODE, .location = { .start = keyword->start, .end = closing->end @@ -3590,7 +3825,7 @@ yp_pre_execution_node_create(yp_parser_t *parser, const yp_token_t *keyword, con *node = (yp_pre_execution_node_t) { { - .type = YP_NODE_PRE_EXECUTION_NODE, + .type = YP_PRE_EXECUTION_NODE, .location = { .start = keyword->start, .end = closing->end @@ -3612,7 +3847,7 @@ yp_range_node_create(yp_parser_t *parser, yp_node_t *left, const yp_token_t *ope *node = (yp_range_node_t) { { - .type = YP_NODE_RANGE_NODE, + .type = YP_RANGE_NODE, .location = { .start = (left == NULL ? operator->start : left->location.start), .end = (right == NULL ? operator->end : right->location.end) @@ -3641,7 +3876,7 @@ yp_redo_node_create(yp_parser_t *parser, const yp_token_t *token) { assert(token->type == YP_TOKEN_KEYWORD_REDO); yp_redo_node_t *node = YP_ALLOC_NODE(parser, yp_redo_node_t); - *node = (yp_redo_node_t) {{ .type = YP_NODE_REDO_NODE, .location = YP_LOCATION_TOKEN_VALUE(token) }}; + *node = (yp_redo_node_t) {{ .type = YP_REDO_NODE, .location = YP_LOCATION_TOKEN_VALUE(token) }}; return node; } @@ -3652,7 +3887,7 @@ yp_regular_expression_node_create(yp_parser_t *parser, const yp_token_t *opening *node = (yp_regular_expression_node_t) { { - .type = YP_NODE_REGULAR_EXPRESSION_NODE, + .type = YP_REGULAR_EXPRESSION_NODE, .flags = yp_regular_expression_flags_create(closing), .location = { .start = MIN(opening->start, closing->start), @@ -3675,11 +3910,11 @@ yp_required_destructured_parameter_node_create(yp_parser_t *parser, const yp_tok *node = (yp_required_destructured_parameter_node_t) { { - .type = YP_NODE_REQUIRED_DESTRUCTURED_PARAMETER_NODE, + .type = YP_REQUIRED_DESTRUCTURED_PARAMETER_NODE, .location = YP_LOCATION_TOKEN_VALUE(opening) }, .opening_loc = YP_LOCATION_TOKEN_VALUE(opening), - .closing_loc = { .start = NULL, .end = NULL }, + .closing_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE, .parameters = YP_EMPTY_NODE_LIST }; @@ -3706,7 +3941,7 @@ yp_required_parameter_node_create(yp_parser_t *parser, const yp_token_t *token) *node = (yp_required_parameter_node_t) { { - .type = YP_NODE_REQUIRED_PARAMETER_NODE, + .type = YP_REQUIRED_PARAMETER_NODE, .location = YP_LOCATION_TOKEN_VALUE(token) }, .name = yp_parser_constant_id_token(parser, token) @@ -3722,7 +3957,7 @@ yp_rescue_modifier_node_create(yp_parser_t *parser, yp_node_t *expression, const *node = (yp_rescue_modifier_node_t) { { - .type = YP_NODE_RESCUE_MODIFIER_NODE, + .type = YP_RESCUE_MODIFIER_NODE, .location = { .start = expression->location.start, .end = rescue_expression->location.end @@ -3743,11 +3978,8 @@ yp_rescue_node_create(yp_parser_t *parser, const yp_token_t *keyword) { *node = (yp_rescue_node_t) { { - .type = YP_NODE_RESCUE_NODE, - .location = { - .start = keyword->start, - .end = keyword->end - } + .type = YP_RESCUE_NODE, + .location = YP_LOCATION_TOKEN_VALUE(keyword) }, .keyword_loc = YP_LOCATION_TOKEN_VALUE(keyword), .operator_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE, @@ -3802,14 +4034,15 @@ yp_rest_parameter_node_create(yp_parser_t *parser, const yp_token_t *operator, c *node = (yp_rest_parameter_node_t) { { - .type = YP_NODE_REST_PARAMETER_NODE, + .type = YP_REST_PARAMETER_NODE, .location = { .start = operator->start, .end = (name->type == YP_TOKEN_NOT_PROVIDED ? operator->end : name->end) } }, - .operator_loc = YP_LOCATION_TOKEN_VALUE(operator), - .name_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(name) + .name = yp_parser_optional_constant_id_token(parser, name), + .name_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(name), + .operator_loc = YP_LOCATION_TOKEN_VALUE(operator) }; return node; @@ -3821,7 +4054,7 @@ yp_retry_node_create(yp_parser_t *parser, const yp_token_t *token) { assert(token->type == YP_TOKEN_KEYWORD_RETRY); yp_retry_node_t *node = YP_ALLOC_NODE(parser, yp_retry_node_t); - *node = (yp_retry_node_t) {{ .type = YP_NODE_RETRY_NODE, .location = YP_LOCATION_TOKEN_VALUE(token) }}; + *node = (yp_retry_node_t) {{ .type = YP_RETRY_NODE, .location = YP_LOCATION_TOKEN_VALUE(token) }}; return node; } @@ -3832,7 +4065,7 @@ yp_return_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_argumen *node = (yp_return_node_t) { { - .type = YP_NODE_RETURN_NODE, + .type = YP_RETURN_NODE, .location = { .start = keyword->start, .end = (arguments == NULL ? keyword->end : arguments->base.location.end) @@ -3851,7 +4084,12 @@ yp_self_node_create(yp_parser_t *parser, const yp_token_t *token) { assert(token->type == YP_TOKEN_KEYWORD_SELF); yp_self_node_t *node = YP_ALLOC_NODE(parser, yp_self_node_t); - *node = (yp_self_node_t) {{ .type = YP_NODE_SELF_NODE, .location = YP_LOCATION_TOKEN_VALUE(token) }}; + *node = (yp_self_node_t) {{ + .type = YP_SELF_NODE, + .flags = YP_NODE_FLAG_STATIC_LITERAL, + .location = YP_LOCATION_TOKEN_VALUE(token) + }}; + return node; } @@ -3862,7 +4100,7 @@ yp_singleton_class_node_create(yp_parser_t *parser, yp_constant_id_list_t *local *node = (yp_singleton_class_node_t) { { - .type = YP_NODE_SINGLETON_CLASS_NODE, + .type = YP_SINGLETON_CLASS_NODE, .location = { .start = class_keyword->start, .end = end_keyword->end @@ -3885,7 +4123,12 @@ yp_source_encoding_node_create(yp_parser_t *parser, const yp_token_t *token) { assert(token->type == YP_TOKEN_KEYWORD___ENCODING__); yp_source_encoding_node_t *node = YP_ALLOC_NODE(parser, yp_source_encoding_node_t); - *node = (yp_source_encoding_node_t) {{ .type = YP_NODE_SOURCE_ENCODING_NODE, .location = YP_LOCATION_TOKEN_VALUE(token) }}; + *node = (yp_source_encoding_node_t) {{ + .type = YP_SOURCE_ENCODING_NODE, + .flags = YP_NODE_FLAG_STATIC_LITERAL, + .location = YP_LOCATION_TOKEN_VALUE(token) + }}; + return node; } @@ -3897,7 +4140,8 @@ yp_source_file_node_create(yp_parser_t *parser, const yp_token_t *file_keyword) *node = (yp_source_file_node_t) { { - .type = YP_NODE_SOURCE_FILE_NODE, + .type = YP_SOURCE_FILE_NODE, + .flags = YP_NODE_FLAG_STATIC_LITERAL, .location = YP_LOCATION_TOKEN_VALUE(file_keyword), }, .filepath = parser->filepath_string, @@ -3912,7 +4156,12 @@ yp_source_line_node_create(yp_parser_t *parser, const yp_token_t *token) { assert(token->type == YP_TOKEN_KEYWORD___LINE__); yp_source_line_node_t *node = YP_ALLOC_NODE(parser, yp_source_line_node_t); - *node = (yp_source_line_node_t) {{ .type = YP_NODE_SOURCE_LINE_NODE, .location = YP_LOCATION_TOKEN_VALUE(token) }}; + *node = (yp_source_line_node_t) {{ + .type = YP_SOURCE_LINE_NODE, + .flags = YP_NODE_FLAG_STATIC_LITERAL, + .location = YP_LOCATION_TOKEN_VALUE(token) + }}; + return node; } @@ -3923,7 +4172,7 @@ yp_splat_node_create(yp_parser_t *parser, const yp_token_t *operator, yp_node_t *node = (yp_splat_node_t) { { - .type = YP_NODE_SPLAT_NODE, + .type = YP_SPLAT_NODE, .location = { .start = operator->start, .end = (expression == NULL ? operator->end : expression->location.end) @@ -3943,7 +4192,7 @@ yp_statements_node_create(yp_parser_t *parser) { *node = (yp_statements_node_t) { { - .type = YP_NODE_STATEMENTS_NODE, + .type = YP_STATEMENTS_NODE, .location = YP_LOCATION_NULL_VALUE(parser) }, .body = YP_EMPTY_NODE_LIST @@ -3987,7 +4236,7 @@ yp_string_concat_node_create(yp_parser_t *parser, yp_node_t *left, yp_node_t *ri *node = (yp_string_concat_node_t) { { - .type = YP_NODE_STRING_CONCAT_NODE, + .type = YP_STRING_CONCAT_NODE, .location = { .start = left->location.start, .end = right->location.end @@ -4004,10 +4253,16 @@ yp_string_concat_node_create(yp_parser_t *parser, yp_node_t *left, yp_node_t *ri static yp_string_node_t * yp_string_node_create(yp_parser_t *parser, const yp_token_t *opening, const yp_token_t *content, const yp_token_t *closing) { yp_string_node_t *node = YP_ALLOC_NODE(parser, yp_string_node_t); + yp_node_flags_t flags = 0; + + if (parser->frozen_string_literal) { + flags = YP_NODE_FLAG_STATIC_LITERAL | YP_STRING_FLAGS_FROZEN; + } *node = (yp_string_node_t) { { - .type = YP_NODE_STRING_NODE, + .type = YP_STRING_NODE, + .flags = flags, .location = { .start = (opening->type == YP_TOKEN_NOT_PROVIDED ? content->start : opening->start), .end = (closing->type == YP_TOKEN_NOT_PROVIDED ? content->end : closing->end) @@ -4030,7 +4285,7 @@ yp_super_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_argument const uint8_t *end; if (arguments->block != NULL) { - end = arguments->block->base.location.end; + end = arguments->block->location.end; } else if (arguments->closing_loc.start != NULL) { end = arguments->closing_loc.end; } else if (arguments->arguments != NULL) { @@ -4042,7 +4297,7 @@ yp_super_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_argument *node = (yp_super_node_t) { { - .type = YP_NODE_SUPER_NODE, + .type = YP_SUPER_NODE, .location = { .start = keyword->start, .end = end, @@ -4065,7 +4320,8 @@ yp_symbol_node_create(yp_parser_t *parser, const yp_token_t *opening, const yp_t *node = (yp_symbol_node_t) { { - .type = YP_NODE_SYMBOL_NODE, + .type = YP_SYMBOL_NODE, + .flags = YP_NODE_FLAG_STATIC_LITERAL, .location = { .start = (opening->type == YP_TOKEN_NOT_PROVIDED ? value->start : opening->start), .end = (closing->type == YP_TOKEN_NOT_PROVIDED ? value->end : closing->end) @@ -4122,10 +4378,10 @@ yp_symbol_node_label_p(yp_node_t *node) { const uint8_t *end = NULL; switch (YP_NODE_TYPE(node)) { - case YP_NODE_SYMBOL_NODE: + case YP_SYMBOL_NODE: end = ((yp_symbol_node_t *) node)->closing_loc.end; break; - case YP_NODE_INTERPOLATED_SYMBOL_NODE: + case YP_INTERPOLATED_SYMBOL_NODE: end = ((yp_interpolated_symbol_node_t *) node)->closing_loc.end; break; default: @@ -4142,7 +4398,8 @@ yp_string_node_to_symbol_node(yp_parser_t *parser, yp_string_node_t *node, const *new_node = (yp_symbol_node_t) { { - .type = YP_NODE_SYMBOL_NODE, + .type = YP_SYMBOL_NODE, + .flags = YP_NODE_FLAG_STATIC_LITERAL, .location = { .start = opening->start, .end = closing->end @@ -4166,10 +4423,16 @@ yp_string_node_to_symbol_node(yp_parser_t *parser, yp_string_node_t *node, const static yp_string_node_t * yp_symbol_node_to_string_node(yp_parser_t *parser, yp_symbol_node_t *node) { yp_string_node_t *new_node = YP_ALLOC_NODE(parser, yp_string_node_t); + yp_node_flags_t flags = 0; + + if (parser->frozen_string_literal) { + flags = YP_NODE_FLAG_STATIC_LITERAL | YP_STRING_FLAGS_FROZEN; + } *new_node = (yp_string_node_t) { { - .type = YP_NODE_STRING_NODE, + .type = YP_STRING_NODE, + .flags = flags, .location = node->base.location }, .opening_loc = node->opening_loc, @@ -4192,7 +4455,12 @@ yp_true_node_create(yp_parser_t *parser, const yp_token_t *token) { assert(token->type == YP_TOKEN_KEYWORD_TRUE); yp_true_node_t *node = YP_ALLOC_NODE(parser, yp_true_node_t); - *node = (yp_true_node_t) {{ .type = YP_NODE_TRUE_NODE, .location = YP_LOCATION_TOKEN_VALUE(token) }}; + *node = (yp_true_node_t) {{ + .type = YP_TRUE_NODE, + .flags = YP_NODE_FLAG_STATIC_LITERAL, + .location = YP_LOCATION_TOKEN_VALUE(token) + }}; + return node; } @@ -4204,7 +4472,7 @@ yp_undef_node_create(yp_parser_t *parser, const yp_token_t *token) { *node = (yp_undef_node_t) { { - .type = YP_NODE_UNDEF_NODE, + .type = YP_UNDEF_NODE, .location = YP_LOCATION_TOKEN_VALUE(token), }, .keyword_loc = YP_LOCATION_TOKEN_VALUE(token), @@ -4224,7 +4492,7 @@ yp_undef_node_append(yp_undef_node_t *node, yp_node_t *name) { // Allocate a new UnlessNode node. static yp_unless_node_t * yp_unless_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t *predicate, yp_statements_node_t *statements) { - yp_flip_flop(predicate); + yp_conditional_predicate(predicate); yp_unless_node_t *node = YP_ALLOC_NODE(parser, yp_unless_node_t); const uint8_t *end; @@ -4236,7 +4504,7 @@ yp_unless_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t *node = (yp_unless_node_t) { { - .type = YP_NODE_UNLESS_NODE, + .type = YP_UNLESS_NODE, .flags = YP_NODE_FLAG_NEWLINE, .location = { .start = keyword->start, @@ -4256,7 +4524,7 @@ yp_unless_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t // Allocate and initialize new UnlessNode node in the modifier form. static yp_unless_node_t * yp_unless_node_modifier_create(yp_parser_t *parser, yp_node_t *statement, const yp_token_t *unless_keyword, yp_node_t *predicate) { - yp_flip_flop(predicate); + yp_conditional_predicate(predicate); yp_unless_node_t *node = YP_ALLOC_NODE(parser, yp_unless_node_t); yp_statements_node_t *statements = yp_statements_node_create(parser); @@ -4264,7 +4532,7 @@ yp_unless_node_modifier_create(yp_parser_t *parser, yp_node_t *statement, const *node = (yp_unless_node_t) { { - .type = YP_NODE_UNLESS_NODE, + .type = YP_UNLESS_NODE, .flags = YP_NODE_FLAG_NEWLINE, .location = { .start = statement->location.start, @@ -4294,7 +4562,7 @@ yp_until_node_create(yp_parser_t *parser, const yp_token_t *keyword, const yp_to *node = (yp_until_node_t) { { - .type = YP_NODE_UNTIL_NODE, + .type = YP_UNTIL_NODE, .flags = flags, .location = { .start = keyword->start, @@ -4317,7 +4585,7 @@ yp_until_node_modifier_create(yp_parser_t *parser, const yp_token_t *keyword, yp *node = (yp_until_node_t) { { - .type = YP_NODE_UNTIL_NODE, + .type = YP_UNTIL_NODE, .flags = flags, .location = { .start = statements->base.location.start, @@ -4340,7 +4608,7 @@ yp_when_node_create(yp_parser_t *parser, const yp_token_t *keyword) { *node = (yp_when_node_t) { { - .type = YP_NODE_WHEN_NODE, + .type = YP_WHEN_NODE, .location = { .start = keyword->start, .end = NULL @@ -4378,7 +4646,7 @@ yp_while_node_create(yp_parser_t *parser, const yp_token_t *keyword, const yp_to *node = (yp_while_node_t) { { - .type = YP_NODE_WHILE_NODE, + .type = YP_WHILE_NODE, .flags = flags, .location = { .start = keyword->start, @@ -4401,7 +4669,7 @@ yp_while_node_modifier_create(yp_parser_t *parser, const yp_token_t *keyword, yp *node = (yp_while_node_t) { { - .type = YP_NODE_WHILE_NODE, + .type = YP_WHILE_NODE, .flags = flags, .location = { .start = statements->base.location.start, @@ -4424,7 +4692,7 @@ yp_xstring_node_create(yp_parser_t *parser, const yp_token_t *opening, const yp_ *node = (yp_x_string_node_t) { { - .type = YP_NODE_X_STRING_NODE, + .type = YP_X_STRING_NODE, .location = { .start = opening->start, .end = closing->end @@ -4457,7 +4725,7 @@ yp_yield_node_create(yp_parser_t *parser, const yp_token_t *keyword, const yp_lo *node = (yp_yield_node_t) { { - .type = YP_NODE_YIELD_NODE, + .type = YP_YIELD_NODE, .location = { .start = keyword->start, .end = end @@ -4474,11 +4742,6 @@ yp_yield_node_create(yp_parser_t *parser, const yp_token_t *keyword, const yp_lo #undef YP_EMPTY_STRING -#undef YP_LOCATION_NULL_VALUE -#undef YP_LOCATION_TOKEN_VALUE -#undef YP_LOCATION_NODE_VALUE -#undef YP_LOCATION_NODE_BASE_VALUE -#undef YP_TOKEN_NOT_PROVIDED_VALUE #undef YP_ALLOC_NODE /******************************************************************************/ @@ -4491,10 +4754,16 @@ yp_parser_scope_push(yp_parser_t *parser, bool closed) { yp_scope_t *scope = (yp_scope_t *) malloc(sizeof(yp_scope_t)); if (scope == NULL) return false; - *scope = (yp_scope_t) { .closed = closed, .previous = parser->current_scope }; - yp_constant_id_list_init(&scope->locals); + *scope = (yp_scope_t) { + .previous = parser->current_scope, + .closed = closed, + .explicit_params = false, + .numbered_params = false + }; + yp_constant_id_list_init(&scope->locals); parser->current_scope = scope; + return true; } @@ -4516,15 +4785,19 @@ yp_parser_local_depth(yp_parser_t *parser, yp_token_t *token) { return -1; } -// Add a local variable from a location to the current scope. -static yp_constant_id_t -yp_parser_local_add_location(yp_parser_t *parser, const uint8_t *start, const uint8_t *end) { - yp_constant_id_t constant_id = yp_parser_constant_id_location(parser, start, end); - +// Add a constant id to the local table of the current scope. +static inline void +yp_parser_local_add(yp_parser_t *parser, yp_constant_id_t constant_id) { if (!yp_constant_id_list_includes(&parser->current_scope->locals, constant_id)) { yp_constant_id_list_append(&parser->current_scope->locals, constant_id); } +} +// Add a local variable from a location to the current scope. +static yp_constant_id_t +yp_parser_local_add_location(yp_parser_t *parser, const uint8_t *start, const uint8_t *end) { + yp_constant_id_t constant_id = yp_parser_constant_id_location(parser, start, end); + if (constant_id != 0) yp_parser_local_add(parser, constant_id); return constant_id; } @@ -4534,6 +4807,13 @@ yp_parser_local_add_token(yp_parser_t *parser, yp_token_t *token) { yp_parser_local_add_location(parser, token->start, token->end); } +// Add a local variable from an owned string to the current scope. +static inline void +yp_parser_local_add_owned(yp_parser_t *parser, const uint8_t *start, size_t length) { + yp_constant_id_t constant_id = yp_parser_constant_id_owned(parser, start, length); + if (constant_id != 0) yp_parser_local_add(parser, constant_id); +} + // Add a parameter name to the current scope and check whether the name of the // parameter is unique or not. static void @@ -4546,11 +4826,13 @@ yp_parser_parameter_name_check(yp_parser_t *parser, yp_token_t *name) { yp_constant_id_t constant_id = yp_parser_constant_id_token(parser, name); if (yp_constant_id_list_includes(&parser->current_scope->locals, constant_id)) { - yp_diagnostic_list_append(&parser->error_list, name->start, name->end, "Duplicated parameter name."); + yp_diagnostic_list_append(&parser->error_list, name->start, name->end, YP_ERR_PARAMETER_NAME_REPEAT); } } -// Pop the current scope off the scope stack. +// Pop the current scope off the scope stack. Note that we specifically do not +// free the associated constant list because we assume that we have already +// transferred ownership of the list to the AST somewhere. static void yp_parser_scope_pop(yp_parser_t *parser) { yp_scope_t *scope = parser->current_scope; @@ -4789,8 +5071,7 @@ parser_lex_encoding_comment_start(yp_parser_t *parser, const uint8_t *cursor, pt static void parser_lex_encoding_comment(yp_parser_t *parser) { const uint8_t *start = parser->current.start + 1; - const uint8_t *end = next_newline(start, parser->end - start); - if (end == NULL) end = parser->end; + const uint8_t *end = parser->current.end; // These are the patterns we're going to match to find the encoding comment. // This is definitely not complete or even really correct. @@ -4887,7 +5168,40 @@ parser_lex_encoding_comment(yp_parser_t *parser) { // didn't understand the encoding that the user was trying to use. In this // case we'll keep using the default encoding but add an error to the // parser to indicate an unsuccessful parse. - yp_diagnostic_list_append(&parser->error_list, encoding_start, encoding_end, "Could not understand the encoding specified in the magic comment."); + yp_diagnostic_list_append(&parser->error_list, encoding_start, encoding_end, YP_ERR_INVALID_ENCODING_MAGIC_COMMENT); +} + +// Check if this is a magic comment that includes the frozen_string_literal +// pragma. If it does, set that field on the parser. +static void +parser_lex_frozen_string_literal_comment(yp_parser_t *parser) { + const uint8_t *cursor = parser->current.start + 1; + const uint8_t *end = parser->current.end; + + size_t key_length = strlen("frozen_string_literal"); + if (key_length > (size_t) (end - cursor)) return; + + const uint8_t *cursor_limit = cursor + (end - cursor) - key_length + 1; + + while ((cursor = yp_memchr(cursor, 'f', (size_t) (cursor_limit - cursor), parser->encoding_changed, &parser->encoding)) != NULL) { + if (memcmp(cursor, "frozen_string_literal", key_length) == 0) { + cursor += key_length; + cursor += yp_strspn_inline_whitespace(cursor, end - cursor); + + if (*cursor == ':' || *cursor == '=') { + cursor++; + cursor += yp_strspn_inline_whitespace(cursor, end - cursor); + + if (cursor + 4 <= end && yp_strncasecmp(cursor, (const uint8_t *) "true", 4) == 0) { + parser->frozen_string_literal = true; + } + + return; + } + } + + cursor++; + } } /******************************************************************************/ @@ -5019,6 +5333,45 @@ context_def_p(yp_parser_t *parser) { /* Specific token lexers */ /******************************************************************************/ +static void +yp_strspn_number_validate(yp_parser_t *parser, const uint8_t *invalid) { + if (invalid != NULL) { + yp_diagnostic_list_append(&parser->error_list, invalid, invalid + 1, YP_ERR_INVALID_NUMBER_UNDERSCORE); + } +} + +static size_t +yp_strspn_binary_number_validate(yp_parser_t *parser, const uint8_t *string) { + const uint8_t *invalid = NULL; + size_t length = yp_strspn_binary_number(string, parser->end - string, &invalid); + yp_strspn_number_validate(parser, invalid); + return length; +} + +static size_t +yp_strspn_octal_number_validate(yp_parser_t *parser, const uint8_t *string) { + const uint8_t *invalid = NULL; + size_t length = yp_strspn_octal_number(string, parser->end - string, &invalid); + yp_strspn_number_validate(parser, invalid); + return length; +} + +static size_t +yp_strspn_decimal_number_validate(yp_parser_t *parser, const uint8_t *string) { + const uint8_t *invalid = NULL; + size_t length = yp_strspn_decimal_number(string, parser->end - string, &invalid); + yp_strspn_number_validate(parser, invalid); + return length; +} + +static size_t +yp_strspn_hexadecimal_number_validate(yp_parser_t *parser, const uint8_t *string) { + const uint8_t *invalid = NULL; + size_t length = yp_strspn_hexadecimal_number(string, parser->end - string, &invalid); + yp_strspn_number_validate(parser, invalid); + return length; +} + static yp_token_type_t lex_optional_float_suffix(yp_parser_t *parser) { yp_token_type_t type = YP_TOKEN_INTEGER; @@ -5028,7 +5381,7 @@ lex_optional_float_suffix(yp_parser_t *parser) { if (peek(parser) == '.') { if (yp_char_is_decimal_digit(peek_offset(parser, 1))) { parser->current.end += 2; - parser->current.end += yp_strspn_decimal_number(parser->current.end, parser->end - parser->current.end); + parser->current.end += yp_strspn_decimal_number_validate(parser, parser->current.end); type = YP_TOKEN_FLOAT; } else { // If we had a . and then something else, then it's not a float suffix on @@ -5044,10 +5397,10 @@ lex_optional_float_suffix(yp_parser_t *parser) { if (yp_char_is_decimal_digit(*parser->current.end)) { parser->current.end++; - parser->current.end += yp_strspn_decimal_number(parser->current.end, parser->end - parser->current.end); + parser->current.end += yp_strspn_decimal_number_validate(parser, parser->current.end); type = YP_TOKEN_FLOAT; } else { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Missing exponent."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_INVALID_FLOAT_EXPONENT); type = YP_TOKEN_FLOAT; } } @@ -5066,9 +5419,9 @@ lex_numeric_prefix(yp_parser_t *parser) { case 'D': parser->current.end++; if (yp_char_is_decimal_digit(peek(parser))) { - parser->current.end += yp_strspn_decimal_number(parser->current.end, parser->end - parser->current.end); + parser->current.end += yp_strspn_decimal_number_validate(parser, parser->current.end); } else { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Invalid decimal number."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_INVALID_NUMBER_DECIMAL); } break; @@ -5078,11 +5431,12 @@ lex_numeric_prefix(yp_parser_t *parser) { case 'B': parser->current.end++; if (yp_char_is_binary_digit(peek(parser))) { - parser->current.end += yp_strspn_binary_number(parser->current.end, parser->end - parser->current.end); + parser->current.end += yp_strspn_binary_number_validate(parser, parser->current.end); } else { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Invalid binary number."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_INVALID_NUMBER_BINARY); } + parser->integer_base = YP_INTEGER_BASE_FLAGS_BINARY; break; // 0o1111 is an octal number @@ -5090,11 +5444,12 @@ lex_numeric_prefix(yp_parser_t *parser) { case 'O': parser->current.end++; if (yp_char_is_octal_digit(peek(parser))) { - parser->current.end += yp_strspn_octal_number(parser->current.end, parser->end - parser->current.end); + parser->current.end += yp_strspn_octal_number_validate(parser, parser->current.end); } else { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Invalid octal number."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_INVALID_NUMBER_OCTAL); } + parser->integer_base = YP_INTEGER_BASE_FLAGS_OCTAL; break; // 01111 is an octal number @@ -5107,7 +5462,8 @@ lex_numeric_prefix(yp_parser_t *parser) { case '5': case '6': case '7': - parser->current.end += yp_strspn_octal_number(parser->current.end, parser->end - parser->current.end); + parser->current.end += yp_strspn_octal_number_validate(parser, parser->current.end); + parser->integer_base = YP_INTEGER_BASE_FLAGS_OCTAL; break; // 0x1111 is a hexadecimal number @@ -5115,11 +5471,12 @@ lex_numeric_prefix(yp_parser_t *parser) { case 'X': parser->current.end++; if (yp_char_is_hexadecimal_digit(peek(parser))) { - parser->current.end += yp_strspn_hexadecimal_number(parser->current.end, parser->end - parser->current.end); + parser->current.end += yp_strspn_hexadecimal_number_validate(parser, parser->current.end); } else { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Invalid hexadecimal number."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_INVALID_NUMBER_HEXADECIMAL); } + parser->integer_base = YP_INTEGER_BASE_FLAGS_HEXADECIMAL; break; // 0.xxx is a float @@ -5138,24 +5495,19 @@ lex_numeric_prefix(yp_parser_t *parser) { } else { // If it didn't start with a 0, then we'll lex as far as we can into a // decimal number. - parser->current.end += yp_strspn_decimal_number(parser->current.end, parser->end - parser->current.end); + parser->current.end += yp_strspn_decimal_number_validate(parser, parser->current.end); // Afterward, we'll lex as far as we can into an optional float suffix. type = lex_optional_float_suffix(parser); } - // If the last character that we consumed was an underscore, then this is - // actually an invalid integer value, and we should return an invalid token. - if (peek_offset(parser, -1) == '_') { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Number literal cannot end with a `_`."); - } - return type; } static yp_token_type_t lex_numeric(yp_parser_t *parser) { yp_token_type_t type = YP_TOKEN_INTEGER; + parser->integer_base = YP_INTEGER_BASE_FLAGS_DECIMAL; if (parser->current.end < parser->end) { type = lex_numeric_prefix(parser); @@ -5199,7 +5551,7 @@ lex_numeric(yp_parser_t *parser) { static yp_token_type_t lex_global_variable(yp_parser_t *parser) { if (parser->current.end >= parser->end) { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Invalid global variable."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_INVALID_VARIABLE_GLOBAL); return YP_TOKEN_GLOBAL_VARIABLE; } @@ -5240,7 +5592,7 @@ lex_global_variable(yp_parser_t *parser) { } while (parser->current.end < parser->end && (width = char_is_identifier(parser, parser->current.end)) > 0); // $0 isn't allowed to be followed by anything. - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Invalid global variable."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_INVALID_VARIABLE_GLOBAL); } return YP_TOKEN_GLOBAL_VARIABLE; @@ -5271,7 +5623,7 @@ lex_global_variable(yp_parser_t *parser) { } else { // If we get here, then we have a $ followed by something that isn't // recognized as a global variable. - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Invalid global variable."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_INVALID_VARIABLE_GLOBAL); } return YP_TOKEN_GLOBAL_VARIABLE; @@ -5500,7 +5852,7 @@ lex_interpolation(yp_parser_t *parser, const uint8_t *pound) { // If we didn't get an valid interpolation, then this is just regular // string content. This is like if we get "#@-". In this case the caller // should keep lexing. - parser->current.end = variable; + parser->current.end = pound + 1; return YP_TOKEN_NOT_PROVIDED; } case '$': @@ -5611,7 +5963,7 @@ lex_question_mark(yp_parser_t *parser) { } if (parser->current.end >= parser->end) { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Incomplete character syntax."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_INCOMPLETE_QUESTION_MARK); return YP_TOKEN_CHARACTER_LITERAL; } @@ -5662,9 +6014,9 @@ lex_at_variable(yp_parser_t *parser) { parser->current.end += width; } } else if (type == YP_TOKEN_CLASS_VARIABLE) { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Incomplete class variable."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_INCOMPLETE_VARIABLE_CLASS); } else { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Incomplete instance variable."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_INCOMPLETE_VARIABLE_INSTANCE); } // If we're lexing an embedded variable, then we need to pop back into the @@ -5763,7 +6115,7 @@ lex_embdoc(yp_parser_t *parser) { parser_lex_callback(parser); } - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Unterminated embdoc"); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_EMBDOC_TERM); comment->end = parser->current.end; yp_list_append(&parser->comment_list, (yp_list_node_t *) comment); @@ -5815,6 +6167,11 @@ parser_lex(yp_parser_t *parser) { // already seen a comment. bool lexed_comment = false; + // Here we cache the current value of the semantic token seen flag. This is + // used to reset it in case we find a token that shouldn't flip this flag. + unsigned int semantic_token_seen = parser->semantic_token_seen; + parser->semantic_token_seen = true; + switch (parser->lex_modes.current->mode) { case YP_LEX_DEFAULT: case YP_LEX_EMBEXPR: @@ -5901,10 +6258,7 @@ parser_lex(yp_parser_t *parser) { case '#': { // comments const uint8_t *ending = next_newline(parser->current.end, parser->end - parser->current.end); - - parser->current.end = ending == NULL ? parser->end : ending + 1; - parser->current.type = YP_TOKEN_COMMENT; - parser_lex_callback(parser); + parser->current.end = ending == NULL ? parser->end : ending; // If we found a comment while lexing, then we're going to // add it to the list of comments in the file and keep @@ -5912,16 +6266,26 @@ parser_lex(yp_parser_t *parser) { yp_comment_t *comment = parser_comment(parser, YP_COMMENT_INLINE); yp_list_append(&parser->comment_list, (yp_list_node_t *) comment); + if (ending) parser->current.end++; + parser->current.type = YP_TOKEN_COMMENT; + parser_lex_callback(parser); + if (parser->current.start == parser->encoding_comment_start) { parser_lex_encoding_comment(parser); } + if (!semantic_token_seen) { + parser_lex_frozen_string_literal_comment(parser); + } + lexed_comment = true; } /* fallthrough */ case '\r': case '\n': { + parser->semantic_token_seen = semantic_token_seen & 0x1; size_t eol_length = match_eol_at(parser, parser->current.end - 1); + if (eol_length) { // The only way you can have carriage returns in this // particular loop is if you have a carriage return @@ -6193,7 +6557,7 @@ parser_lex(yp_parser_t *parser) { yp_token_type_t type = YP_TOKEN_STAR; if (lex_state_spcarg_p(parser, space_seen)) { - yp_diagnostic_list_append(&parser->warning_list, parser->current.start, parser->current.end, "`*' interpreted as argument prefix"); + yp_diagnostic_list_append(&parser->warning_list, parser->current.start, parser->current.end, YP_WARN_AMBIGUOUS_PREFIX_STAR); type = YP_TOKEN_USTAR; } else if (lex_state_beg_p(parser)) { type = YP_TOKEN_USTAR; @@ -6337,7 +6701,7 @@ parser_lex(yp_parser_t *parser) { // this is not a valid heredoc declaration. In this case we // will add an error, but we will still return a heredoc // start. - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Unterminated heredoc."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_EMBDOC_TERM); body_start = parser->end; } else { // Otherwise, we want to indicate that the body of the @@ -6534,7 +6898,7 @@ parser_lex(yp_parser_t *parser) { &parser->warning_list, parser->current.start, parser->current.end, - "ambiguous first argument; put parentheses or a space even after `+` operator" + YP_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS ); } @@ -6583,7 +6947,7 @@ parser_lex(yp_parser_t *parser) { &parser->warning_list, parser->current.start, parser->current.end, - "ambiguous first argument; put parentheses or a space even after `-` operator" + YP_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS ); } @@ -6681,7 +7045,7 @@ parser_lex(yp_parser_t *parser) { } if (lex_state_spcarg_p(parser, space_seen)) { - yp_diagnostic_list_append(&parser->warning_list, parser->current.start, parser->current.end, "ambiguity between regexp and two divisions: wrap regexp in parentheses or add a space after `/' operator"); + yp_diagnostic_list_append(&parser->warning_list, parser->current.start, parser->current.end, YP_WARN_AMBIGUOUS_SLASH); lex_mode_push_regexp(parser, '\0', '/'); LEX(YP_TOKEN_REGEXP_BEGIN); } @@ -6716,11 +7080,12 @@ parser_lex(yp_parser_t *parser) { // % %= %i %I %q %Q %w %W case '%': { - // If there is no subsequent character then we have an invalid token. We're - // going to say it's the percent operator because we don't want to move into the - // string lex mode unnecessarily. + // If there is no subsequent character then we have an + // invalid token. We're going to say it's the percent + // operator because we don't want to move into the string + // lex mode unnecessarily. if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->current.end >= parser->end)) { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Unexpected end of input"); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_INVALID_PERCENT); LEX(YP_TOKEN_PERCENT); } @@ -6749,6 +7114,14 @@ parser_lex(yp_parser_t *parser) { } } + // Delimiters for %-literals cannot be alphanumeric. We + // validate that here. + uint8_t delimiter = peek_offset(parser, 1); + if (delimiter >= 0x80 || parser->encoding.alnum_char(&delimiter, 1)) { + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_INVALID_PERCENT); + goto lex_next_token; + } + switch (peek(parser)) { case 'i': { parser->current.end++; @@ -6845,7 +7218,7 @@ parser_lex(yp_parser_t *parser) { // unparseable. In this case we'll just drop it from the parser // and skip past it and hope that the next token is something // that we can parse. - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Invalid %% token"); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_INVALID_PERCENT); goto lex_next_token; } } @@ -6881,7 +7254,7 @@ parser_lex(yp_parser_t *parser) { // token as we've exhausted all of the other options. We'll skip past // it and return the next token. if (!width) { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Invalid token."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_INVALID_TOKEN); goto lex_next_token; } @@ -6900,6 +7273,14 @@ parser_lex(yp_parser_t *parser) { (parser->current.end == parser->end || match_eol(parser)) ) { + // Since we know we're about to add an __END__ comment, we know we + // need at add all of the newlines to get the correct column + // information for it. + const uint8_t *cursor = parser->current.end; + while ((cursor = next_newline(cursor, parser->end - cursor)) != NULL) { + yp_newline_list_append(&parser->newline_list, cursor++); + } + parser->current.end = parser->end; parser->current.type = YP_TOKEN___END__; parser_lex_callback(parser); @@ -6952,9 +7333,16 @@ parser_lex(yp_parser_t *parser) { // going to trim it off the beginning and create a new token. size_t whitespace; - bool should_stop = parser->heredoc_end; + if (parser->heredoc_end) { + whitespace = yp_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end); + if (peek_offset(parser, (ptrdiff_t)whitespace) == '\n') { + whitespace += 1; + } + } else { + whitespace = yp_strspn_whitespace_newlines(parser->current.end, parser->end - parser->current.end, &parser->newline_list); + } - if ((whitespace = yp_strspn_whitespace_newlines(parser->current.end, parser->end - parser->current.end, &parser->newline_list, should_stop)) > 0) { + if (whitespace > 0) { parser->current.end += whitespace; if (peek_offset(parser, -1) == '\n') { // mutates next_start @@ -7597,29 +7985,6 @@ yp_xstring_node_create_and_unescape(yp_parser_t *parser, const yp_token_t *openi return node; } -// Returns true if the current token is of the specified type. -static inline bool -match_type_p(yp_parser_t *parser, yp_token_type_t type) { - return parser->current.type == type; -} - -// Returns true if the current token is of any of the specified types. -static bool -match_any_type_p(yp_parser_t *parser, size_t count, ...) { - va_list types; - va_start(types, count); - - for (size_t index = 0; index < count; index++) { - if (match_type_p(parser, va_arg(types, yp_token_type_t))) { - va_end(types); - return true; - } - } - - va_end(types); - return false; -} - // These are the various precedence rules. Because we are using a Pratt parser, // they are named binding power to represent the manner in which nodes are bound // together in the stack. @@ -7720,29 +8085,29 @@ yp_binding_powers_t yp_binding_powers[YP_TOKEN_MAXIMUM] = { [YP_TOKEN_AMPERSAND_AMPERSAND] = LEFT_ASSOCIATIVE(YP_BINDING_POWER_LOGICAL_AND), // != !~ == === =~ <=> - [YP_TOKEN_BANG_EQUAL] = RIGHT_ASSOCIATIVE(YP_BINDING_POWER_EQUALITY), - [YP_TOKEN_BANG_TILDE] = RIGHT_ASSOCIATIVE(YP_BINDING_POWER_EQUALITY), - [YP_TOKEN_EQUAL_EQUAL] = RIGHT_ASSOCIATIVE(YP_BINDING_POWER_EQUALITY), - [YP_TOKEN_EQUAL_EQUAL_EQUAL] = RIGHT_ASSOCIATIVE(YP_BINDING_POWER_EQUALITY), - [YP_TOKEN_EQUAL_TILDE] = RIGHT_ASSOCIATIVE(YP_BINDING_POWER_EQUALITY), - [YP_TOKEN_LESS_EQUAL_GREATER] = RIGHT_ASSOCIATIVE(YP_BINDING_POWER_EQUALITY), + [YP_TOKEN_BANG_EQUAL] = LEFT_ASSOCIATIVE(YP_BINDING_POWER_EQUALITY), + [YP_TOKEN_BANG_TILDE] = LEFT_ASSOCIATIVE(YP_BINDING_POWER_EQUALITY), + [YP_TOKEN_EQUAL_EQUAL] = LEFT_ASSOCIATIVE(YP_BINDING_POWER_EQUALITY), + [YP_TOKEN_EQUAL_EQUAL_EQUAL] = LEFT_ASSOCIATIVE(YP_BINDING_POWER_EQUALITY), + [YP_TOKEN_EQUAL_TILDE] = LEFT_ASSOCIATIVE(YP_BINDING_POWER_EQUALITY), + [YP_TOKEN_LESS_EQUAL_GREATER] = LEFT_ASSOCIATIVE(YP_BINDING_POWER_EQUALITY), // > >= < <= - [YP_TOKEN_GREATER] = RIGHT_ASSOCIATIVE(YP_BINDING_POWER_COMPARISON), - [YP_TOKEN_GREATER_EQUAL] = RIGHT_ASSOCIATIVE(YP_BINDING_POWER_COMPARISON), - [YP_TOKEN_LESS] = RIGHT_ASSOCIATIVE(YP_BINDING_POWER_COMPARISON), - [YP_TOKEN_LESS_EQUAL] = RIGHT_ASSOCIATIVE(YP_BINDING_POWER_COMPARISON), + [YP_TOKEN_GREATER] = LEFT_ASSOCIATIVE(YP_BINDING_POWER_COMPARISON), + [YP_TOKEN_GREATER_EQUAL] = LEFT_ASSOCIATIVE(YP_BINDING_POWER_COMPARISON), + [YP_TOKEN_LESS] = LEFT_ASSOCIATIVE(YP_BINDING_POWER_COMPARISON), + [YP_TOKEN_LESS_EQUAL] = LEFT_ASSOCIATIVE(YP_BINDING_POWER_COMPARISON), // ^ | - [YP_TOKEN_CARET] = RIGHT_ASSOCIATIVE(YP_BINDING_POWER_BITWISE_OR), - [YP_TOKEN_PIPE] = RIGHT_ASSOCIATIVE(YP_BINDING_POWER_BITWISE_OR), + [YP_TOKEN_CARET] = LEFT_ASSOCIATIVE(YP_BINDING_POWER_BITWISE_OR), + [YP_TOKEN_PIPE] = LEFT_ASSOCIATIVE(YP_BINDING_POWER_BITWISE_OR), // & - [YP_TOKEN_AMPERSAND] = RIGHT_ASSOCIATIVE(YP_BINDING_POWER_BITWISE_AND), + [YP_TOKEN_AMPERSAND] = LEFT_ASSOCIATIVE(YP_BINDING_POWER_BITWISE_AND), // >> << - [YP_TOKEN_GREATER_GREATER] = RIGHT_ASSOCIATIVE(YP_BINDING_POWER_SHIFT), - [YP_TOKEN_LESS_LESS] = RIGHT_ASSOCIATIVE(YP_BINDING_POWER_SHIFT), + [YP_TOKEN_GREATER_GREATER] = LEFT_ASSOCIATIVE(YP_BINDING_POWER_SHIFT), + [YP_TOKEN_LESS_LESS] = LEFT_ASSOCIATIVE(YP_BINDING_POWER_SHIFT), // - + [YP_TOKEN_MINUS] = LEFT_ASSOCIATIVE(YP_BINDING_POWER_TERM), @@ -7756,7 +8121,7 @@ yp_binding_powers_t yp_binding_powers[YP_TOKEN_MAXIMUM] = { // -@ [YP_TOKEN_UMINUS] = RIGHT_ASSOCIATIVE_UNARY(YP_BINDING_POWER_UMINUS), - [YP_TOKEN_UMINUS_NUM] = RIGHT_ASSOCIATIVE_UNARY(YP_BINDING_POWER_UMINUS), + [YP_TOKEN_UMINUS_NUM] = { YP_BINDING_POWER_UMINUS, YP_BINDING_POWER_MAX, false }, // ** [YP_TOKEN_STAR_STAR] = RIGHT_ASSOCIATIVE(YP_BINDING_POWER_EXPONENT), @@ -7781,39 +8146,81 @@ yp_binding_powers_t yp_binding_powers[YP_TOKEN_MAXIMUM] = { #undef RIGHT_ASSOCIATIVE #undef RIGHT_ASSOCIATIVE_UNARY +// Returns true if the current token is of the given type. +static inline bool +match1(const yp_parser_t *parser, yp_token_type_t type) { + return parser->current.type == type; +} + +// Returns true if the current token is of either of the given types. +static inline bool +match2(const yp_parser_t *parser, yp_token_type_t type1, yp_token_type_t type2) { + return match1(parser, type1) || match1(parser, type2); +} + +// Returns true if the current token is any of the three given types. +static inline bool +match3(const yp_parser_t *parser, yp_token_type_t type1, yp_token_type_t type2, yp_token_type_t type3) { + return match1(parser, type1) || match1(parser, type2) || match1(parser, type3); +} + +// Returns true if the current token is any of the five given types. +static inline bool +match5(const yp_parser_t *parser, yp_token_type_t type1, yp_token_type_t type2, yp_token_type_t type3, yp_token_type_t type4, yp_token_type_t type5) { + return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5); +} + +// Returns true if the current token is any of the six given types. +static inline bool +match6(const yp_parser_t *parser, yp_token_type_t type1, yp_token_type_t type2, yp_token_type_t type3, yp_token_type_t type4, yp_token_type_t type5, yp_token_type_t type6) { + return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6); +} + +// Returns true if the current token is any of the seven given types. +static inline bool +match7(const yp_parser_t *parser, yp_token_type_t type1, yp_token_type_t type2, yp_token_type_t type3, yp_token_type_t type4, yp_token_type_t type5, yp_token_type_t type6, yp_token_type_t type7) { + return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7); +} + +// Returns true if the current token is any of the eight given types. +static inline bool +match8(const yp_parser_t *parser, yp_token_type_t type1, yp_token_type_t type2, yp_token_type_t type3, yp_token_type_t type4, yp_token_type_t type5, yp_token_type_t type6, yp_token_type_t type7, yp_token_type_t type8) { + 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); +} + // If the current token is of the specified type, lex forward by one token and // return true. Otherwise, return false. For example: // -// if (accept(parser, YP_TOKEN_COLON)) { ... } +// if (accept1(parser, YP_TOKEN_COLON)) { ... } // static bool -accept(yp_parser_t *parser, yp_token_type_t type) { - if (match_type_p(parser, type)) { +accept1(yp_parser_t *parser, yp_token_type_t type) { + if (match1(parser, type)) { parser_lex(parser); return true; } return false; } -// If the current token is of any of the specified types, lex forward by one -// token and return true. Otherwise, return false. For example: -// -// if (accept_any(parser, 2, YP_TOKEN_COLON, YP_TOKEN_SEMICOLON)) { ... } -// -static bool -accept_any(yp_parser_t *parser, size_t count, ...) { - va_list types; - va_start(types, count); - - for (size_t index = 0; index < count; index++) { - if (match_type_p(parser, va_arg(types, yp_token_type_t))) { - parser_lex(parser); - va_end(types); - return true; - } +// If the current token is either of the two given types, lex forward by one +// token and return true. Otherwise return false. +static inline bool +accept2(yp_parser_t *parser, yp_token_type_t type1, yp_token_type_t type2) { + if (match2(parser, type1, type2)) { + parser_lex(parser); + return true; } + return false; +} - va_end(types); +// If the current token is any of the three given types, lex forward by one +// token and return true. Otherwise return false. +static inline bool +accept3(yp_parser_t *parser, yp_token_type_t type1, yp_token_type_t type2, yp_token_type_t type3) { + if (match3(parser, type1, type2, type3)) { + parser_lex(parser); + return true; + } return false; } @@ -7827,36 +8234,31 @@ accept_any(yp_parser_t *parser, size_t count, ...) { // valid) and create an artificial token instead. This allows us to recover from // the fact that the token isn't present and continue parsing. static void -expect(yp_parser_t *parser, yp_token_type_t type, const char *message) { - if (accept(parser, type)) return; +expect1(yp_parser_t *parser, yp_token_type_t type, yp_diagnostic_id_t diag_id) { + if (accept1(parser, type)) return; - yp_diagnostic_list_append(&parser->error_list, parser->previous.end, parser->previous.end, message); + const uint8_t *location = parser->previous.end; + yp_diagnostic_list_append(&parser->error_list, location, location, diag_id); - parser->previous = - (yp_token_t) { .type = YP_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end }; + parser->previous.start = location; + parser->previous.type = YP_TOKEN_MISSING; } +// This function is the same as expect1, but it expects either of two token +// types. static void -expect_any(yp_parser_t *parser, const char*message, size_t count, ...) { - va_list types; - va_start(types, count); - - for (size_t index = 0; index < count; index++) { - if (accept(parser, va_arg(types, yp_token_type_t))) { - va_end(types); - return; - } - } +expect2(yp_parser_t *parser, yp_token_type_t type1, yp_token_type_t type2, yp_diagnostic_id_t diag_id) { + if (accept2(parser, type1, type2)) return; - va_end(types); + const uint8_t *location = parser->previous.end; + yp_diagnostic_list_append(&parser->error_list, location, location, diag_id); - yp_diagnostic_list_append(&parser->error_list, parser->previous.end, parser->previous.end, message); - parser->previous = - (yp_token_t) { .type = YP_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end }; + parser->previous.start = location; + parser->previous.type = YP_TOKEN_MISSING; } static yp_node_t * -parse_expression(yp_parser_t *parser, yp_binding_power_t binding_power, const char *message); +parse_expression(yp_parser_t *parser, yp_binding_power_t binding_power, yp_diagnostic_id_t diag_id); // This function controls whether or not we will attempt to parse an expression // beginning at the subsequent token. It is used when we are in a context where @@ -7933,76 +8335,98 @@ token_begins_expression_p(yp_token_type_t type) { // Parse an expression with the given binding power that may be optionally // prefixed by the * operator. static yp_node_t * -parse_starred_expression(yp_parser_t *parser, yp_binding_power_t binding_power, const char *message) { - if (accept(parser, YP_TOKEN_USTAR)) { +parse_starred_expression(yp_parser_t *parser, yp_binding_power_t binding_power, yp_diagnostic_id_t diag_id) { + if (accept1(parser, YP_TOKEN_USTAR)) { yp_token_t operator = parser->previous; - yp_node_t *expression = parse_expression(parser, binding_power, "Expected expression after `*'."); + yp_node_t *expression = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_STAR); return (yp_node_t *) yp_splat_node_create(parser, &operator, expression); } - return parse_expression(parser, binding_power, message); + return parse_expression(parser, binding_power, diag_id); +} + +// Convert the name of a method into the corresponding write method name. For +// exmaple, foo would be turned into foo=. +static void +parse_write_name(yp_string_t *string) { + // The method name needs to change. If we previously had + // foo, we now need foo=. In this case we'll allocate a new + // owned string, copy the previous method name in, and + // append an =. + size_t length = yp_string_length(string); + uint8_t *name = calloc(length + 1, sizeof(uint8_t)); + if (name == NULL) return; + + memcpy(name, yp_string_source(string), length); + name[length] = '='; + + // Now switch the name to the new string. + yp_string_free(string); + yp_string_owned_init(string, name, length + 1); } // Convert the given node into a valid target node. static yp_node_t * parse_target(yp_parser_t *parser, yp_node_t *target) { switch (YP_NODE_TYPE(target)) { - case YP_NODE_MISSING_NODE: + case YP_MISSING_NODE: return target; - case YP_NODE_CLASS_VARIABLE_READ_NODE: + case YP_CLASS_VARIABLE_READ_NODE: assert(sizeof(yp_class_variable_target_node_t) == sizeof(yp_class_variable_read_node_t)); - target->type = YP_NODE_CLASS_VARIABLE_TARGET_NODE; + target->type = YP_CLASS_VARIABLE_TARGET_NODE; return target; - case YP_NODE_CONSTANT_PATH_NODE: + case YP_CONSTANT_PATH_NODE: assert(sizeof(yp_constant_path_target_node_t) == sizeof(yp_constant_path_node_t)); - target->type = YP_NODE_CONSTANT_PATH_TARGET_NODE; + target->type = YP_CONSTANT_PATH_TARGET_NODE; return target; - case YP_NODE_CONSTANT_READ_NODE: + case YP_CONSTANT_READ_NODE: assert(sizeof(yp_constant_target_node_t) == sizeof(yp_constant_read_node_t)); - target->type = YP_NODE_CONSTANT_TARGET_NODE; + target->type = YP_CONSTANT_TARGET_NODE; return target; - case YP_NODE_BACK_REFERENCE_READ_NODE: - assert(sizeof(yp_global_variable_target_node_t) == sizeof(yp_back_reference_read_node_t)); - /* fallthrough */ - case YP_NODE_NUMBERED_REFERENCE_READ_NODE: - assert(sizeof(yp_global_variable_target_node_t) == sizeof(yp_numbered_reference_read_node_t)); - yp_diagnostic_list_append(&parser->error_list, target->location.start, target->location.end, "Can't set variable"); - /* fallthrough */ - case YP_NODE_GLOBAL_VARIABLE_READ_NODE: + case YP_BACK_REFERENCE_READ_NODE: + case YP_NUMBERED_REFERENCE_READ_NODE: + yp_diagnostic_list_append(&parser->error_list, target->location.start, target->location.end, YP_ERR_WRITE_TARGET_READONLY); + return target; + case YP_GLOBAL_VARIABLE_READ_NODE: assert(sizeof(yp_global_variable_target_node_t) == sizeof(yp_global_variable_read_node_t)); - target->type = YP_NODE_GLOBAL_VARIABLE_TARGET_NODE; + target->type = YP_GLOBAL_VARIABLE_TARGET_NODE; return target; - case YP_NODE_LOCAL_VARIABLE_READ_NODE: - assert(sizeof(yp_local_variable_target_node_t) == sizeof(yp_local_variable_read_node_t)); - target->type = YP_NODE_LOCAL_VARIABLE_TARGET_NODE; + case YP_LOCAL_VARIABLE_READ_NODE: + if (token_is_numbered_parameter(target->location.start, target->location.end)) { + yp_diagnostic_list_append(&parser->error_list, target->location.start, target->location.end, YP_ERR_PARAMETER_NUMBERED_RESERVED); + } else { + assert(sizeof(yp_local_variable_target_node_t) == sizeof(yp_local_variable_read_node_t)); + target->type = YP_LOCAL_VARIABLE_TARGET_NODE; + } + return target; - case YP_NODE_INSTANCE_VARIABLE_READ_NODE: + case YP_INSTANCE_VARIABLE_READ_NODE: assert(sizeof(yp_instance_variable_target_node_t) == sizeof(yp_instance_variable_read_node_t)); - target->type = YP_NODE_INSTANCE_VARIABLE_TARGET_NODE; + target->type = YP_INSTANCE_VARIABLE_TARGET_NODE; return target; - case YP_NODE_MULTI_WRITE_NODE: + case YP_MULTI_TARGET_NODE: return target; - case YP_NODE_SPLAT_NODE: { + case YP_SPLAT_NODE: { yp_splat_node_t *splat = (yp_splat_node_t *) target; if (splat->expression != NULL) { splat->expression = parse_target(parser, splat->expression); } - yp_token_t operator = not_provided(parser); - yp_location_t location = { .start = NULL, .end = NULL }; - - yp_multi_write_node_t *multi_write = yp_multi_write_node_create(parser, &operator, NULL, &location, &location); - yp_multi_write_node_targets_append(multi_write, (yp_node_t *) splat); + yp_multi_target_node_t *multi_target = yp_multi_target_node_create(parser); + yp_multi_target_node_targets_append(multi_target, (yp_node_t *) splat); - return (yp_node_t *) multi_write; + return (yp_node_t *) multi_target; } - case YP_NODE_CALL_NODE: { + case YP_CALL_NODE: { yp_call_node_t *call = (yp_call_node_t *) target; // If we have no arguments to the call node and we need this to be a // target then this is either a method call or a local variable write. if ( + (call->message_loc.start != NULL) && + (call->message_loc.end[-1] != '!') && + (call->message_loc.end[-1] != '?') && (call->opening_loc.start == NULL) && (call->arguments == NULL) && (call->block == NULL) @@ -8026,38 +8450,27 @@ parse_target(yp_parser_t *parser, yp_node_t *target) { target = (yp_node_t *) yp_local_variable_read_node_create(parser, &name, 0); assert(sizeof(yp_local_variable_target_node_t) == sizeof(yp_local_variable_read_node_t)); - target->type = YP_NODE_LOCAL_VARIABLE_TARGET_NODE; + target->type = YP_LOCAL_VARIABLE_TARGET_NODE; if (token_is_numbered_parameter(message.start, message.end)) { - yp_diagnostic_list_append(&parser->error_list, message.start, message.end, "reserved for numbered parameter"); + yp_diagnostic_list_append(&parser->error_list, message.start, message.end, YP_ERR_PARAMETER_NUMBERED_RESERVED); } return target; } - // The method name needs to change. If we previously had foo, we now - // need foo=. In this case we'll allocate a new owned string, copy - // the previous method name in, and append an =. - size_t length = yp_string_length(&call->name); - - uint8_t *name = calloc(length + 1, sizeof(uint8_t)); - if (name == NULL) return NULL; - - memcpy(name, yp_string_source(&call->name), length); - name[length] = '='; - - // Now switch the name to the new string. - yp_string_free(&call->name); - yp_string_owned_init(&call->name, name, length + 1); - - return target; + if (*call->message_loc.start == '_' || parser->encoding.alnum_char(call->message_loc.start, call->message_loc.end - call->message_loc.start)) { + parse_write_name(&call->name); + return (yp_node_t *) call; + } } // If there is no call operator and the message is "[]" then this is // an aref expression, and we can transform it into an aset // expression. if ( - (call->operator_loc.start == NULL) && + (call->call_operator_loc.start == NULL) && + (call->message_loc.start != NULL) && (call->message_loc.start[0] == '[') && (call->message_loc.end[-1] == ']') && (call->block == NULL) @@ -8073,39 +8486,57 @@ parse_target(yp_parser_t *parser, yp_node_t *target) { // In this case we have a node that we don't know how to convert // into a target. We need to treat it as an error. For now, we'll // mark it as an error and just skip right past it. - yp_diagnostic_list_append(&parser->error_list, target->location.start, target->location.end, "Unexpected write target."); + yp_diagnostic_list_append(&parser->error_list, target->location.start, target->location.end, YP_ERR_WRITE_TARGET_UNEXPECTED); return target; } } +// Parse a write targets and validate that it is in a valid position for +// assignment. +static yp_node_t * +parse_target_validate(yp_parser_t *parser, yp_node_t *target) { + yp_node_t *result = parse_target(parser, target); + + // Ensure that we have either an = or a ) after the targets. + if (!match3(parser, YP_TOKEN_EQUAL, YP_TOKEN_PARENTHESIS_RIGHT, YP_TOKEN_KEYWORD_IN)) { + yp_diagnostic_list_append(&parser->error_list, result->location.start, result->location.end, YP_ERR_WRITE_TARGET_UNEXPECTED); + } + + return result; +} + // Convert the given node into a valid write node. static yp_node_t * parse_write(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_node_t *value) { switch (YP_NODE_TYPE(target)) { - case YP_NODE_MISSING_NODE: + case YP_MISSING_NODE: return target; - case YP_NODE_CLASS_VARIABLE_READ_NODE: { + case YP_CLASS_VARIABLE_READ_NODE: { yp_class_variable_write_node_t *node = yp_class_variable_write_node_create(parser, (yp_class_variable_read_node_t *) target, operator, value); yp_node_destroy(parser, target); return (yp_node_t *) node; } - case YP_NODE_CONSTANT_PATH_NODE: + case YP_CONSTANT_PATH_NODE: return (yp_node_t *) yp_constant_path_write_node_create(parser, (yp_constant_path_node_t *) target, operator, value); - case YP_NODE_CONSTANT_READ_NODE: { - yp_constant_write_node_t *node = yp_constant_write_node_create(parser, &target->location, operator, value); + case YP_CONSTANT_READ_NODE: { + yp_constant_write_node_t *node = yp_constant_write_node_create(parser, (yp_constant_read_node_t *) target, operator, value); yp_node_destroy(parser, target); return (yp_node_t *) node; } - case YP_NODE_BACK_REFERENCE_READ_NODE: - case YP_NODE_NUMBERED_REFERENCE_READ_NODE: - yp_diagnostic_list_append(&parser->error_list, target->location.start, target->location.end, "Can't set variable"); + case YP_BACK_REFERENCE_READ_NODE: + case YP_NUMBERED_REFERENCE_READ_NODE: + yp_diagnostic_list_append(&parser->error_list, target->location.start, target->location.end, YP_ERR_WRITE_TARGET_READONLY); /* fallthrough */ - case YP_NODE_GLOBAL_VARIABLE_READ_NODE: { + case YP_GLOBAL_VARIABLE_READ_NODE: { yp_global_variable_write_node_t *node = yp_global_variable_write_node_create(parser, target, operator, value); yp_node_destroy(parser, target); return (yp_node_t *) node; } - case YP_NODE_LOCAL_VARIABLE_READ_NODE: { + case YP_LOCAL_VARIABLE_READ_NODE: { + if (token_is_numbered_parameter(target->location.start, target->location.end)) { + yp_diagnostic_list_append(&parser->error_list, target->location.start, target->location.end, YP_ERR_PARAMETER_NUMBERED_RESERVED); + } + yp_local_variable_read_node_t *local_read = (yp_local_variable_read_node_t *) target; yp_constant_id_t constant_id = local_read->name; @@ -8116,37 +8547,35 @@ parse_write(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_nod return (yp_node_t *) yp_local_variable_write_node_create(parser, constant_id, depth, value, &name_loc, operator); } - case YP_NODE_INSTANCE_VARIABLE_READ_NODE: { + case YP_INSTANCE_VARIABLE_READ_NODE: { yp_node_t *write_node = (yp_node_t *) yp_instance_variable_write_node_create(parser, (yp_instance_variable_read_node_t *) target, operator, value); yp_node_destroy(parser, target); return write_node; } - case YP_NODE_MULTI_WRITE_NODE: { - yp_multi_write_node_t *multi_write = (yp_multi_write_node_t *) target; - yp_multi_write_node_operator_loc_set(multi_write, operator); - - multi_write->value = value; - multi_write->base.location.end = value->location.end; - return (yp_node_t *) multi_write; - } - case YP_NODE_SPLAT_NODE: { + case YP_MULTI_TARGET_NODE: + return (yp_node_t *) yp_multi_write_node_create(parser, (yp_multi_target_node_t *) target, operator, value); + case YP_SPLAT_NODE: { yp_splat_node_t *splat = (yp_splat_node_t *) target; if (splat->expression != NULL) { splat->expression = parse_write(parser, splat->expression, operator, value); } - yp_location_t location = { .start = NULL, .end = NULL }; - yp_multi_write_node_t *multi_write = yp_multi_write_node_create(parser, operator, value, &location, &location); - yp_multi_write_node_targets_append(multi_write, (yp_node_t *) splat); + yp_multi_target_node_t *multi_target = yp_multi_target_node_create(parser); + yp_multi_target_node_targets_append(multi_target, (yp_node_t *) splat); - return (yp_node_t *) multi_write; + return (yp_node_t *) yp_multi_write_node_create(parser, multi_target, operator, value); } - case YP_NODE_CALL_NODE: { + case YP_CALL_NODE: { yp_call_node_t *call = (yp_call_node_t *) target; + // If we have no arguments to the call node and we need this to be a - // target then this is either a method call or a local variable write. + // target then this is either a method call or a local variable + // write. if ( + (call->message_loc.start != NULL) && + (call->message_loc.end[-1] != '!') && + (call->message_loc.end[-1] != '?') && (call->opening_loc.start == NULL) && (call->arguments == NULL) && (call->block == NULL) @@ -8170,50 +8599,39 @@ parse_write(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_nod target = (yp_node_t *) yp_local_variable_write_node_create(parser, constant_id, 0, value, &message, operator); if (token_is_numbered_parameter(message.start, message.end)) { - yp_diagnostic_list_append(&parser->error_list, message.start, message.end, "reserved for numbered parameter"); + yp_diagnostic_list_append(&parser->error_list, message.start, message.end, YP_ERR_PARAMETER_NUMBERED_RESERVED); } return target; } - // When we get here, we have a method call, because it was - // previously marked as a method call but now we have an =. This - // looks like: - // - // foo.bar = 1 - // - // When it was parsed in the prefix position, foo.bar was seen as a - // method call with no arguments. Now we have an =, so we know it's - // a method call with an argument. In this case we will create the - // arguments node, parse the argument, and add it to the list. - yp_arguments_node_t *arguments = yp_arguments_node_create(parser); - call->arguments = arguments; - yp_arguments_node_arguments_append(arguments, value); - target->location.end = arguments->base.location.end; - - // The method name needs to change. If we previously had foo, we now - // need foo=. In this case we'll allocate a new owned string, copy - // the previous method name in, and append an =. - size_t length = yp_string_length(&call->name); - - uint8_t *name = calloc(length + 1, sizeof(uint8_t)); - if (name == NULL) return NULL; - - memcpy(name, yp_string_source(&call->name), length); - name[length] = '='; - - // Now switch the name to the new string. - yp_string_free(&call->name); - yp_string_owned_init(&call->name, name, length + 1); + if (*call->message_loc.start == '_' || parser->encoding.alnum_char(call->message_loc.start, call->message_loc.end - call->message_loc.start)) { + // When we get here, we have a method call, because it was + // previously marked as a method call but now we have an =. This + // looks like: + // + // foo.bar = 1 + // + // When it was parsed in the prefix position, foo.bar was seen as a + // method call with no arguments. Now we have an =, so we know it's + // a method call with an argument. In this case we will create the + // arguments node, parse the argument, and add it to the list. + yp_arguments_node_t *arguments = yp_arguments_node_create(parser); + call->arguments = arguments; - return target; + yp_arguments_node_arguments_append(arguments, value); + call->base.location.end = arguments->base.location.end; + + parse_write_name(&call->name); + return (yp_node_t *) call; + } } // If there is no call operator and the message is "[]" then this is // an aref expression, and we can transform it into an aset // expression. if ( - (call->operator_loc.start == NULL) && + (call->call_operator_loc.start == NULL) && (call->message_loc.start[0] == '[') && (call->message_loc.end[-1] == ']') && (call->block == NULL) @@ -8243,7 +8661,7 @@ parse_write(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_nod // In this case we have a node that we don't know how to convert into a // target. We need to treat it as an error. For now, we'll mark it as an // error and just skip right past it. - yp_diagnostic_list_append(&parser->error_list, operator->start, operator->end, "Unexpected `='."); + yp_diagnostic_list_append(&parser->error_list, operator->start, operator->end, YP_ERR_WRITE_TARGET_UNEXPECTED); return target; } } @@ -8258,123 +8676,61 @@ parse_write(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_nod // target node or a multi-target node. static yp_node_t * parse_targets(yp_parser_t *parser, yp_node_t *first_target, yp_binding_power_t binding_power) { - yp_token_t operator = not_provided(parser); - - // The first_target parameter can be NULL in the case that we're parsing a - // location that we know requires a multi write, as in the case of a for loop. - // In this case we will set up the parsing loop slightly differently. - if (first_target != NULL) { - first_target = parse_target(parser, first_target); - - if (!match_type_p(parser, YP_TOKEN_COMMA)) { - return first_target; - } - } - - yp_location_t lparen_loc = { .start = NULL, .end = NULL }; - yp_multi_write_node_t *result = yp_multi_write_node_create(parser, &operator, NULL, &lparen_loc, &lparen_loc); - - if (first_target != NULL) { - yp_multi_write_node_targets_append(result, first_target); - } + bool has_splat = YP_NODE_TYPE_P(first_target, YP_SPLAT_NODE); - bool has_splat = false; + yp_multi_target_node_t *result = yp_multi_target_node_create(parser); + yp_multi_target_node_targets_append(result, parse_target(parser, first_target)); - if (first_target == NULL || accept(parser, YP_TOKEN_COMMA)) { - do { - if (accept(parser, YP_TOKEN_USTAR)) { - // Here we have a splat operator. It can have a name or be anonymous. It - // can be the final target or be in the middle if there haven't been any - // others yet. - - if (has_splat) { - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Multiple splats in multi-assignment."); - } + while (accept1(parser, YP_TOKEN_COMMA)) { + if (accept1(parser, YP_TOKEN_USTAR)) { + // Here we have a splat operator. It can have a name or be + // anonymous. It can be the final target or be in the middle if + // there haven't been any others yet. + if (has_splat) { + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_MULTI_ASSIGN_MULTI_SPLATS); + } - yp_token_t star_operator = parser->previous; - yp_node_t *name = NULL; + yp_token_t star_operator = parser->previous; + yp_node_t *name = NULL; - if (token_begins_expression_p(parser->current.type)) { - name = parse_expression(parser, binding_power, "Expected an expression after '*'."); - name = parse_target(parser, name); - } - - yp_node_t *splat = (yp_node_t *) yp_splat_node_create(parser, &star_operator, name); - yp_multi_write_node_targets_append(result, splat); - has_splat = true; - } else if (accept(parser, YP_TOKEN_PARENTHESIS_LEFT)) { - // Here we have a parenthesized list of targets. We'll recurse down into - // the parentheses by calling parse_targets again and then finish out - // the node when it returns. - - yp_token_t lparen = parser->previous; - yp_node_t *first_child_target = parse_expression(parser, YP_BINDING_POWER_STATEMENT, "Expected an expression after '('."); - yp_node_t *child_target = parse_targets(parser, first_child_target, YP_BINDING_POWER_STATEMENT); - - expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected an ')' after multi-assignment."); - yp_token_t rparen = parser->previous; - - if (YP_NODE_TYPE_P(child_target, YP_NODE_MULTI_WRITE_NODE) && first_target == NULL && result->targets.size == 0) { - yp_node_destroy(parser, (yp_node_t *) result); - result = (yp_multi_write_node_t *) child_target; - result->base.location.start = lparen.start; - result->base.location.end = rparen.end; - result->lparen_loc = (yp_location_t) { .start = lparen.start, .end = lparen.end }; - result->rparen_loc = (yp_location_t) { .start = rparen.start, .end = rparen.end }; - } else { - yp_multi_write_node_t *target; - - if (YP_NODE_TYPE_P(child_target, YP_NODE_MULTI_WRITE_NODE)) { - target = (yp_multi_write_node_t *) child_target; - target->base.location.start = lparen.start; - target->base.location.end = rparen.end; - target->lparen_loc = (yp_location_t) { .start = lparen.start, .end = lparen.end }; - target->rparen_loc = (yp_location_t) { .start = rparen.start, .end = rparen.end }; - } else { - yp_token_t operator = not_provided(parser); - - target = yp_multi_write_node_create( - parser, - &operator, - NULL, - &(yp_location_t) { .start = lparen.start, .end = lparen.end }, - &(yp_location_t) { .start = rparen.start, .end = rparen.end } - ); + if (token_begins_expression_p(parser->current.type)) { + name = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_STAR); + name = parse_target(parser, name); + } - yp_multi_write_node_targets_append(target, child_target); - } + yp_node_t *splat = (yp_node_t *) yp_splat_node_create(parser, &star_operator, name); + yp_multi_target_node_targets_append(result, splat); + has_splat = true; + } else if (token_begins_expression_p(parser->current.type)) { + yp_node_t *target = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_COMMA); + target = parse_target(parser, target); - target->base.location.start = lparen.start; - target->base.location.end = rparen.end; - yp_multi_write_node_targets_append(result, (yp_node_t *) target); - } - } else { - if (!token_begins_expression_p(parser->current.type) && !match_type_p(parser, YP_TOKEN_USTAR)) { - if (first_target == NULL && result->targets.size == 0) { - // If we get here, then we weren't able to parse anything at all, so - // we need to return a missing node. - yp_node_destroy(parser, (yp_node_t *) result); - yp_diagnostic_list_append(&parser->error_list, operator.start, operator.end, "Expected index after for."); - return (yp_node_t *) yp_missing_node_create(parser, operator.start, operator.end); - } + yp_multi_target_node_targets_append(result, target); + } else { + // If we get here, then we have a trailing , in a multi target node. + // We need to indicate this somehow in the tree, so we'll add an + // anonymous splat. + yp_node_t *splat = (yp_node_t *) yp_splat_node_create(parser, &parser->previous, NULL); + yp_multi_target_node_targets_append(result, splat); + break; + } + } - // If we get here, then we have a trailing , in a multi write node. - // We need to indicate this somehow in the tree, so we'll add an - // anonymous splat. - yp_node_t *splat = (yp_node_t *) yp_splat_node_create(parser, &parser->previous, NULL); - yp_multi_write_node_targets_append(result, splat); - return (yp_node_t *) result; - } + return (yp_node_t *) result; +} - yp_node_t *target = parse_expression(parser, binding_power, "Expected another expression after ','."); - target = parse_target(parser, target); +// Parse a list of targets and validate that it is in a valid position for +// assignment. +static yp_node_t * +parse_targets_validate(yp_parser_t *parser, yp_node_t *first_target, yp_binding_power_t binding_power) { + yp_node_t *result = parse_targets(parser, first_target, binding_power); - yp_multi_write_node_targets_append(result, target); - } - } while (accept(parser, YP_TOKEN_COMMA)); + // Ensure that we have either an = or a ) after the targets. + if (!match2(parser, YP_TOKEN_EQUAL, YP_TOKEN_PARENTHESIS_RIGHT)) { + yp_diagnostic_list_append(&parser->error_list, result->location.start, result->location.end, YP_ERR_WRITE_TARGET_UNEXPECTED); } - return (yp_node_t *) result; + return result; } // Parse a list of statements separated by newlines or semicolons. @@ -8382,7 +8738,7 @@ static yp_statements_node_t * parse_statements(yp_parser_t *parser, yp_context_t context) { // First, skip past any optional terminators that might be at the beginning of // the statements. - while (accept_any(parser, 2, YP_TOKEN_SEMICOLON, YP_TOKEN_NEWLINE)); + while (accept2(parser, YP_TOKEN_SEMICOLON, YP_TOKEN_NEWLINE)); // If we have a terminator, then we can just return NULL. if (context_terminator(context, &parser->current)) return NULL; @@ -8394,7 +8750,7 @@ parse_statements(yp_parser_t *parser, yp_context_t context) { context_push(parser, context); while (true) { - yp_node_t *node = parse_expression(parser, YP_BINDING_POWER_STATEMENT, "Expected to be able to parse an expression."); + yp_node_t *node = parse_expression(parser, YP_BINDING_POWER_STATEMENT, YP_ERR_CANNOT_PARSE_EXPRESSION); yp_statements_node_body_append(statements, node); // If we're recovering from a syntax error, then we need to stop parsing the @@ -8408,10 +8764,10 @@ parse_statements(yp_parser_t *parser, yp_context_t context) { // If we have a terminator, then we will parse all consequtive terminators // and then continue parsing the statements list. - if (accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)) { + if (accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)) { // If we have a terminator, then we will continue parsing the statements // list. - while (accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)); + while (accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)); if (context_terminator(context, &parser->current)) break; // Now we can continue parsing the list of statements. @@ -8433,13 +8789,13 @@ parse_statements(yp_parser_t *parser, yp_context_t context) { // were unable to parse an expression, then we will skip past this token and // continue parsing the statements list. Otherwise we'll add an error and // continue parsing the statements list. - if (YP_NODE_TYPE_P(node, YP_NODE_MISSING_NODE)) { + if (YP_NODE_TYPE_P(node, YP_MISSING_NODE)) { parser_lex(parser); - while (accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)); + while (accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)); if (context_terminator(context, &parser->current)) break; } else { - expect(parser, YP_TOKEN_NEWLINE, "Expected a newline or semicolon after statement."); + expect1(parser, YP_TOKEN_NEWLINE, YP_ERR_EXPECT_EOL_AFTER_STATEMENT); } } @@ -8450,7 +8806,7 @@ parse_statements(yp_parser_t *parser, yp_context_t context) { // Parse all of the elements of a hash. static void parse_assocs(yp_parser_t *parser, yp_node_t *node) { - assert(YP_NODE_TYPE_P(node, YP_NODE_HASH_NODE) || YP_NODE_TYPE_P(node, YP_NODE_KEYWORD_HASH_NODE)); + assert(YP_NODE_TYPE_P(node, YP_HASH_NODE) || YP_NODE_TYPE_P(node, YP_KEYWORD_HASH_NODE)); while (true) { yp_node_t *element; @@ -8462,57 +8818,75 @@ parse_assocs(yp_parser_t *parser, yp_node_t *node) { yp_node_t *value = NULL; if (token_begins_expression_p(parser->current.type)) { - value = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected an expression after ** in hash."); + value = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH); } else if (yp_parser_local_depth(parser, &operator) == -1) { - yp_diagnostic_list_append(&parser->error_list, operator.start, operator.end, "Expected an expression after ** in hash."); + yp_diagnostic_list_append(&parser->error_list, operator.start, operator.end, YP_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH); } element = (yp_node_t *) yp_assoc_splat_node_create(parser, value, &operator); break; } case YP_TOKEN_LABEL: { + yp_token_t label = parser->current; parser_lex(parser); - yp_node_t *key = (yp_node_t *) yp_symbol_node_label_create(parser, &parser->previous); + yp_node_t *key = (yp_node_t *) yp_symbol_node_label_create(parser, &label); yp_token_t operator = not_provided(parser); yp_node_t *value = NULL; if (token_begins_expression_p(parser->current.type)) { - value = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected an expression after the label in hash."); + value = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_HASH_EXPRESSION_AFTER_LABEL); + } else { + if (parser->encoding.isupper_char(label.start, (label.end - 1) - label.start)) { + yp_token_t constant = { .type = YP_TOKEN_CONSTANT, .start = label.start, .end = label.end - 1 }; + value = (yp_node_t *) yp_constant_read_node_create(parser, &constant); + } else { + int depth = yp_parser_local_depth(parser, &((yp_token_t) { .type = YP_TOKEN_IDENTIFIER, .start = label.start, .end = label.end - 1 })); + yp_token_t identifier = { .type = YP_TOKEN_IDENTIFIER, .start = label.start, .end = label.end - 1 }; + + if (depth == -1) { + value = (yp_node_t *) yp_call_node_variable_call_create(parser, &identifier); + } else { + value = (yp_node_t *) yp_local_variable_read_node_create(parser, &identifier, (uint32_t) depth); + } + } + + value->location.end++; + value = (yp_node_t *) yp_implicit_node_create(parser, value); } element = (yp_node_t *) yp_assoc_node_create(parser, key, &operator, value); break; } default: { - yp_node_t *key = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected a key in the hash literal."); + yp_node_t *key = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_HASH_KEY); yp_token_t operator; if (yp_symbol_node_label_p(key)) { operator = not_provided(parser); } else { - expect(parser, YP_TOKEN_EQUAL_GREATER, "Expected a => between the key and the value in the hash."); + expect1(parser, YP_TOKEN_EQUAL_GREATER, YP_ERR_HASH_ROCKET); operator = parser->previous; } - yp_node_t *value = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected a value in the hash literal."); + yp_node_t *value = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_HASH_VALUE); element = (yp_node_t *) yp_assoc_node_create(parser, key, &operator, value); break; } } - if (YP_NODE_TYPE_P(node, YP_NODE_HASH_NODE)) { + if (YP_NODE_TYPE_P(node, YP_HASH_NODE)) { yp_hash_node_elements_append((yp_hash_node_t *) node, element); } else { yp_keyword_hash_node_elements_append((yp_keyword_hash_node_t *) node, element); } // If there's no comma after the element, then we're done. - if (!accept(parser, YP_TOKEN_COMMA)) return; + if (!accept1(parser, YP_TOKEN_COMMA)) return; // If the next element starts with a label or a **, then we know we have // another element in the hash, so we'll continue parsing. - if (match_any_type_p(parser, 2, YP_TOKEN_USTAR_STAR, YP_TOKEN_LABEL)) continue; + if (match2(parser, YP_TOKEN_USTAR_STAR, YP_TOKEN_LABEL)) continue; // Otherwise we need to check if the subsequent token begins an expression. // If it does, then we'll continue parsing. @@ -8523,6 +8897,16 @@ parse_assocs(yp_parser_t *parser, yp_node_t *node) { } } +// Append an argument to a list of arguments. +static inline void +parse_arguments_append(yp_parser_t *parser, yp_arguments_t *arguments, yp_node_t *argument) { + if (arguments->arguments == NULL) { + arguments->arguments = yp_arguments_node_create(parser); + } + + yp_arguments_node_arguments_append(arguments->arguments, argument); +} + // Parse a list of arguments. static void parse_arguments(yp_parser_t *parser, yp_arguments_t *arguments, bool accepts_forwarding, yp_token_type_t terminator) { @@ -8531,7 +8915,7 @@ parse_arguments(yp_parser_t *parser, yp_arguments_t *arguments, bool accepts_for // First we need to check if the next token is one that could be the start of // an argument. If it's not, then we can just return. if ( - match_any_type_p(parser, 2, terminator, YP_TOKEN_EOF) || + match2(parser, terminator, YP_TOKEN_EOF) || (binding_power != YP_BINDING_POWER_UNSET && binding_power < YP_BINDING_POWER_RANGE) || context_terminator(parser->current_context->context, &parser->current) ) { @@ -8541,9 +8925,9 @@ parse_arguments(yp_parser_t *parser, yp_arguments_t *arguments, bool accepts_for bool parsed_bare_hash = false; bool parsed_block_argument = false; - while (!match_type_p(parser, YP_TOKEN_EOF)) { + while (!match1(parser, YP_TOKEN_EOF)) { if (parsed_block_argument) { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Unexpected argument after block argument."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_ARGUMENT_AFTER_BLOCK); } yp_node_t *argument = NULL; @@ -8552,17 +8936,18 @@ parse_arguments(yp_parser_t *parser, yp_arguments_t *arguments, bool accepts_for case YP_TOKEN_USTAR_STAR: case YP_TOKEN_LABEL: { if (parsed_bare_hash) { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Unexpected bare hash."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_ARGUMENT_BARE_HASH); } yp_keyword_hash_node_t *hash = yp_keyword_hash_node_create(parser); - argument = (yp_node_t *)hash; + argument = (yp_node_t *) hash; - if (!match_any_type_p(parser, 7, terminator, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON, YP_TOKEN_EOF, YP_TOKEN_BRACE_RIGHT, YP_TOKEN_KEYWORD_DO, YP_TOKEN_PARENTHESIS_RIGHT)) { + if (!match7(parser, terminator, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON, YP_TOKEN_EOF, YP_TOKEN_BRACE_RIGHT, YP_TOKEN_KEYWORD_DO, YP_TOKEN_PARENTHESIS_RIGHT)) { parse_assocs(parser, (yp_node_t *) hash); } parsed_bare_hash = true; + parse_arguments_append(parser, arguments, argument); break; } case YP_TOKEN_UAMPERSAND: { @@ -8571,36 +8956,42 @@ parse_arguments(yp_parser_t *parser, yp_arguments_t *arguments, bool accepts_for yp_node_t *expression = NULL; if (token_begins_expression_p(parser->current.type)) { - expression = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected to be able to parse an argument."); + expression = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_EXPECT_ARGUMENT); } else if (yp_parser_local_depth(parser, &operator) == -1) { - yp_diagnostic_list_append(&parser->error_list, operator.start, operator.end, "unexpected & when parent method is not forwarding."); + yp_diagnostic_list_append(&parser->error_list, operator.start, operator.end, YP_ERR_ARGUMENT_NO_FORWARDING_AMP); + } + + argument = (yp_node_t *) yp_block_argument_node_create(parser, &operator, expression); + if (parsed_block_argument) { + parse_arguments_append(parser, arguments, argument); + } else { + arguments->block = argument; } - argument = (yp_node_t *)yp_block_argument_node_create(parser, &operator, expression); parsed_block_argument = true; - arguments->implicit_block = true; break; } case YP_TOKEN_USTAR: { parser_lex(parser); yp_token_t operator = parser->previous; - if (match_any_type_p(parser, 2, YP_TOKEN_PARENTHESIS_RIGHT, YP_TOKEN_COMMA)) { + if (match2(parser, YP_TOKEN_PARENTHESIS_RIGHT, YP_TOKEN_COMMA)) { if (yp_parser_local_depth(parser, &parser->previous) == -1) { - yp_diagnostic_list_append(&parser->error_list, operator.start, operator.end, "unexpected * when parent method is not forwarding."); + yp_diagnostic_list_append(&parser->error_list, operator.start, operator.end, YP_ERR_ARGUMENT_NO_FORWARDING_STAR); } argument = (yp_node_t *) yp_splat_node_create(parser, &operator, NULL); } else { - yp_node_t *expression = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected an expression after '*' in argument."); + yp_node_t *expression = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_EXPECT_EXPRESSION_AFTER_SPLAT); if (parsed_bare_hash) { - yp_diagnostic_list_append(&parser->error_list, operator.start, expression->location.end, "Unexpected splat argument after double splat."); + yp_diagnostic_list_append(&parser->error_list, operator.start, expression->location.end, YP_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT); } argument = (yp_node_t *) yp_splat_node_create(parser, &operator, expression); } + parse_arguments_append(parser, arguments, argument); break; } case YP_TOKEN_UDOT_DOT_DOT: { @@ -8611,14 +9002,15 @@ parse_arguments(yp_parser_t *parser, yp_arguments_t *arguments, bool accepts_for // If the token begins an expression then this ... was not actually // argument forwarding but was instead a range. yp_token_t operator = parser->previous; - yp_node_t *right = parse_expression(parser, YP_BINDING_POWER_RANGE, "Expected a value after the operator."); + yp_node_t *right = parse_expression(parser, YP_BINDING_POWER_RANGE, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); argument = (yp_node_t *) yp_range_node_create(parser, NULL, &operator, right); } else { if (yp_parser_local_depth(parser, &parser->previous) == -1) { - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "unexpected ... when parent method is not forwarding."); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES); } - argument = (yp_node_t *)yp_forwarding_arguments_node_create(parser, &parser->previous); + argument = (yp_node_t *) yp_forwarding_arguments_node_create(parser, &parser->previous); + parse_arguments_append(parser, arguments, argument); break; } } @@ -8626,12 +9018,12 @@ parse_arguments(yp_parser_t *parser, yp_arguments_t *arguments, bool accepts_for /* fallthrough */ default: { if (argument == NULL) { - argument = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected to be able to parse an argument."); + argument = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_EXPECT_ARGUMENT); } - if (yp_symbol_node_label_p(argument) || accept(parser, YP_TOKEN_EQUAL_GREATER)) { + if (yp_symbol_node_label_p(argument) || accept1(parser, YP_TOKEN_EQUAL_GREATER)) { if (parsed_bare_hash) { - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Unexpected bare hash argument."); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_ARGUMENT_BARE_HASH); } yp_token_t operator; @@ -8644,16 +9036,16 @@ parse_arguments(yp_parser_t *parser, yp_arguments_t *arguments, bool accepts_for yp_keyword_hash_node_t *bare_hash = yp_keyword_hash_node_create(parser); // Finish parsing the one we are part way through - yp_node_t *value = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected a value in the hash literal."); + yp_node_t *value = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_HASH_VALUE); argument = (yp_node_t *) yp_assoc_node_create(parser, argument, &operator, value); yp_keyword_hash_node_elements_append(bare_hash, argument); argument = (yp_node_t *) bare_hash; // Then parse more if we have a comma - if (accept(parser, YP_TOKEN_COMMA) && ( + if (accept1(parser, YP_TOKEN_COMMA) && ( token_begins_expression_p(parser->current.type) || - match_any_type_p(parser, 2, YP_TOKEN_USTAR_STAR, YP_TOKEN_LABEL) + match2(parser, YP_TOKEN_USTAR_STAR, YP_TOKEN_LABEL) )) { parse_assocs(parser, (yp_node_t *) bare_hash); } @@ -8661,19 +9053,18 @@ parse_arguments(yp_parser_t *parser, yp_arguments_t *arguments, bool accepts_for parsed_bare_hash = true; } + parse_arguments_append(parser, arguments, argument); break; } } - yp_arguments_node_arguments_append(arguments->arguments, argument); - // If parsing the argument failed, we need to stop parsing arguments. - if (YP_NODE_TYPE_P(argument, YP_NODE_MISSING_NODE) || parser->recovering) break; + if (YP_NODE_TYPE_P(argument, YP_MISSING_NODE) || parser->recovering) break; // If the terminator of these arguments is not EOF, then we have a specific // token we're looking for. In that case we can accept a newline here // because it is not functioning as a statement terminator. - if (terminator != YP_TOKEN_EOF) accept(parser, YP_TOKEN_NEWLINE); + if (terminator != YP_TOKEN_EOF) accept1(parser, YP_TOKEN_NEWLINE); if (parser->previous.type == YP_TOKEN_COMMA && parsed_bare_hash) { // If we previously were on a comma and we just parsed a bare hash, then @@ -8682,12 +9073,12 @@ parse_arguments(yp_parser_t *parser, yp_arguments_t *arguments, bool accepts_for } else { // If there is no comma at the end of the argument list then we're done // parsing arguments and can break out of this loop. - if (!accept(parser, YP_TOKEN_COMMA)) break; + if (!accept1(parser, YP_TOKEN_COMMA)) break; } // If we hit the terminator, then that means we have a trailing comma so we // can accept that output as well. - if (match_type_p(parser, terminator)) break; + if (match1(parser, terminator)) break; } } @@ -8700,7 +9091,7 @@ parse_arguments(yp_parser_t *parser, yp_arguments_t *arguments, bool accepts_for // It can recurse infinitely down, and splats are allowed to group arguments. static yp_required_destructured_parameter_node_t * parse_required_destructured_parameter(yp_parser_t *parser) { - expect(parser, YP_TOKEN_PARENTHESIS_LEFT, "Expected '(' to start a required parameter."); + expect1(parser, YP_TOKEN_PARENTHESIS_LEFT, YP_ERR_EXPECT_LPAREN_REQ_PARAMETER); yp_token_t opening = parser->previous; yp_required_destructured_parameter_node_t *node = yp_required_destructured_parameter_node_create(parser, &opening); @@ -8709,9 +9100,9 @@ parse_required_destructured_parameter(yp_parser_t *parser) { do { yp_node_t *param; - if (node->parameters.size > 0 && match_type_p(parser, YP_TOKEN_PARENTHESIS_RIGHT)) { + if (node->parameters.size > 0 && match1(parser, YP_TOKEN_PARENTHESIS_RIGHT)) { if (parsed_splat) { - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Unexpected splat after splat."); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_ARGUMENT_SPLAT_AFTER_SPLAT); } param = (yp_node_t *) yp_splat_node_create(parser, &parser->previous, NULL); @@ -8719,17 +9110,17 @@ parse_required_destructured_parameter(yp_parser_t *parser) { break; } - if (match_type_p(parser, YP_TOKEN_PARENTHESIS_LEFT)) { + if (match1(parser, YP_TOKEN_PARENTHESIS_LEFT)) { param = (yp_node_t *) parse_required_destructured_parameter(parser); - } else if (accept(parser, YP_TOKEN_USTAR)) { + } else if (accept1(parser, YP_TOKEN_USTAR)) { if (parsed_splat) { - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Unexpected splat after splat."); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_ARGUMENT_SPLAT_AFTER_SPLAT); } yp_token_t star = parser->previous; yp_node_t *value = NULL; - if (accept(parser, YP_TOKEN_IDENTIFIER)) { + if (accept1(parser, YP_TOKEN_IDENTIFIER)) { yp_token_t name = parser->previous; value = (yp_node_t *) yp_required_parameter_node_create(parser, &name); yp_parser_local_add_token(parser, &name); @@ -8738,7 +9129,7 @@ parse_required_destructured_parameter(yp_parser_t *parser) { param = (yp_node_t *) yp_splat_node_create(parser, &star, value); parsed_splat = true; } else { - expect(parser, YP_TOKEN_IDENTIFIER, "Expected an identifier for a required parameter."); + expect1(parser, YP_TOKEN_IDENTIFIER, YP_ERR_EXPECT_IDENT_REQ_PARAMETER); yp_token_t name = parser->previous; param = (yp_node_t *) yp_required_parameter_node_create(parser, &name); @@ -8746,9 +9137,9 @@ parse_required_destructured_parameter(yp_parser_t *parser) { } yp_required_destructured_parameter_node_append_parameter(node, param); - } while (accept(parser, YP_TOKEN_COMMA)); + } while (accept1(parser, YP_TOKEN_COMMA)); - expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected ')' to end a required parameter."); + expect1(parser, YP_TOKEN_PARENTHESIS_RIGHT, YP_ERR_EXPECT_RPAREN_REQ_PARAMETER); yp_required_destructured_parameter_node_closing_set(node, &parser->previous); return node; @@ -8803,12 +9194,12 @@ update_parameter_state(yp_parser_t *parser, yp_token_t *token, yp_parameters_ord } if (token->type == YP_TOKEN_USTAR && *current == YP_PARAMETERS_ORDER_AFTER_OPTIONAL) { - yp_diagnostic_list_append(&parser->error_list, token->start, token->end, "Unexpected parameter *"); + yp_diagnostic_list_append(&parser->error_list, token->start, token->end, YP_ERR_PARAMETER_STAR); } if (*current == YP_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) { // We know what transition we failed on, so we can provide a better error here. - yp_diagnostic_list_append(&parser->error_list, token->start, token->end, "Unexpected parameter order"); + yp_diagnostic_list_append(&parser->error_list, token->start, token->end, YP_ERR_PARAMETER_ORDER); } else if (state < *current) { *current = state; } @@ -8850,7 +9241,7 @@ parse_parameters( yp_token_t operator = parser->previous; yp_token_t name; - if (accept(parser, YP_TOKEN_IDENTIFIER)) { + if (accept1(parser, YP_TOKEN_IDENTIFIER)) { name = parser->previous; yp_parser_parameter_name_check(parser, &name); yp_parser_local_add_token(parser, &name); @@ -8863,7 +9254,7 @@ parse_parameters( if (params->block == NULL) { yp_parameters_node_block_set(params, param); } else { - yp_diagnostic_list_append(&parser->error_list, param->base.location.start, param->base.location.end, "Unexpected multiple block parameter"); + yp_diagnostic_list_append(&parser->error_list, param->base.location.start, param->base.location.end, YP_ERR_PARAMETER_BLOCK_MULTI); yp_parameters_node_posts_append(params, (yp_node_t *) param); } @@ -8871,7 +9262,7 @@ parse_parameters( } case YP_TOKEN_UDOT_DOT_DOT: { if (!allows_forwarding_parameter) { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Unexpected ..."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES); } if (order > YP_PARAMETERS_ORDER_NOTHING_AFTER) { update_parameter_state(parser, &parser->current, &order); @@ -8894,16 +9285,16 @@ parse_parameters( parser_lex(parser); switch (parser->previous.type) { case YP_TOKEN_CONSTANT: - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Formal argument cannot be a constant"); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_ARGUMENT_FORMAL_CONSTANT); break; case YP_TOKEN_INSTANCE_VARIABLE: - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Formal argument cannot be an instance variable"); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_ARGUMENT_FORMAL_IVAR); break; case YP_TOKEN_GLOBAL_VARIABLE: - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Formal argument cannot be a global variable"); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_ARGUMENT_FORMAL_GLOBAL); break; case YP_TOKEN_CLASS_VARIABLE: - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Formal argument cannot be a class variable"); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_ARGUMENT_FORMAL_CLASS); break; default: break; } @@ -8918,10 +9309,10 @@ parse_parameters( yp_parser_parameter_name_check(parser, &name); yp_parser_local_add_token(parser, &name); - if (accept(parser, YP_TOKEN_EQUAL)) { + if (accept1(parser, YP_TOKEN_EQUAL)) { yp_token_t operator = parser->previous; context_push(parser, YP_CONTEXT_DEFAULT_PARAMS); - yp_node_t *value = parse_expression(parser, binding_power, "Expected to find a default value for the parameter."); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_PARAMETER_NO_DEFAULT); yp_optional_parameter_node_t *param = yp_optional_parameter_node_create(parser, &name, &operator, value); yp_parameters_node_optionals_append(params, param); @@ -8979,7 +9370,7 @@ parse_parameters( yp_node_t *value = NULL; if (token_begins_expression_p(parser->current.type)) { context_push(parser, YP_CONTEXT_DEFAULT_PARAMS); - value = parse_expression(parser, binding_power, "Expected to find a default value for the keyword parameter."); + value = parse_expression(parser, binding_power, YP_ERR_PARAMETER_NO_DEFAULT_KW); context_pop(parser); } @@ -9007,7 +9398,7 @@ parse_parameters( yp_token_t operator = parser->previous; yp_token_t name; - if (accept(parser, YP_TOKEN_IDENTIFIER)) { + if (accept1(parser, YP_TOKEN_IDENTIFIER)) { name = parser->previous; yp_parser_parameter_name_check(parser, &name); yp_parser_local_add_token(parser, &name); @@ -9020,7 +9411,7 @@ parse_parameters( if (params->rest == NULL) { yp_parameters_node_rest_set(params, param); } else { - yp_diagnostic_list_append(&parser->error_list, param->base.location.start, param->base.location.end, "Unexpected multiple splat parameters."); + yp_diagnostic_list_append(&parser->error_list, param->base.location.start, param->base.location.end, YP_ERR_PARAMETER_SPLAT_MULTI); yp_parameters_node_posts_append(params, (yp_node_t *) param); } @@ -9034,12 +9425,12 @@ parse_parameters( yp_token_t operator = parser->previous; yp_node_t *param; - if (accept(parser, YP_TOKEN_KEYWORD_NIL)) { + if (accept1(parser, YP_TOKEN_KEYWORD_NIL)) { param = (yp_node_t *) yp_no_keywords_parameter_node_create(parser, &operator, &parser->previous); } else { yp_token_t name; - if (accept(parser, YP_TOKEN_IDENTIFIER)) { + if (accept1(parser, YP_TOKEN_IDENTIFIER)) { name = parser->previous; yp_parser_parameter_name_check(parser, &name); yp_parser_local_add_token(parser, &name); @@ -9054,7 +9445,7 @@ parse_parameters( if (params->keyword_rest == NULL) { yp_parameters_node_keyword_rest_set(params, param); } else { - yp_diagnostic_list_append(&parser->error_list, param->location.start, param->location.end, "Unexpected multiple double splat parameters."); + yp_diagnostic_list_append(&parser->error_list, param->location.start, param->location.end, YP_ERR_PARAMETER_ASSOC_SPLAT_MULTI); yp_parameters_node_posts_append(params, param); } @@ -9072,11 +9463,11 @@ parse_parameters( if (params->rest == NULL) { yp_parameters_node_rest_set(params, param); } else { - yp_diagnostic_list_append(&parser->error_list, param->base.location.start, param->base.location.end, "Unexpected multiple splat parameters."); + yp_diagnostic_list_append(&parser->error_list, param->base.location.start, param->base.location.end, YP_ERR_PARAMETER_SPLAT_MULTI); yp_parameters_node_posts_append(params, (yp_node_t *) param); } } else { - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Unexpected ','."); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_PARAMETER_WILD_LOOSE_COMMA); } } @@ -9085,9 +9476,9 @@ parse_parameters( } if (looping && uses_parentheses) { - accept(parser, YP_TOKEN_NEWLINE); + accept1(parser, YP_TOKEN_NEWLINE); } - } while (looping && accept(parser, YP_TOKEN_COMMA)); + } while (looping && accept1(parser, YP_TOKEN_COMMA)); yp_do_loop_stack_pop(parser); @@ -9106,7 +9497,7 @@ static inline void parse_rescues(yp_parser_t *parser, yp_begin_node_t *parent_node) { yp_rescue_node_t *current = NULL; - while (accept(parser, YP_TOKEN_KEYWORD_RESCUE)) { + while (accept1(parser, YP_TOKEN_KEYWORD_RESCUE)) { yp_rescue_node_t *rescue = yp_rescue_node_create(parser, &parser->previous); switch (parser->current.type) { @@ -9117,7 +9508,7 @@ parse_rescues(yp_parser_t *parser, yp_begin_node_t *parent_node) { parser_lex(parser); yp_rescue_node_operator_set(rescue, &parser->previous); - yp_node_t *reference = parse_expression(parser, YP_BINDING_POWER_INDEX, "Expected an exception variable after `=>` in rescue statement."); + yp_node_t *reference = parse_expression(parser, YP_BINDING_POWER_INDEX, YP_ERR_RESCUE_VARIABLE); reference = parse_target(parser, reference); yp_rescue_node_reference_set(rescue, reference); @@ -9130,48 +9521,48 @@ parse_rescues(yp_parser_t *parser, yp_begin_node_t *parent_node) { // going to just continue on. break; default: { - if (token_begins_expression_p(parser->current.type) || match_type_p(parser, YP_TOKEN_USTAR)) { + if (token_begins_expression_p(parser->current.type) || match1(parser, YP_TOKEN_USTAR)) { // Here we have something that could be an exception expression, so // we'll attempt to parse it here and any others delimited by commas. do { - yp_node_t *expression = parse_starred_expression(parser, YP_BINDING_POWER_DEFINED, "Expected to find a rescued expression."); + yp_node_t *expression = parse_starred_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_RESCUE_EXPRESSION); yp_rescue_node_exceptions_append(rescue, expression); // If we hit a newline, then this is the end of the rescue expression. We // can continue on to parse the statements. - if (match_any_type_p(parser, 3, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON, YP_TOKEN_KEYWORD_THEN)) break; + if (match3(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON, YP_TOKEN_KEYWORD_THEN)) break; // If we hit a `=>` then we're going to parse the exception variable. Once // we've done that, we'll break out of the loop and parse the statements. - if (accept(parser, YP_TOKEN_EQUAL_GREATER)) { + if (accept1(parser, YP_TOKEN_EQUAL_GREATER)) { yp_rescue_node_operator_set(rescue, &parser->previous); - yp_node_t *reference = parse_expression(parser, YP_BINDING_POWER_INDEX, "Expected an exception variable after `=>` in rescue statement."); + yp_node_t *reference = parse_expression(parser, YP_BINDING_POWER_INDEX, YP_ERR_RESCUE_VARIABLE); reference = parse_target(parser, reference); yp_rescue_node_reference_set(rescue, reference); break; } - } while (accept(parser, YP_TOKEN_COMMA)); + } while (accept1(parser, YP_TOKEN_COMMA)); } } } - if (accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)) { - accept(parser, YP_TOKEN_KEYWORD_THEN); + if (accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)) { + accept1(parser, YP_TOKEN_KEYWORD_THEN); } else { - expect(parser, YP_TOKEN_KEYWORD_THEN, "Expected a terminator after rescue clause."); + expect1(parser, YP_TOKEN_KEYWORD_THEN, YP_ERR_RESCUE_TERM); } - if (!match_any_type_p(parser, 3, YP_TOKEN_KEYWORD_ELSE, YP_TOKEN_KEYWORD_ENSURE, YP_TOKEN_KEYWORD_END)) { + if (!match3(parser, YP_TOKEN_KEYWORD_ELSE, YP_TOKEN_KEYWORD_ENSURE, YP_TOKEN_KEYWORD_END)) { yp_accepts_block_stack_push(parser, true); yp_statements_node_t *statements = parse_statements(parser, YP_CONTEXT_RESCUE); if (statements) { yp_rescue_node_statements_set(rescue, statements); } yp_accepts_block_stack_pop(parser); - accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); + accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); } if (current == NULL) { @@ -9195,32 +9586,32 @@ parse_rescues(yp_parser_t *parser, yp_begin_node_t *parent_node) { } } - if (accept(parser, YP_TOKEN_KEYWORD_ELSE)) { + if (accept1(parser, YP_TOKEN_KEYWORD_ELSE)) { yp_token_t else_keyword = parser->previous; - accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); + accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); yp_statements_node_t *else_statements = NULL; - if (!match_any_type_p(parser, 2, YP_TOKEN_KEYWORD_END, YP_TOKEN_KEYWORD_ENSURE)) { + if (!match2(parser, YP_TOKEN_KEYWORD_END, YP_TOKEN_KEYWORD_ENSURE)) { yp_accepts_block_stack_push(parser, true); else_statements = parse_statements(parser, YP_CONTEXT_RESCUE_ELSE); yp_accepts_block_stack_pop(parser); - accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); + accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); } yp_else_node_t *else_clause = yp_else_node_create(parser, &else_keyword, else_statements, &parser->current); yp_begin_node_else_clause_set(parent_node, else_clause); } - if (accept(parser, YP_TOKEN_KEYWORD_ENSURE)) { + if (accept1(parser, YP_TOKEN_KEYWORD_ENSURE)) { yp_token_t ensure_keyword = parser->previous; - accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); + accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); yp_statements_node_t *ensure_statements = NULL; - if (!match_type_p(parser, YP_TOKEN_KEYWORD_END)) { + if (!match1(parser, YP_TOKEN_KEYWORD_END)) { yp_accepts_block_stack_push(parser, true); ensure_statements = parse_statements(parser, YP_CONTEXT_ENSURE); yp_accepts_block_stack_pop(parser); - accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); + accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); } yp_ensure_node_t *ensure_clause = yp_ensure_node_create(parser, &ensure_keyword, ensure_statements, &parser->current); @@ -9268,7 +9659,7 @@ parse_block_parameters( bool is_lambda_literal ) { yp_parameters_node_t *parameters = NULL; - if (!match_type_p(parser, YP_TOKEN_SEMICOLON)) { + if (!match1(parser, YP_TOKEN_SEMICOLON)) { parameters = parse_parameters( parser, is_lambda_literal ? YP_BINDING_POWER_DEFINED : YP_BINDING_POWER_INDEX, @@ -9279,12 +9670,14 @@ parse_block_parameters( } yp_block_parameters_node_t *block_parameters = yp_block_parameters_node_create(parser, parameters, opening); - if (accept(parser, YP_TOKEN_SEMICOLON)) { + if (accept1(parser, YP_TOKEN_SEMICOLON)) { do { - expect(parser, YP_TOKEN_IDENTIFIER, "Expected a local variable name."); + expect1(parser, YP_TOKEN_IDENTIFIER, YP_ERR_BLOCK_PARAM_LOCAL_VARIABLE); yp_parser_local_add_token(parser, &parser->previous); - yp_block_parameters_node_append_local(block_parameters, &parser->previous); - } while (accept(parser, YP_TOKEN_COMMA)); + + yp_block_local_variable_node_t *local = yp_block_local_variable_node_create(parser, &parser->previous); + yp_block_parameters_node_append_local(block_parameters, local); + } while (accept1(parser, YP_TOKEN_COMMA)); } return block_parameters; @@ -9294,53 +9687,54 @@ parse_block_parameters( static yp_block_node_t * parse_block(yp_parser_t *parser) { yp_token_t opening = parser->previous; - accept(parser, YP_TOKEN_NEWLINE); + accept1(parser, YP_TOKEN_NEWLINE); yp_accepts_block_stack_push(parser, true); yp_parser_scope_push(parser, false); yp_block_parameters_node_t *parameters = NULL; - if (accept(parser, YP_TOKEN_PIPE)) { + if (accept1(parser, YP_TOKEN_PIPE)) { + parser->current_scope->explicit_params = true; yp_token_t block_parameters_opening = parser->previous; - if (match_type_p(parser, YP_TOKEN_PIPE)) { + if (match1(parser, YP_TOKEN_PIPE)) { parameters = yp_block_parameters_node_create(parser, NULL, &block_parameters_opening); parser->command_start = true; parser_lex(parser); } else { parameters = parse_block_parameters(parser, true, &block_parameters_opening, false); - accept(parser, YP_TOKEN_NEWLINE); + accept1(parser, YP_TOKEN_NEWLINE); parser->command_start = true; - expect(parser, YP_TOKEN_PIPE, "Expected block parameters to end with '|'."); + expect1(parser, YP_TOKEN_PIPE, YP_ERR_BLOCK_PARAM_PIPE_TERM); } yp_block_parameters_node_closing_set(parameters, &parser->previous); } - accept(parser, YP_TOKEN_NEWLINE); + accept1(parser, YP_TOKEN_NEWLINE); yp_node_t *statements = NULL; if (opening.type == YP_TOKEN_BRACE_LEFT) { - if (!match_type_p(parser, YP_TOKEN_BRACE_RIGHT)) { + if (!match1(parser, YP_TOKEN_BRACE_RIGHT)) { statements = (yp_node_t *) parse_statements(parser, YP_CONTEXT_BLOCK_BRACES); } - expect(parser, YP_TOKEN_BRACE_RIGHT, "Expected block beginning with '{' to end with '}'."); + expect1(parser, YP_TOKEN_BRACE_RIGHT, YP_ERR_BLOCK_TERM_BRACE); } else { - if (!match_type_p(parser, YP_TOKEN_KEYWORD_END)) { - if (!match_any_type_p(parser, 3, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ELSE, YP_TOKEN_KEYWORD_ENSURE)) { + if (!match1(parser, YP_TOKEN_KEYWORD_END)) { + if (!match3(parser, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ELSE, YP_TOKEN_KEYWORD_ENSURE)) { yp_accepts_block_stack_push(parser, true); statements = (yp_node_t *) parse_statements(parser, YP_CONTEXT_BLOCK_KEYWORDS); yp_accepts_block_stack_pop(parser); } - if (match_any_type_p(parser, 2, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE)) { - assert(statements == NULL || YP_NODE_TYPE_P(statements, YP_NODE_STATEMENTS_NODE)); + if (match2(parser, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE)) { + assert(statements == NULL || YP_NODE_TYPE_P(statements, YP_STATEMENTS_NODE)); statements = (yp_node_t *) parse_rescues_as_begin(parser, (yp_statements_node_t *) statements); } } - expect(parser, YP_TOKEN_KEYWORD_END, "Expected block beginning with 'do' to end with 'end'."); + expect1(parser, YP_TOKEN_KEYWORD_END, YP_ERR_BLOCK_TERM_END); } yp_constant_id_list_t locals = parser->current_scope->locals; @@ -9356,30 +9750,27 @@ static bool parse_arguments_list(yp_parser_t *parser, yp_arguments_t *arguments, bool accepts_block) { bool found = false; - if (accept(parser, YP_TOKEN_PARENTHESIS_LEFT)) { + if (accept1(parser, YP_TOKEN_PARENTHESIS_LEFT)) { found |= true; - arguments->opening_loc = ((yp_location_t) { .start = parser->previous.start, .end = parser->previous.end }); + arguments->opening_loc = YP_LOCATION_TOKEN_VALUE(&parser->previous); - if (accept(parser, YP_TOKEN_PARENTHESIS_RIGHT)) { - arguments->closing_loc = ((yp_location_t) { .start = parser->previous.start, .end = parser->previous.end }); + if (accept1(parser, YP_TOKEN_PARENTHESIS_RIGHT)) { + arguments->closing_loc = YP_LOCATION_TOKEN_VALUE(&parser->previous); } else { - arguments->arguments = yp_arguments_node_create(parser); - yp_accepts_block_stack_push(parser, true); parse_arguments(parser, arguments, true, YP_TOKEN_PARENTHESIS_RIGHT); - expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected a ')' to close the argument list."); + expect1(parser, YP_TOKEN_PARENTHESIS_RIGHT, YP_ERR_ARGUMENT_TERM_PAREN); yp_accepts_block_stack_pop(parser); - arguments->closing_loc = ((yp_location_t) { .start = parser->previous.start, .end = parser->previous.end }); + arguments->closing_loc = YP_LOCATION_TOKEN_VALUE(&parser->previous); } - } else if ((token_begins_expression_p(parser->current.type) || match_any_type_p(parser, 3, YP_TOKEN_USTAR, YP_TOKEN_USTAR_STAR, YP_TOKEN_UAMPERSAND)) && !match_type_p(parser, YP_TOKEN_BRACE_LEFT)) { + } else if ((token_begins_expression_p(parser->current.type) || match3(parser, YP_TOKEN_USTAR, YP_TOKEN_USTAR_STAR, YP_TOKEN_UAMPERSAND)) && !match1(parser, YP_TOKEN_BRACE_LEFT)) { found |= true; yp_accepts_block_stack_push(parser, false); // If we get here, then the subsequent token cannot be used as an infix // operator. In this case we assume the subsequent token is part of an // argument to this method call. - arguments->arguments = yp_arguments_node_create(parser); parse_arguments(parser, arguments, true, YP_TOKEN_EOF); yp_accepts_block_stack_pop(parser); @@ -9389,16 +9780,28 @@ parse_arguments_list(yp_parser_t *parser, yp_arguments_t *arguments, bool accept // node that starts with a {. If there is, then we can parse it and add it to // the arguments. if (accepts_block) { - if (accept(parser, YP_TOKEN_BRACE_LEFT)) { + yp_block_node_t *block = NULL; + + if (accept1(parser, YP_TOKEN_BRACE_LEFT)) { found |= true; - arguments->block = parse_block(parser); - } else if (yp_accepts_block_stack_p(parser) && accept(parser, YP_TOKEN_KEYWORD_DO)) { + block = parse_block(parser); + yp_arguments_validate_block(parser, arguments, block); + } else if (yp_accepts_block_stack_p(parser) && accept1(parser, YP_TOKEN_KEYWORD_DO)) { found |= true; - arguments->block = parse_block(parser); + block = parse_block(parser); + } + + if (block != NULL) { + if (arguments->block == NULL) { + arguments->block = (yp_node_t *) block; + } else { + yp_diagnostic_list_append(&parser->error_list, block->base.location.start, block->base.location.end, YP_ERR_ARGUMENT_BLOCK_MULTI); + yp_arguments_node_arguments_append(arguments->arguments, arguments->block); + arguments->block = (yp_node_t *) block; + } } } - yp_arguments_validate(parser, arguments); return found; } @@ -9407,20 +9810,21 @@ parse_conditional(yp_parser_t *parser, yp_context_t context) { yp_token_t keyword = parser->previous; context_push(parser, YP_CONTEXT_PREDICATE); - yp_node_t *predicate = parse_expression(parser, YP_BINDING_POWER_MODIFIER, "Expected to find a predicate for the conditional."); + yp_diagnostic_id_t error_id = context == YP_CONTEXT_IF ? YP_ERR_CONDITIONAL_IF_PREDICATE : YP_ERR_CONDITIONAL_UNLESS_PREDICATE; + yp_node_t *predicate = parse_expression(parser, YP_BINDING_POWER_MODIFIER, error_id); // Predicates are closed by a term, a "then", or a term and then a "then". - accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); - accept(parser, YP_TOKEN_KEYWORD_THEN); + accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); + accept1(parser, YP_TOKEN_KEYWORD_THEN); context_pop(parser); yp_statements_node_t *statements = NULL; - if (!match_any_type_p(parser, 3, YP_TOKEN_KEYWORD_ELSIF, YP_TOKEN_KEYWORD_ELSE, YP_TOKEN_KEYWORD_END)) { + if (!match3(parser, YP_TOKEN_KEYWORD_ELSIF, YP_TOKEN_KEYWORD_ELSE, YP_TOKEN_KEYWORD_END)) { yp_accepts_block_stack_push(parser, true); statements = parse_statements(parser, context); yp_accepts_block_stack_pop(parser); - accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); + accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); } yp_token_t end_keyword = not_provided(parser); @@ -9443,19 +9847,19 @@ parse_conditional(yp_parser_t *parser, yp_context_t context) { // Parse any number of elsif clauses. This will form a linked list of if // nodes pointing to each other from the top. if (context == YP_CONTEXT_IF) { - while (accept(parser, YP_TOKEN_KEYWORD_ELSIF)) { + while (accept1(parser, YP_TOKEN_KEYWORD_ELSIF)) { yp_token_t elsif_keyword = parser->previous; - yp_node_t *predicate = parse_expression(parser, YP_BINDING_POWER_MODIFIER, "Expected to find a predicate for the elsif clause."); + yp_node_t *predicate = parse_expression(parser, YP_BINDING_POWER_MODIFIER, YP_ERR_CONDITIONAL_ELSIF_PREDICATE); // Predicates are closed by a term, a "then", or a term and then a "then". - accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); - accept(parser, YP_TOKEN_KEYWORD_THEN); + accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); + accept1(parser, YP_TOKEN_KEYWORD_THEN); yp_accepts_block_stack_push(parser, true); yp_statements_node_t *statements = parse_statements(parser, YP_CONTEXT_ELSIF); yp_accepts_block_stack_pop(parser); - accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); + accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); yp_node_t *elsif = (yp_node_t *) yp_if_node_create(parser, &elsif_keyword, predicate, statements, NULL, &end_keyword); ((yp_if_node_t *) current)->consequent = elsif; @@ -9463,7 +9867,7 @@ parse_conditional(yp_parser_t *parser, yp_context_t context) { } } - if (match_type_p(parser, YP_TOKEN_KEYWORD_ELSE)) { + if (match1(parser, YP_TOKEN_KEYWORD_ELSE)) { parser_lex(parser); yp_token_t else_keyword = parser->previous; @@ -9471,8 +9875,8 @@ parse_conditional(yp_parser_t *parser, yp_context_t context) { yp_statements_node_t *else_statements = parse_statements(parser, YP_CONTEXT_ELSE); yp_accepts_block_stack_pop(parser); - accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); - expect(parser, YP_TOKEN_KEYWORD_END, "Expected `end` to close `else` clause."); + accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); + expect1(parser, YP_TOKEN_KEYWORD_END, YP_ERR_CONDITIONAL_TERM_ELSE); yp_else_node_t *else_node = yp_else_node_create(parser, &else_keyword, else_statements, &parser->previous); @@ -9488,7 +9892,8 @@ parse_conditional(yp_parser_t *parser, yp_context_t context) { break; } } else { - expect(parser, YP_TOKEN_KEYWORD_END, "Expected `end` to close conditional statement."); + // We should specialize this error message to refer to 'if' or 'unless' explicitly. + expect1(parser, YP_TOKEN_KEYWORD_END, YP_ERR_CONDITIONAL_TERM); } // Set the appropriate end location for all of the nodes in the subtree. @@ -9499,12 +9904,12 @@ parse_conditional(yp_parser_t *parser, yp_context_t context) { while (recursing) { switch (YP_NODE_TYPE(current)) { - case YP_NODE_IF_NODE: + case YP_IF_NODE: yp_if_node_end_keyword_loc_set((yp_if_node_t *) current, &parser->previous); current = ((yp_if_node_t *) current)->consequent; recursing = current != NULL; break; - case YP_NODE_ELSE_NODE: + case YP_ELSE_NODE: yp_else_node_end_keyword_loc_set((yp_else_node_t *) current, &parser->previous); recursing = false; break; @@ -9541,7 +9946,6 @@ parse_conditional(yp_parser_t *parser, yp_context_t context) { case YP_TOKEN_KEYWORD_TRUE: case YP_TOKEN_KEYWORD_UNDEF: case YP_TOKEN_KEYWORD_UNLESS: case YP_TOKEN_KEYWORD_UNTIL: \ case YP_TOKEN_KEYWORD_WHEN: case YP_TOKEN_KEYWORD_WHILE: case YP_TOKEN_KEYWORD_YIELD - // This macro allows you to define a case statement for all of the operators. // It's meant to be used in a switch statement. #define YP_CASE_OPERATOR YP_TOKEN_AMPERSAND: case YP_TOKEN_BACKTICK: case YP_TOKEN_BANG_EQUAL: \ @@ -9575,10 +9979,10 @@ parse_conditional(yp_parser_t *parser, yp_context_t context) { // This macro allows you to define a case statement for all of the nodes that // can be transformed into write targets. -#define YP_CASE_WRITABLE YP_NODE_CLASS_VARIABLE_READ_NODE: case YP_NODE_CONSTANT_PATH_NODE: \ - case YP_NODE_CONSTANT_READ_NODE: case YP_NODE_GLOBAL_VARIABLE_READ_NODE: case YP_NODE_LOCAL_VARIABLE_READ_NODE: \ - case YP_NODE_INSTANCE_VARIABLE_READ_NODE: case YP_NODE_MULTI_WRITE_NODE: case YP_NODE_BACK_REFERENCE_READ_NODE: \ - case YP_NODE_NUMBERED_REFERENCE_READ_NODE +#define YP_CASE_WRITABLE YP_CLASS_VARIABLE_READ_NODE: case YP_CONSTANT_PATH_NODE: \ + case YP_CONSTANT_READ_NODE: case YP_GLOBAL_VARIABLE_READ_NODE: case YP_LOCAL_VARIABLE_READ_NODE: \ + case YP_INSTANCE_VARIABLE_READ_NODE: case YP_MULTI_TARGET_NODE: case YP_BACK_REFERENCE_READ_NODE: \ + case YP_NUMBERED_REFERENCE_READ_NODE // Parse a node that is part of a string. If the subsequent tokens cannot be // parsed as a string part, then NULL is returned. @@ -9629,7 +10033,7 @@ parse_string_part(yp_parser_t *parser) { yp_token_t opening = parser->previous; yp_statements_node_t *statements = NULL; - if (!match_type_p(parser, YP_TOKEN_EMBEXPR_END)) { + if (!match1(parser, YP_TOKEN_EMBEXPR_END)) { yp_accepts_block_stack_push(parser, true); statements = parse_statements(parser, YP_CONTEXT_EMBEXPR); yp_accepts_block_stack_pop(parser); @@ -9638,7 +10042,7 @@ parse_string_part(yp_parser_t *parser) { parser->brace_nesting = brace_nesting; lex_state_set(parser, state); - expect(parser, YP_TOKEN_EMBEXPR_END, "Expected a closing delimiter for an embedded expression."); + expect1(parser, YP_TOKEN_EMBEXPR_END, YP_ERR_EMBEXPR_END); yp_token_t closing = parser->previous; return (yp_node_t *) yp_embedded_statements_node_create(parser, &opening, statements, &closing); @@ -9692,7 +10096,7 @@ parse_string_part(yp_parser_t *parser) { // we'll not attempt to lex this token and instead just return a // missing node. default: - expect(parser, YP_TOKEN_IDENTIFIER, "Expected a valid embedded variable."); + expect1(parser, YP_TOKEN_IDENTIFIER, YP_ERR_EMBVAR_INVALID); variable = (yp_node_t *) yp_missing_node_create(parser, parser->current.start, parser->current.end); break; } @@ -9701,7 +10105,7 @@ parse_string_part(yp_parser_t *parser) { } default: parser_lex(parser); - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Could not understand string part"); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_CANNOT_PARSE_STRING_PART); return NULL; } } @@ -9732,7 +10136,7 @@ parse_symbol(yp_parser_t *parser, yp_lex_mode_t *lex_mode, yp_lex_state_t next_s symbol = parser->previous; break; default: - expect(parser, YP_TOKEN_IDENTIFIER, "Expected symbol."); + expect1(parser, YP_TOKEN_IDENTIFIER, YP_ERR_SYMBOL_INVALID); symbol = parser->previous; break; } @@ -9743,7 +10147,7 @@ parse_symbol(yp_parser_t *parser, yp_lex_mode_t *lex_mode, yp_lex_state_t next_s if (lex_mode->as.string.interpolation) { // If we have the end of the symbol, then we can return an empty symbol. - if (match_type_p(parser, YP_TOKEN_STRING_END)) { + if (match1(parser, YP_TOKEN_STRING_END)) { if (next_state != YP_LEX_STATE_NONE) lex_state_set(parser, next_state); parser_lex(parser); @@ -9757,9 +10161,9 @@ parse_symbol(yp_parser_t *parser, yp_lex_mode_t *lex_mode, yp_lex_state_t next_s // If we got a string part, then it's possible that we could transform // what looks like an interpolated symbol into a regular symbol. - if (part && YP_NODE_TYPE_P(part, YP_NODE_STRING_NODE) && match_any_type_p(parser, 2, YP_TOKEN_STRING_END, YP_TOKEN_EOF)) { + if (part && YP_NODE_TYPE_P(part, YP_STRING_NODE) && match2(parser, YP_TOKEN_STRING_END, YP_TOKEN_EOF)) { if (next_state != YP_LEX_STATE_NONE) lex_state_set(parser, next_state); - parser_lex(parser); + expect1(parser, YP_TOKEN_STRING_END, YP_ERR_SYMBOL_TERM_INTERPOLATED); return (yp_node_t *) yp_string_node_to_symbol_node(parser, (yp_string_node_t *) part, &opening, &parser->previous); } @@ -9769,20 +10173,20 @@ parse_symbol(yp_parser_t *parser, yp_lex_mode_t *lex_mode, yp_lex_state_t next_s yp_node_list_t node_list = YP_EMPTY_NODE_LIST; if (part) yp_node_list_append(&node_list, part); - while (!match_any_type_p(parser, 2, YP_TOKEN_STRING_END, YP_TOKEN_EOF)) { + while (!match2(parser, YP_TOKEN_STRING_END, YP_TOKEN_EOF)) { if ((part = parse_string_part(parser)) != NULL) { yp_node_list_append(&node_list, part); } } if (next_state != YP_LEX_STATE_NONE) lex_state_set(parser, next_state); - expect(parser, YP_TOKEN_STRING_END, "Expected a closing delimiter for an interpolated symbol."); + expect1(parser, YP_TOKEN_STRING_END, YP_ERR_SYMBOL_TERM_INTERPOLATED); return (yp_node_t *) yp_interpolated_symbol_node_create(parser, &opening, &node_list, &parser->previous); } yp_token_t content; - if (accept(parser, YP_TOKEN_STRING_CONTENT)) { + if (accept1(parser, YP_TOKEN_STRING_CONTENT)) { content = parser->previous; } else { content = (yp_token_t) { .type = YP_TOKEN_STRING_CONTENT, .start = parser->previous.end, .end = parser->previous.end }; @@ -9791,7 +10195,7 @@ parse_symbol(yp_parser_t *parser, yp_lex_mode_t *lex_mode, yp_lex_state_t next_s if (next_state != YP_LEX_STATE_NONE) { lex_state_set(parser, next_state); } - expect(parser, YP_TOKEN_STRING_END, "Expected a closing delimiter for a dynamic symbol."); + expect1(parser, YP_TOKEN_STRING_END, YP_ERR_SYMBOL_TERM_DYNAMIC); return (yp_node_t *) yp_symbol_node_create_and_unescape(parser, &opening, &content, &parser->previous, YP_UNESCAPE_ALL); } @@ -9819,7 +10223,7 @@ parse_undef_argument(yp_parser_t *parser) { return parse_symbol(parser, &lex_mode, YP_LEX_STATE_NONE); } default: - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Expected a bare word or symbol argument."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_UNDEF_ARGUMENT); return (yp_node_t *) yp_missing_node_create(parser, parser->current.start, parser->current.end); } } @@ -9861,22 +10265,71 @@ parse_alias_argument(yp_parser_t *parser, bool first) { parser_lex(parser); return (yp_node_t *) yp_global_variable_read_node_create(parser, &parser->previous); default: - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Expected a bare word, symbol or global variable argument."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_ALIAS_ARGUMENT); return (yp_node_t *) yp_missing_node_create(parser, parser->current.start, parser->current.end); } } +// Return true if any of the visible scopes to the current context are using +// numbered parameters. +static bool +outer_scope_using_numbered_params_p(yp_parser_t *parser) { + for (yp_scope_t *scope = parser->current_scope->previous; scope != NULL && !scope->closed; scope = scope->previous) { + if (scope->numbered_params) return true; + } + + return false; +} + // Parse an identifier into either a local variable read or a call. static yp_node_t * parse_variable_call(yp_parser_t *parser) { yp_node_flags_t flags = 0; - if (!match_type_p(parser, YP_TOKEN_PARENTHESIS_LEFT) && (parser->previous.end[-1] != '!') && (parser->previous.end[-1] != '?')) { + if (!match1(parser, YP_TOKEN_PARENTHESIS_LEFT) && (parser->previous.end[-1] != '!') && (parser->previous.end[-1] != '?')) { int depth; if ((depth = yp_parser_local_depth(parser, &parser->previous)) != -1) { return (yp_node_t *) yp_local_variable_read_node_create(parser, &parser->previous, (uint32_t) depth); } + if (!parser->current_scope->closed && token_is_numbered_parameter(parser->previous.start, parser->previous.end)) { + // Indicate that this scope is using numbered params so that child + // scopes cannot. + parser->current_scope->numbered_params = true; + + // Now that we know we have a numbered parameter, we need to check + // if it's allowed in this context. If it is, then we will create a + // local variable read. If it's not, then we'll create a normal call + // node but add an error. + if (parser->current_scope->explicit_params) { + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_NUMBERED_PARAMETER_NOT_ALLOWED); + } else if (outer_scope_using_numbered_params_p(parser)) { + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_NUMBERED_PARAMETER_OUTER_SCOPE); + } else { + // When you use a numbered parameter, it implies the existence + // of all of the locals that exist before it. For example, + // referencing _2 means that _1 must exist. Therefore here we + // loop through all of the possibilities and add them into the + // constant pool. + uint8_t number = parser->previous.start[1]; + uint8_t current = '1'; + uint8_t *value; + + while (current < number) { + value = malloc(2); + value[0] = '_'; + value[1] = current++; + yp_parser_local_add_owned(parser, value, 2); + } + + // Now we can add the actual token that is being used. For + // this one we can add a shared version since it is directly + // referenced in the source. + yp_parser_local_add_token(parser, &parser->previous); + return (yp_node_t *) yp_local_variable_read_node_create(parser, &parser->previous, 0); + } + } + flags |= YP_CALL_NODE_FLAGS_VARIABLE_CALL; } @@ -9899,8 +10352,55 @@ parse_method_definition_name(yp_parser_t *parser) { parser_lex(parser); return parser->previous; default: - return not_provided(parser); + return (yp_token_t) { .type = YP_TOKEN_MISSING, .start = parser->current.start, .end = parser->current.end }; + } +} + +static int +parse_heredoc_common_whitespace_for_single_node(yp_parser_t *parser, yp_node_t *node, int common_whitespace) +{ + const yp_location_t *content_loc = &((yp_string_node_t *) node)->content_loc; + int cur_whitespace; + const uint8_t *cur_char = content_loc->start; + + while (cur_char && cur_char < content_loc->end) { + // Any empty newlines aren't included in the minimum whitespace + // calculation. + size_t eol_length; + while ((eol_length = match_eol_at(parser, cur_char))) { + cur_char += eol_length; + } + + if (cur_char == content_loc->end) break; + + cur_whitespace = 0; + + while (yp_char_is_inline_whitespace(*cur_char) && cur_char < content_loc->end) { + if (cur_char[0] == '\t') { + cur_whitespace = (cur_whitespace / YP_TAB_WHITESPACE_SIZE + 1) * YP_TAB_WHITESPACE_SIZE; + } else { + cur_whitespace++; + } + cur_char++; + } + + // If we hit a newline, then we have encountered a line that + // contains only whitespace, and it shouldn't be considered in + // the calculation of common leading whitespace. + eol_length = match_eol_at(parser, cur_char); + if (eol_length) { + cur_char += eol_length; + continue; + } + + if (cur_whitespace < common_whitespace || common_whitespace == -1) { + common_whitespace = cur_whitespace; + } + + cur_char = next_newline(cur_char + 1, parser->end - (cur_char + 1)); + if (cur_char) cur_char++; } + return common_whitespace; } // Calculate the common leading whitespace for each line in a heredoc. @@ -9910,69 +10410,102 @@ parse_heredoc_common_whitespace(yp_parser_t *parser, yp_node_list_t *nodes) { for (size_t index = 0; index < nodes->size; index++) { yp_node_t *node = nodes->nodes[index]; - - if (!YP_NODE_TYPE_P(node, YP_NODE_STRING_NODE)) continue; - const yp_location_t *content_loc = &((yp_string_node_t *) node)->content_loc; + if (!YP_NODE_TYPE_P(node, YP_STRING_NODE)) continue; // If the previous node wasn't a string node, we don't want to trim // whitespace. This could happen after an interpolated expression or // variable. - if (index == 0 || YP_NODE_TYPE_P(nodes->nodes[index - 1], YP_NODE_STRING_NODE)) { - int cur_whitespace; - const uint8_t *cur_char = content_loc->start; - - while (cur_char && cur_char < content_loc->end) { - // Any empty newlines aren't included in the minimum whitespace - // calculation. - size_t eol_length; - while ((eol_length = match_eol_at(parser, cur_char))) { - cur_char += eol_length; - } - - if (cur_char == content_loc->end) break; + if (index == 0 || YP_NODE_TYPE_P(nodes->nodes[index - 1], YP_STRING_NODE)) { + common_whitespace = parse_heredoc_common_whitespace_for_single_node(parser, node, common_whitespace); + } + } - cur_whitespace = 0; + return common_whitespace; +} - while (yp_char_is_inline_whitespace(*cur_char) && cur_char < content_loc->end) { - if (cur_char[0] == '\t') { - cur_whitespace = (cur_whitespace / YP_TAB_WHITESPACE_SIZE + 1) * YP_TAB_WHITESPACE_SIZE; - } else { - cur_whitespace++; - } - cur_char++; +static yp_string_t * +parse_heredoc_dedent_single_node(yp_parser_t *parser, yp_string_t *string, bool dedent_node, int common_whitespace, yp_heredoc_quote_t quote) +{ + // Get a reference to the string struct that is being held by the string + // node. This is the value we're going to actually manipulate. + yp_string_ensure_owned(string); + + // Now get the bounds of the existing string. We'll use this as a + // destination to move bytes into. We'll also use it for bounds checking + // since we don't require that these strings be null terminated. + size_t dest_length = yp_string_length(string); + uint8_t *source_start = (uint8_t *) string->source; + + const uint8_t *source_cursor = source_start; + const uint8_t *source_end = source_cursor + dest_length; + + // We're going to move bytes backward in the string when we get leading + // whitespace, so we'll maintain a pointer to the current position in the + // string that we're writing to. + uint8_t *dest_cursor = source_start; + + while (source_cursor < source_end) { + // If we need to dedent the next element within the heredoc or the next + // line within the string node, then we'll do it here. + if (dedent_node) { + int trimmed_whitespace = 0; + + // While we haven't reached the amount of common whitespace that we need + // to trim and we haven't reached the end of the string, we'll keep + // trimming whitespace. Trimming in this context means skipping over + // these bytes such that they aren't copied into the new string. + while ((source_cursor < source_end) && yp_char_is_inline_whitespace(*source_cursor) && trimmed_whitespace < common_whitespace) { + if (*source_cursor == '\t') { + trimmed_whitespace = (trimmed_whitespace / YP_TAB_WHITESPACE_SIZE + 1) * YP_TAB_WHITESPACE_SIZE; + if (trimmed_whitespace > common_whitespace) break; + } else { + trimmed_whitespace++; } - // If we hit a newline, then we have encountered a line that - // contains only whitespace, and it shouldn't be considered in - // the calculation of common leading whitespace. - eol_length = match_eol_at(parser, cur_char); - if (eol_length) { - cur_char += eol_length; - continue; - } + source_cursor++; + dest_length--; + } + } - if (cur_whitespace < common_whitespace || common_whitespace == -1) { - common_whitespace = cur_whitespace; - } + // At this point we have dedented all that we need to, so we need to find + // the next newline. + const uint8_t *breakpoint = next_newline(source_cursor, source_end - source_cursor); - cur_char = next_newline(cur_char + 1, parser->end - (cur_char + 1)); - if (cur_char) cur_char++; - } + if (breakpoint == NULL) { + // If there isn't another newline, then we can just move the rest of the + // string and break from the loop. + memmove(dest_cursor, source_cursor, (size_t) (source_end - source_cursor)); + break; } + + // Otherwise, we need to move everything including the newline, and + // then set the dedent_node flag to true. + if (breakpoint < source_end) breakpoint++; + memmove(dest_cursor, source_cursor, (size_t) (breakpoint - source_cursor)); + dest_cursor += (breakpoint - source_cursor); + source_cursor = breakpoint; + dedent_node = true; } - return common_whitespace; + // We only want to write this node into the list if it has any content. + string->length = dest_length; + + if (dest_length != 0) { + yp_unescape_manipulate_string(parser, string, (quote == YP_HEREDOC_QUOTE_SINGLE) ? YP_UNESCAPE_MINIMAL : YP_UNESCAPE_ALL); + } + return string; } // Take a heredoc node that is indented by a ~ and trim the leading whitespace. static void -parse_heredoc_dedent(yp_parser_t *parser, yp_node_t *node, yp_heredoc_quote_t quote) { +parse_heredoc_dedent(yp_parser_t *parser, yp_node_t *heredoc_node, yp_heredoc_quote_t quote) +{ yp_node_list_t *nodes; if (quote == YP_HEREDOC_QUOTE_BACKTICK) { - nodes = &((yp_interpolated_x_string_node_t *) node)->parts; + nodes = &((yp_interpolated_x_string_node_t *) heredoc_node)->parts; } else { - nodes = &((yp_interpolated_string_node_t *) node)->parts; + nodes = &((yp_interpolated_string_node_t *) heredoc_node)->parts; } // First, calculate how much common whitespace we need to trim. If there is @@ -9995,80 +10528,17 @@ parse_heredoc_dedent(yp_parser_t *parser, yp_node_t *node, yp_heredoc_quote_t qu // We're not manipulating child nodes that aren't strings. In this case // we'll skip past it and indicate that the subsequent node should not // be dedented. - if (!YP_NODE_TYPE_P(node, YP_NODE_STRING_NODE)) { + if (!YP_NODE_TYPE_P(node, YP_STRING_NODE)) { nodes->nodes[write_index++] = node; dedent_next = false; continue; } - // Get a reference to the string struct that is being held by the string - // node. This is the value we're going to actual manipulate. - yp_string_t *string = &(((yp_string_node_t *) node)->unescaped); - yp_string_ensure_owned(string); - - // Now get the bounds of the existing string. We'll use this as a - // destination to move bytes into. We'll also use it for bounds checking - // since we don't require that these strings be null terminated. - size_t dest_length = yp_string_length(string); - uint8_t *source_start = (uint8_t *) string->source; - - const uint8_t *source_cursor = source_start; - const uint8_t *source_end = source_cursor + dest_length; - - // We're going to move bytes backward in the string when we get leading - // whitespace, so we'll maintain a pointer to the current position in the - // string that we're writing to. - uint8_t *dest_cursor = source_start; - - while (source_cursor < source_end) { - // If we need to dedent the next element within the heredoc or the next - // line within the string node, then we'll do it here. - if (dedent_next) { - int trimmed_whitespace = 0; - - // While we haven't reached the amount of common whitespace that we need - // to trim and we haven't reached the end of the string, we'll keep - // trimming whitespace. Trimming in this context means skipping over - // these bytes such that they aren't copied into the new string. - while ((source_cursor < source_end) && yp_char_is_inline_whitespace(*source_cursor) && trimmed_whitespace < common_whitespace) { - if (*source_cursor == '\t') { - trimmed_whitespace = (trimmed_whitespace / YP_TAB_WHITESPACE_SIZE + 1) * YP_TAB_WHITESPACE_SIZE; - if (trimmed_whitespace > common_whitespace) break; - } else { - trimmed_whitespace++; - } - - source_cursor++; - dest_length--; - } - } - - // At this point we have dedented all that we need to, so we need to find - // the next newline. - const uint8_t *breakpoint = next_newline(source_cursor, source_end - source_cursor); - - if (breakpoint == NULL) { - // If there isn't another newline, then we can just move the rest of the - // string and break from the loop. - memmove(dest_cursor, source_cursor, (size_t) (source_end - source_cursor)); - break; - } - - // Otherwise, we need to move everything including the newline, and - // then set the dedent_next flag to true. - if (breakpoint < source_end) breakpoint++; - memmove(dest_cursor, source_cursor, (size_t) (breakpoint - source_cursor)); - dest_cursor += (breakpoint - source_cursor); - source_cursor = breakpoint; - dedent_next = true; - } - - // We only want to write this node into the list if it has any content. - if (dest_length == 0) { + yp_string_node_t *string_node = ((yp_string_node_t *) node); + parse_heredoc_dedent_single_node(parser, &string_node->unescaped, dedent_next, common_whitespace, quote); + if (string_node->unescaped.length == 0) { yp_node_destroy(parser, node); } else { - string->length = dest_length; - yp_unescape_manipulate_string(parser, string, (quote == YP_HEREDOC_QUOTE_SINGLE) ? YP_UNESCAPE_MINIMAL : YP_UNESCAPE_ALL); nodes->nodes[write_index++] = node; } @@ -10080,16 +10550,16 @@ parse_heredoc_dedent(yp_parser_t *parser, yp_node_t *node, yp_heredoc_quote_t qu } static yp_node_t * -parse_pattern(yp_parser_t *parser, bool top_pattern, const char *message); +parse_pattern(yp_parser_t *parser, bool top_pattern, yp_diagnostic_id_t diag_id); // Accept any number of constants joined by :: delimiters. static yp_node_t * parse_pattern_constant_path(yp_parser_t *parser, yp_node_t *node) { // Now, if there are any :: operators that follow, parse them as constant // path nodes. - while (accept(parser, YP_TOKEN_COLON_COLON)) { + while (accept1(parser, YP_TOKEN_COLON_COLON)) { yp_token_t delimiter = parser->previous; - expect(parser, YP_TOKEN_CONSTANT, "Expected a constant after the :: operator."); + expect1(parser, YP_TOKEN_CONSTANT, YP_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT); yp_node_t *child = (yp_node_t *) yp_constant_read_node_create(parser, &parser->previous); node = (yp_node_t *)yp_constant_path_node_create(parser, node, &delimiter, child); @@ -10098,7 +10568,7 @@ parse_pattern_constant_path(yp_parser_t *parser, yp_node_t *node) { // If there is a [ or ( that follows, then this is part of a larger pattern // expression. We'll parse the inner pattern here, then modify the returned // inner pattern with our constant path attached. - if (!match_any_type_p(parser, 2, YP_TOKEN_BRACKET_LEFT, YP_TOKEN_PARENTHESIS_LEFT)) { + if (!match2(parser, YP_TOKEN_BRACKET_LEFT, YP_TOKEN_PARENTHESIS_LEFT)) { return node; } @@ -10106,14 +10576,14 @@ parse_pattern_constant_path(yp_parser_t *parser, yp_node_t *node) { yp_token_t closing; yp_node_t *inner = NULL; - if (accept(parser, YP_TOKEN_BRACKET_LEFT)) { + if (accept1(parser, YP_TOKEN_BRACKET_LEFT)) { opening = parser->previous; - accept(parser, YP_TOKEN_NEWLINE); + accept1(parser, YP_TOKEN_NEWLINE); - if (!accept(parser, YP_TOKEN_BRACKET_RIGHT)) { - inner = parse_pattern(parser, true, "Expected a pattern expression after the [ operator."); - accept(parser, YP_TOKEN_NEWLINE); - expect(parser, YP_TOKEN_BRACKET_RIGHT, "Expected a ] to close the pattern expression."); + if (!accept1(parser, YP_TOKEN_BRACKET_RIGHT)) { + inner = parse_pattern(parser, true, YP_ERR_PATTERN_EXPRESSION_AFTER_BRACKET); + accept1(parser, YP_TOKEN_NEWLINE); + expect1(parser, YP_TOKEN_BRACKET_RIGHT, YP_ERR_PATTERN_TERM_BRACKET); } closing = parser->previous; @@ -10121,9 +10591,9 @@ parse_pattern_constant_path(yp_parser_t *parser, yp_node_t *node) { parser_lex(parser); opening = parser->previous; - if (!accept(parser, YP_TOKEN_PARENTHESIS_RIGHT)) { - inner = parse_pattern(parser, true, "Expected a pattern expression after the ( operator."); - expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected a ) to close the pattern expression."); + if (!accept1(parser, YP_TOKEN_PARENTHESIS_RIGHT)) { + inner = parse_pattern(parser, true, YP_ERR_PATTERN_EXPRESSION_AFTER_PAREN); + expect1(parser, YP_TOKEN_PARENTHESIS_RIGHT, YP_ERR_PATTERN_TERM_PAREN); } closing = parser->previous; @@ -10140,7 +10610,7 @@ parse_pattern_constant_path(yp_parser_t *parser, yp_node_t *node) { // it doesn't already have a constant. If it's not one of those node types // or it does have a constant, then we'll create an array pattern. switch (YP_NODE_TYPE(inner)) { - case YP_NODE_ARRAY_PATTERN_NODE: { + case YP_ARRAY_PATTERN_NODE: { yp_array_pattern_node_t *pattern_node = (yp_array_pattern_node_t *) inner; if (pattern_node->constant == NULL) { @@ -10148,15 +10618,15 @@ parse_pattern_constant_path(yp_parser_t *parser, yp_node_t *node) { pattern_node->base.location.end = closing.end; pattern_node->constant = node; - pattern_node->opening_loc = (yp_location_t) { .start = opening.start, .end = opening.end }; - pattern_node->closing_loc = (yp_location_t) { .start = closing.start, .end = closing.end }; + pattern_node->opening_loc = YP_LOCATION_TOKEN_VALUE(&opening); + pattern_node->closing_loc = YP_LOCATION_TOKEN_VALUE(&closing); return (yp_node_t *) pattern_node; } break; } - case YP_NODE_FIND_PATTERN_NODE: { + case YP_FIND_PATTERN_NODE: { yp_find_pattern_node_t *pattern_node = (yp_find_pattern_node_t *) inner; if (pattern_node->constant == NULL) { @@ -10164,15 +10634,15 @@ parse_pattern_constant_path(yp_parser_t *parser, yp_node_t *node) { pattern_node->base.location.end = closing.end; pattern_node->constant = node; - pattern_node->opening_loc = (yp_location_t) { .start = opening.start, .end = opening.end }; - pattern_node->closing_loc = (yp_location_t) { .start = closing.start, .end = closing.end }; + pattern_node->opening_loc = YP_LOCATION_TOKEN_VALUE(&opening); + pattern_node->closing_loc = YP_LOCATION_TOKEN_VALUE(&closing); return (yp_node_t *) pattern_node; } break; } - case YP_NODE_HASH_PATTERN_NODE: { + case YP_HASH_PATTERN_NODE: { yp_hash_pattern_node_t *pattern_node = (yp_hash_pattern_node_t *) inner; if (pattern_node->constant == NULL) { @@ -10180,8 +10650,8 @@ parse_pattern_constant_path(yp_parser_t *parser, yp_node_t *node) { pattern_node->base.location.end = closing.end; pattern_node->constant = node; - pattern_node->opening_loc = (yp_location_t) { .start = opening.start, .end = opening.end }; - pattern_node->closing_loc = (yp_location_t) { .start = closing.start, .end = closing.end }; + pattern_node->opening_loc = YP_LOCATION_TOKEN_VALUE(&opening); + pattern_node->closing_loc = YP_LOCATION_TOKEN_VALUE(&closing); return (yp_node_t *) pattern_node; } @@ -10210,7 +10680,7 @@ parse_pattern_rest(yp_parser_t *parser) { // Rest patterns don't necessarily have a name associated with them. So we // will check for that here. If they do, then we'll add it to the local table // since this pattern will cause it to become a local variable. - if (accept(parser, YP_TOKEN_IDENTIFIER)) { + if (accept1(parser, YP_TOKEN_IDENTIFIER)) { yp_token_t identifier = parser->previous; yp_parser_local_add_token(parser, &identifier); name = (yp_node_t *) yp_local_variable_target_node_create(parser, &identifier); @@ -10229,11 +10699,11 @@ parse_pattern_keyword_rest(yp_parser_t *parser) { yp_token_t operator = parser->previous; yp_node_t *value = NULL; - if (accept(parser, YP_TOKEN_KEYWORD_NIL)) { + if (accept1(parser, YP_TOKEN_KEYWORD_NIL)) { return (yp_node_t *) yp_no_keywords_parameter_node_create(parser, &operator, &parser->previous); } - if (accept(parser, YP_TOKEN_IDENTIFIER)) { + if (accept1(parser, YP_TOKEN_IDENTIFIER)) { yp_parser_local_add_token(parser, &parser->previous); value = (yp_node_t *) yp_local_variable_target_node_create(parser, &parser->previous); } @@ -10244,11 +10714,11 @@ parse_pattern_keyword_rest(yp_parser_t *parser) { // Parse a hash pattern. static yp_hash_pattern_node_t * parse_pattern_hash(yp_parser_t *parser, yp_node_t *first_assoc) { - if (YP_NODE_TYPE_P(first_assoc, YP_NODE_ASSOC_NODE)) { - if (!match_any_type_p(parser, 7, YP_TOKEN_COMMA, YP_TOKEN_KEYWORD_THEN, YP_TOKEN_BRACE_RIGHT, YP_TOKEN_BRACKET_RIGHT, YP_TOKEN_PARENTHESIS_RIGHT, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)) { + if (YP_NODE_TYPE_P(first_assoc, YP_ASSOC_NODE)) { + if (!match7(parser, YP_TOKEN_COMMA, YP_TOKEN_KEYWORD_THEN, YP_TOKEN_BRACE_RIGHT, YP_TOKEN_BRACKET_RIGHT, YP_TOKEN_PARENTHESIS_RIGHT, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)) { // Here we have a value for the first assoc in the list, so we will parse it // now and update the first assoc. - yp_node_t *value = parse_pattern(parser, false, "Expected a pattern expression after the key."); + yp_node_t *value = parse_pattern(parser, false, YP_ERR_PATTERN_EXPRESSION_AFTER_KEY); yp_assoc_node_t *assoc = (yp_assoc_node_t *) first_assoc; assoc->base.location.end = value->location.end; @@ -10256,7 +10726,7 @@ parse_pattern_hash(yp_parser_t *parser, yp_node_t *first_assoc) { } else { yp_node_t *key = ((yp_assoc_node_t *) first_assoc)->key; - if (YP_NODE_TYPE_P(key, YP_NODE_SYMBOL_NODE)) { + if (YP_NODE_TYPE_P(key, YP_SYMBOL_NODE)) { const yp_location_t *value_loc = &((yp_symbol_node_t *) key)->value_loc; yp_parser_local_add_location(parser, value_loc->start, value_loc->end); } @@ -10267,23 +10737,23 @@ parse_pattern_hash(yp_parser_t *parser, yp_node_t *first_assoc) { yp_node_list_append(&assocs, first_assoc); // If there are any other assocs, then we'll parse them now. - while (accept(parser, YP_TOKEN_COMMA)) { + while (accept1(parser, YP_TOKEN_COMMA)) { // Here we need to break to support trailing commas. - if (match_any_type_p(parser, 6, YP_TOKEN_KEYWORD_THEN, YP_TOKEN_BRACE_RIGHT, YP_TOKEN_BRACKET_RIGHT, YP_TOKEN_PARENTHESIS_RIGHT, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)) { + if (match6(parser, YP_TOKEN_KEYWORD_THEN, YP_TOKEN_BRACE_RIGHT, YP_TOKEN_BRACKET_RIGHT, YP_TOKEN_PARENTHESIS_RIGHT, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)) { break; } yp_node_t *assoc; - if (match_type_p(parser, YP_TOKEN_USTAR_STAR)) { + if (match1(parser, YP_TOKEN_USTAR_STAR)) { assoc = parse_pattern_keyword_rest(parser); } else { - expect(parser, YP_TOKEN_LABEL, "Expected a label after the `,'."); + expect1(parser, YP_TOKEN_LABEL, YP_ERR_PATTERN_LABEL_AFTER_COMMA); yp_node_t *key = (yp_node_t *) yp_symbol_node_label_create(parser, &parser->previous); yp_node_t *value = NULL; - if (!match_any_type_p(parser, 7, YP_TOKEN_COMMA, YP_TOKEN_KEYWORD_THEN, YP_TOKEN_BRACE_RIGHT, YP_TOKEN_BRACKET_RIGHT, YP_TOKEN_PARENTHESIS_RIGHT, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)) { - value = parse_pattern(parser, false, "Expected a pattern expression after the key."); + if (!match7(parser, YP_TOKEN_COMMA, YP_TOKEN_KEYWORD_THEN, YP_TOKEN_BRACE_RIGHT, YP_TOKEN_BRACKET_RIGHT, YP_TOKEN_PARENTHESIS_RIGHT, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)) { + value = parse_pattern(parser, false, YP_ERR_PATTERN_EXPRESSION_AFTER_KEY); } else { const yp_location_t *value_loc = &((yp_symbol_node_t *) key)->value_loc; yp_parser_local_add_location(parser, value_loc->start, value_loc->end); @@ -10304,7 +10774,7 @@ parse_pattern_hash(yp_parser_t *parser, yp_node_t *first_assoc) { // Parse a pattern expression primitive. static yp_node_t * -parse_pattern_primitive(yp_parser_t *parser, const char *message) { +parse_pattern_primitive(yp_parser_t *parser, yp_diagnostic_id_t diag_id) { switch (parser->current.type) { case YP_TOKEN_IDENTIFIER: { parser_lex(parser); @@ -10315,7 +10785,7 @@ parse_pattern_primitive(yp_parser_t *parser, const char *message) { yp_token_t opening = parser->current; parser_lex(parser); - if (accept(parser, YP_TOKEN_BRACKET_RIGHT)) { + if (accept1(parser, YP_TOKEN_BRACKET_RIGHT)) { // If we have an empty array pattern, then we'll just return a new // array pattern node. return (yp_node_t *)yp_array_pattern_node_empty_create(parser, &opening, &parser->previous); @@ -10323,36 +10793,36 @@ parse_pattern_primitive(yp_parser_t *parser, const char *message) { // Otherwise, we'll parse the inner pattern, then deal with it depending // on the type it returns. - yp_node_t *inner = parse_pattern(parser, true, "Expected a pattern expression after the [ operator."); + yp_node_t *inner = parse_pattern(parser, true, YP_ERR_PATTERN_EXPRESSION_AFTER_BRACKET); - accept(parser, YP_TOKEN_NEWLINE); + accept1(parser, YP_TOKEN_NEWLINE); - expect(parser, YP_TOKEN_BRACKET_RIGHT, "Expected a ] to close the pattern expression."); + expect1(parser, YP_TOKEN_BRACKET_RIGHT, YP_ERR_PATTERN_TERM_BRACKET); yp_token_t closing = parser->previous; switch (YP_NODE_TYPE(inner)) { - case YP_NODE_ARRAY_PATTERN_NODE: { + case YP_ARRAY_PATTERN_NODE: { yp_array_pattern_node_t *pattern_node = (yp_array_pattern_node_t *) inner; if (pattern_node->opening_loc.start == NULL) { pattern_node->base.location.start = opening.start; pattern_node->base.location.end = closing.end; - pattern_node->opening_loc = (yp_location_t) { .start = opening.start, .end = opening.end }; - pattern_node->closing_loc = (yp_location_t) { .start = closing.start, .end = closing.end }; + pattern_node->opening_loc = YP_LOCATION_TOKEN_VALUE(&opening); + pattern_node->closing_loc = YP_LOCATION_TOKEN_VALUE(&closing); return (yp_node_t *) pattern_node; } break; } - case YP_NODE_FIND_PATTERN_NODE: { + case YP_FIND_PATTERN_NODE: { yp_find_pattern_node_t *pattern_node = (yp_find_pattern_node_t *) inner; if (pattern_node->opening_loc.start == NULL) { pattern_node->base.location.start = opening.start; pattern_node->base.location.end = closing.end; - pattern_node->opening_loc = (yp_location_t) { .start = opening.start, .end = opening.end }; - pattern_node->closing_loc = (yp_location_t) { .start = closing.start, .end = closing.end }; + pattern_node->opening_loc = YP_LOCATION_TOKEN_VALUE(&opening); + pattern_node->closing_loc = YP_LOCATION_TOKEN_VALUE(&closing); return (yp_node_t *) pattern_node; } @@ -10375,7 +10845,7 @@ parse_pattern_primitive(yp_parser_t *parser, const char *message) { yp_token_t opening = parser->current; parser_lex(parser); - if (accept(parser, YP_TOKEN_BRACE_RIGHT)) { + if (accept1(parser, YP_TOKEN_BRACE_RIGHT)) { // If we have an empty hash pattern, then we'll just return a new hash // pattern node. node = yp_hash_pattern_node_empty_create(parser, &opening, &parser->previous); @@ -10391,15 +10861,15 @@ parse_pattern_primitive(yp_parser_t *parser, const char *message) { key = parse_pattern_keyword_rest(parser); break; case YP_TOKEN_STRING_BEGIN: - key = parse_expression(parser, YP_BINDING_POWER_MAX, "Expected a key in the hash pattern."); + key = parse_expression(parser, YP_BINDING_POWER_MAX, YP_ERR_PATTERN_HASH_KEY); if (!yp_symbol_node_label_p(key)) { - yp_diagnostic_list_append(&parser->error_list, key->location.start, key->location.end, "Expected a label as the key in the hash pattern."); + yp_diagnostic_list_append(&parser->error_list, key->location.start, key->location.end, YP_ERR_PATTERN_HASH_KEY_LABEL); } break; default: parser_lex(parser); - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Expected a key in the hash pattern."); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_PATTERN_HASH_KEY); key = (yp_node_t *) yp_missing_node_create(parser, parser->previous.start, parser->previous.end); break; } @@ -10407,15 +10877,15 @@ parse_pattern_primitive(yp_parser_t *parser, const char *message) { yp_token_t operator = not_provided(parser); node = parse_pattern_hash(parser, (yp_node_t *) yp_assoc_node_create(parser, key, &operator, NULL)); - accept(parser, YP_TOKEN_NEWLINE); - expect(parser, YP_TOKEN_BRACE_RIGHT, "Expected a } to close the pattern expression."); + accept1(parser, YP_TOKEN_NEWLINE); + expect1(parser, YP_TOKEN_BRACE_RIGHT, YP_ERR_PATTERN_TERM_BRACE); yp_token_t closing = parser->previous; node->base.location.start = opening.start; node->base.location.end = closing.end; - node->opening_loc = (yp_location_t) { .start = opening.start, .end = opening.end }; - node->closing_loc = (yp_location_t) { .start = closing.start, .end = closing.end }; + node->opening_loc = YP_LOCATION_TOKEN_VALUE(&opening); + node->closing_loc = YP_LOCATION_TOKEN_VALUE(&closing); } parser->pattern_matching_newlines = previous_pattern_matching_newlines; @@ -10430,21 +10900,21 @@ parse_pattern_primitive(yp_parser_t *parser, const char *message) { // expression as the right side of the range. switch (parser->current.type) { case YP_CASE_PRIMITIVE: { - yp_node_t *right = parse_expression(parser, YP_BINDING_POWER_MAX, "Expected an expression after the range operator."); + yp_node_t *right = parse_expression(parser, YP_BINDING_POWER_MAX, YP_ERR_PATTERN_EXPRESSION_AFTER_RANGE); return (yp_node_t *) yp_range_node_create(parser, NULL, &operator, right); } default: { - yp_diagnostic_list_append(&parser->error_list, operator.start, operator.end, "Expected an expression after the range operator."); + yp_diagnostic_list_append(&parser->error_list, operator.start, operator.end, YP_ERR_PATTERN_EXPRESSION_AFTER_RANGE); yp_node_t *right = (yp_node_t *) yp_missing_node_create(parser, operator.start, operator.end); return (yp_node_t *) yp_range_node_create(parser, NULL, &operator, right); } } } case YP_CASE_PRIMITIVE: { - yp_node_t *node = parse_expression(parser, YP_BINDING_POWER_MAX, message); + yp_node_t *node = parse_expression(parser, YP_BINDING_POWER_MAX, diag_id); // Now that we have a primitive, we need to check if it's part of a range. - if (accept_any(parser, 2, YP_TOKEN_DOT_DOT, YP_TOKEN_DOT_DOT_DOT)) { + if (accept2(parser, YP_TOKEN_DOT_DOT, YP_TOKEN_DOT_DOT_DOT)) { yp_token_t operator = parser->previous; // Now that we have the operator, we need to check if this is followed @@ -10452,7 +10922,7 @@ parse_pattern_primitive(yp_parser_t *parser, const char *message) { // node. Otherwise, we'll create an endless range. switch (parser->current.type) { case YP_CASE_PRIMITIVE: { - yp_node_t *right = parse_expression(parser, YP_BINDING_POWER_MAX, "Expected an expression after the range operator."); + yp_node_t *right = parse_expression(parser, YP_BINDING_POWER_MAX, YP_ERR_PATTERN_EXPRESSION_AFTER_RANGE); return (yp_node_t *) yp_range_node_create(parser, node, &operator, right); } default: @@ -10512,17 +10982,17 @@ parse_pattern_primitive(yp_parser_t *parser, const char *message) { yp_token_t lparen = parser->current; parser_lex(parser); - yp_node_t *expression = parse_expression(parser, YP_BINDING_POWER_STATEMENT, "Expected an expression after the pin operator."); + yp_node_t *expression = parse_expression(parser, YP_BINDING_POWER_STATEMENT, YP_ERR_PATTERN_EXPRESSION_AFTER_PIN); parser->pattern_matching_newlines = previous_pattern_matching_newlines; - accept(parser, YP_TOKEN_NEWLINE); - expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected a closing parenthesis after the expression."); + accept1(parser, YP_TOKEN_NEWLINE); + expect1(parser, YP_TOKEN_PARENTHESIS_RIGHT, YP_ERR_PATTERN_TERM_PAREN); return (yp_node_t *) yp_pinned_expression_node_create(parser, expression, &operator, &lparen, &parser->previous); } default: { // If we get here, then we have a pin operator followed by something // not understood. We'll create a missing node and return that. - yp_diagnostic_list_append(&parser->error_list, operator.start, operator.end, "Expected a variable after the pin operator."); + yp_diagnostic_list_append(&parser->error_list, operator.start, operator.end, YP_ERR_PATTERN_EXPRESSION_AFTER_PIN); yp_node_t *variable = (yp_node_t *) yp_missing_node_create(parser, operator.start, operator.end); return (yp_node_t *) yp_pinned_variable_node_create(parser, &operator, variable); } @@ -10532,7 +11002,7 @@ parse_pattern_primitive(yp_parser_t *parser, const char *message) { yp_token_t delimiter = parser->current; parser_lex(parser); - expect(parser, YP_TOKEN_CONSTANT, "Expected a constant after the :: operator."); + expect1(parser, YP_TOKEN_CONSTANT, YP_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT); yp_node_t *child = (yp_node_t *) yp_constant_read_node_create(parser, &parser->previous); yp_constant_path_node_t *node = yp_constant_path_node_create(parser, NULL, &delimiter, child); @@ -10546,7 +11016,7 @@ parse_pattern_primitive(yp_parser_t *parser, const char *message) { return parse_pattern_constant_path(parser, node); } default: - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, message); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, diag_id); return (yp_node_t *) yp_missing_node_create(parser, parser->current.start, parser->current.end); } } @@ -10554,7 +11024,7 @@ parse_pattern_primitive(yp_parser_t *parser, const char *message) { // Parse any number of primitives joined by alternation and ended optionally by // assignment. static yp_node_t * -parse_pattern_primitives(yp_parser_t *parser, const char *message) { +parse_pattern_primitives(yp_parser_t *parser, yp_diagnostic_id_t diag_id) { yp_node_t *node = NULL; do { @@ -10571,9 +11041,9 @@ parse_pattern_primitives(yp_parser_t *parser, const char *message) { case YP_TOKEN_UDOT_DOT_DOT: case YP_CASE_PRIMITIVE: { if (node == NULL) { - node = parse_pattern_primitive(parser, message); + node = parse_pattern_primitive(parser, diag_id); } else { - yp_node_t *right = parse_pattern_primitive(parser, "Expected to be able to parse a pattern after `|'."); + yp_node_t *right = parse_pattern_primitive(parser, YP_ERR_PATTERN_EXPRESSION_AFTER_PIPE); node = (yp_node_t *) yp_alternation_pattern_node_create(parser, node, right, &operator); } @@ -10584,13 +11054,13 @@ parse_pattern_primitives(yp_parser_t *parser, const char *message) { if (node != NULL) { yp_node_destroy(parser, node); } - node = parse_pattern(parser, false, "Expected a pattern after the opening parenthesis."); + node = parse_pattern(parser, false, YP_ERR_PATTERN_EXPRESSION_AFTER_PAREN); - expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected a closing parenthesis after the pattern."); + expect1(parser, YP_TOKEN_PARENTHESIS_RIGHT, YP_ERR_PATTERN_TERM_PAREN); break; } default: { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, message); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, diag_id); yp_node_t *right = (yp_node_t *) yp_missing_node_create(parser, parser->current.start, parser->current.end); if (node == NULL) { @@ -10602,14 +11072,14 @@ parse_pattern_primitives(yp_parser_t *parser, const char *message) { break; } } - } while (accept(parser, YP_TOKEN_PIPE)); + } while (accept1(parser, YP_TOKEN_PIPE)); // If we have an =>, then we are assigning this pattern to a variable. // In this case we should create an assignment node. - while (accept(parser, YP_TOKEN_EQUAL_GREATER)) { + while (accept1(parser, YP_TOKEN_EQUAL_GREATER)) { yp_token_t operator = parser->previous; - expect(parser, YP_TOKEN_IDENTIFIER, "Expected an identifier after the `=>' operator."); + expect1(parser, YP_TOKEN_IDENTIFIER, YP_ERR_PATTERN_IDENT_AFTER_HROCKET); yp_token_t identifier = parser->previous; yp_parser_local_add_token(parser, &identifier); @@ -10622,7 +11092,7 @@ parse_pattern_primitives(yp_parser_t *parser, const char *message) { // Parse a pattern matching expression. static yp_node_t * -parse_pattern(yp_parser_t *parser, bool top_pattern, const char *message) { +parse_pattern(yp_parser_t *parser, bool top_pattern, yp_diagnostic_id_t diag_id) { yp_node_t *node = NULL; bool leading_rest = false; @@ -10650,7 +11120,7 @@ parse_pattern(yp_parser_t *parser, bool top_pattern, const char *message) { } /* fallthrough */ default: - node = parse_pattern_primitives(parser, message); + node = parse_pattern_primitives(parser, diag_id); break; } @@ -10661,7 +11131,7 @@ parse_pattern(yp_parser_t *parser, bool top_pattern, const char *message) { return (yp_node_t *) parse_pattern_hash(parser, (yp_node_t *) yp_assoc_node_create(parser, node, &operator, NULL)); } - if (top_pattern && match_type_p(parser, YP_TOKEN_COMMA)) { + if (top_pattern && match1(parser, YP_TOKEN_COMMA)) { // If we have a comma, then we are now parsing either an array pattern or a // find pattern. We need to parse all of the patterns, put them into a big // list, and then determine which type of node we have. @@ -10669,25 +11139,25 @@ parse_pattern(yp_parser_t *parser, bool top_pattern, const char *message) { yp_node_list_append(&nodes, node); // Gather up all of the patterns into the list. - while (accept(parser, YP_TOKEN_COMMA)) { + while (accept1(parser, YP_TOKEN_COMMA)) { // Break early here in case we have a trailing comma. - if (match_any_type_p(parser, 5, YP_TOKEN_KEYWORD_THEN, YP_TOKEN_BRACE_RIGHT, YP_TOKEN_BRACKET_RIGHT, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)) { + if (match5(parser, YP_TOKEN_KEYWORD_THEN, YP_TOKEN_BRACE_RIGHT, YP_TOKEN_BRACKET_RIGHT, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)) { break; } - if (accept(parser, YP_TOKEN_USTAR)) { + if (accept1(parser, YP_TOKEN_USTAR)) { node = (yp_node_t *) parse_pattern_rest(parser); // If we have already parsed a splat pattern, then this is an error. We // will continue to parse the rest of the patterns, but we will indicate // it as an error. if (trailing_rest) { - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Unexpected rest pattern."); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_PATTERN_REST); } trailing_rest = true; } else { - node = parse_pattern_primitives(parser, "Expected a pattern after the comma."); + node = parse_pattern_primitives(parser, YP_ERR_PATTERN_EXPRESSION_AFTER_COMMA); } yp_node_list_append(&nodes, node); @@ -10697,7 +11167,7 @@ parse_pattern(yp_parser_t *parser, bool top_pattern, const char *message) { // call this a find pattern, regardless of how many rest patterns are in // between because we know we already added the appropriate errors. // Otherwise we will create an array pattern. - if (YP_NODE_TYPE_P(nodes.nodes[0], YP_NODE_SPLAT_NODE) && YP_NODE_TYPE_P(nodes.nodes[nodes.size - 1], YP_NODE_SPLAT_NODE)) { + if (YP_NODE_TYPE_P(nodes.nodes[0], YP_SPLAT_NODE) && YP_NODE_TYPE_P(nodes.nodes[nodes.size - 1], YP_SPLAT_NODE)) { node = (yp_node_t *) yp_find_pattern_node_create(parser, &nodes); } else { node = (yp_node_t *) yp_array_pattern_node_node_list_create(parser, &nodes); @@ -10719,15 +11189,15 @@ parse_pattern(yp_parser_t *parser, bool top_pattern, const char *message) { static inline void parse_negative_numeric(yp_node_t *node) { switch (YP_NODE_TYPE(node)) { - case YP_NODE_INTEGER_NODE: - case YP_NODE_FLOAT_NODE: + case YP_INTEGER_NODE: + case YP_FLOAT_NODE: node->location.start--; break; - case YP_NODE_RATIONAL_NODE: + case YP_RATIONAL_NODE: node->location.start--; parse_negative_numeric(((yp_rational_node_t *) node)->numeric); break; - case YP_NODE_IMAGINARY_NODE: + case YP_IMAGINARY_NODE: node->location.start--; parse_negative_numeric(((yp_imaginary_node_t *) node)->numeric); break; @@ -10737,6 +11207,163 @@ parse_negative_numeric(yp_node_t *node) { } } +// Returns a string content token at a particular location that is empty. +static yp_token_t +parse_strings_empty_content(const uint8_t *location) { + return (yp_token_t) { .type = YP_TOKEN_STRING_CONTENT, .start = location, .end = location }; +} + +// Parse a set of strings that could be concatenated together. +static inline yp_node_t * +parse_strings(yp_parser_t *parser) { + assert(parser->current.type == YP_TOKEN_STRING_BEGIN); + yp_node_t *result = NULL; + + while (match1(parser, YP_TOKEN_STRING_BEGIN)) { + yp_node_t *node = NULL; + + // Here we have found a string literal. We'll parse it and add it to + // the list of strings. + assert(parser->lex_modes.current->mode == YP_LEX_STRING); + bool lex_interpolation = parser->lex_modes.current->as.string.interpolation; + + yp_token_t opening = parser->current; + parser_lex(parser); + + if (accept1(parser, YP_TOKEN_STRING_END)) { + // If we get here, then we have an end immediately after a + // start. In that case we'll create an empty content token and + // return an uninterpolated string. + yp_token_t content = parse_strings_empty_content(parser->previous.start); + node = (yp_node_t *) yp_string_node_create_and_unescape(parser, &opening, &content, &parser->previous, YP_UNESCAPE_NONE); + } else if (accept1(parser, YP_TOKEN_LABEL_END)) { + // If we get here, then we have an end of a label immediately + // after a start. In that case we'll create an empty symbol + // node. + yp_token_t opening = not_provided(parser); + yp_token_t content = parse_strings_empty_content(parser->previous.start); + node = (yp_node_t *) yp_symbol_node_create(parser, &opening, &content, &parser->previous); + } else if (!lex_interpolation) { + // If we don't accept interpolation then we expect the string to + // start with a single string content node. + expect1(parser, YP_TOKEN_STRING_CONTENT, YP_ERR_EXPECT_STRING_CONTENT); + yp_token_t content = parser->previous; + + // It is unfortunately possible to have multiple string content + // nodes in a row in the case that there's heredoc content in + // the middle of the string, like this cursed example: + // + // <<-END+'b + // a + // END + // c'+'d' + // + // In that case we need to switch to an interpolated string to + // be able to contain all of the parts. + if (match1(parser, YP_TOKEN_STRING_CONTENT)) { + yp_node_list_t parts = YP_EMPTY_NODE_LIST; + + yp_token_t delimiters = not_provided(parser); + yp_node_t *part = (yp_node_t *) yp_string_node_create_and_unescape(parser, &delimiters, &content, &delimiters, YP_UNESCAPE_MINIMAL); + yp_node_list_append(&parts, part); + + while (accept1(parser, YP_TOKEN_STRING_CONTENT)) { + part = (yp_node_t *) yp_string_node_create_and_unescape(parser, &delimiters, &parser->previous, &delimiters, YP_UNESCAPE_MINIMAL); + yp_node_list_append(&parts, part); + } + + expect1(parser, YP_TOKEN_STRING_END, YP_ERR_STRING_LITERAL_TERM); + node = (yp_node_t *) yp_interpolated_string_node_create(parser, &opening, &parts, &parser->previous); + } else if (accept1(parser, YP_TOKEN_LABEL_END)) { + node = (yp_node_t *) yp_symbol_node_create_and_unescape(parser, &opening, &content, &parser->previous, YP_UNESCAPE_ALL); + } else { + expect1(parser, YP_TOKEN_STRING_END, YP_ERR_STRING_LITERAL_TERM); + node = (yp_node_t *) yp_string_node_create_and_unescape(parser, &opening, &content, &parser->previous, YP_UNESCAPE_MINIMAL); + } + } else if (match1(parser, YP_TOKEN_STRING_CONTENT)) { + // In this case we've hit string content so we know the string + // at least has something in it. We'll need to check if the + // following token is the end (in which case we can return a + // plain string) or if it's not then it has interpolation. + yp_token_t content = parser->current; + parser_lex(parser); + + if (accept1(parser, YP_TOKEN_STRING_END)) { + node = (yp_node_t *) yp_string_node_create_and_unescape(parser, &opening, &content, &parser->previous, YP_UNESCAPE_ALL); + } else if (accept1(parser, YP_TOKEN_LABEL_END)) { + node = (yp_node_t *) yp_symbol_node_create_and_unescape(parser, &opening, &content, &parser->previous, YP_UNESCAPE_ALL); + } else { + // If we get here, then we have interpolation so we'll need + // to create a string or symbol node with interpolation. + yp_node_list_t parts = YP_EMPTY_NODE_LIST; + yp_token_t string_opening = not_provided(parser); + yp_token_t string_closing = not_provided(parser); + + yp_node_t *part = (yp_node_t *) yp_string_node_create_and_unescape(parser, &string_opening, &parser->previous, &string_closing, YP_UNESCAPE_ALL); + yp_node_list_append(&parts, part); + + while (!match3(parser, YP_TOKEN_STRING_END, YP_TOKEN_LABEL_END, YP_TOKEN_EOF)) { + if ((part = parse_string_part(parser)) != NULL) { + yp_node_list_append(&parts, part); + } + } + + if (accept1(parser, YP_TOKEN_LABEL_END)) { + node = (yp_node_t *) yp_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous); + } else { + expect1(parser, YP_TOKEN_STRING_END, YP_ERR_STRING_INTERPOLATED_TERM); + node = (yp_node_t *) yp_interpolated_string_node_create(parser, &opening, &parts, &parser->previous); + } + } + } else { + // If we get here, then the first part of the string is not + // plain string content, in which case we need to parse the + // string as an interpolated string. + yp_node_list_t parts = YP_EMPTY_NODE_LIST; + yp_node_t *part = NULL; + + while (!match3(parser, YP_TOKEN_STRING_END, YP_TOKEN_LABEL_END, YP_TOKEN_EOF)) { + if ((part = parse_string_part(parser)) != NULL) { + yp_node_list_append(&parts, part); + } + } + + if (accept1(parser, YP_TOKEN_LABEL_END)) { + node = (yp_node_t *) yp_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous); + } else { + expect1(parser, YP_TOKEN_STRING_END, YP_ERR_STRING_INTERPOLATED_TERM); + node = (yp_node_t *) yp_interpolated_string_node_create(parser, &opening, &parts, &parser->previous); + } + } + + if (result == NULL) { + // If the node we just parsed is a symbol node, then we can't + // concatenate it with anything else, so we can now return that + // node. + if (YP_NODE_TYPE_P(node, YP_SYMBOL_NODE) || YP_NODE_TYPE_P(node, YP_INTERPOLATED_SYMBOL_NODE)) { + return node; + } + + // If we don't already have a node, then it's fine and we can just + // set the result to be the node we just parsed. + result = node; + } else { + // Otherwise we need to check the type of the node we just parsed. + // If it cannot be concatenated with the previous node, then we'll + // need to add a syntax error. + if (!YP_NODE_TYPE_P(node, YP_STRING_NODE) && !YP_NODE_TYPE_P(node, YP_INTERPOLATED_STRING_NODE)) { + yp_diagnostic_list_append(&parser->error_list, node->location.start, node->location.end, YP_ERR_STRING_CONCATENATION); + } + + // Either way we will create a concat node to hold the strings + // together. + result = (yp_node_t *) yp_string_concat_node_create(parser, result, node); + } + } + + return result; +} + // Parse an expression that begins with the previous node that we just lexed. static inline yp_node_t * parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { @@ -10748,46 +11375,46 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_accepts_block_stack_push(parser, true); bool parsed_bare_hash = false; - while (!match_any_type_p(parser, 2, YP_TOKEN_BRACKET_RIGHT, YP_TOKEN_EOF)) { + while (!match2(parser, YP_TOKEN_BRACKET_RIGHT, YP_TOKEN_EOF)) { // Handle the case where we don't have a comma and we have a newline followed by a right bracket. - if (accept(parser, YP_TOKEN_NEWLINE) && match_type_p(parser, YP_TOKEN_BRACKET_RIGHT)) { + if (accept1(parser, YP_TOKEN_NEWLINE) && match1(parser, YP_TOKEN_BRACKET_RIGHT)) { break; } if (yp_array_node_size(array) != 0) { - expect(parser, YP_TOKEN_COMMA, "Expected a separator for the elements in an array."); + expect1(parser, YP_TOKEN_COMMA, YP_ERR_ARRAY_SEPARATOR); } // If we have a right bracket immediately following a comma, this is // allowed since it's a trailing comma. In this case we can break out of // the loop. - if (match_type_p(parser, YP_TOKEN_BRACKET_RIGHT)) break; + if (match1(parser, YP_TOKEN_BRACKET_RIGHT)) break; yp_node_t *element; - if (accept(parser, YP_TOKEN_USTAR)) { + if (accept1(parser, YP_TOKEN_USTAR)) { yp_token_t operator = parser->previous; - yp_node_t *expression = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected an expression after '*' in the array."); + yp_node_t *expression = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_ARRAY_EXPRESSION_AFTER_STAR); element = (yp_node_t *) yp_splat_node_create(parser, &operator, expression); - } else if (match_any_type_p(parser, 2, YP_TOKEN_LABEL, YP_TOKEN_USTAR_STAR)) { + } else if (match2(parser, YP_TOKEN_LABEL, YP_TOKEN_USTAR_STAR)) { if (parsed_bare_hash) { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Unexpected bare hash."); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_EXPRESSION_BARE_HASH); } yp_keyword_hash_node_t *hash = yp_keyword_hash_node_create(parser); element = (yp_node_t *)hash; - if (!match_any_type_p(parser, 8, YP_TOKEN_EOF, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON, YP_TOKEN_EOF, YP_TOKEN_BRACE_RIGHT, YP_TOKEN_BRACKET_RIGHT, YP_TOKEN_KEYWORD_DO, YP_TOKEN_PARENTHESIS_RIGHT)) { + if (!match8(parser, YP_TOKEN_EOF, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON, YP_TOKEN_EOF, YP_TOKEN_BRACE_RIGHT, YP_TOKEN_BRACKET_RIGHT, YP_TOKEN_KEYWORD_DO, YP_TOKEN_PARENTHESIS_RIGHT)) { parse_assocs(parser, (yp_node_t *) hash); } parsed_bare_hash = true; } else { - element = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected an element for the array."); + element = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_ARRAY_EXPRESSION); - if (yp_symbol_node_label_p(element) || accept(parser, YP_TOKEN_EQUAL_GREATER)) { + if (yp_symbol_node_label_p(element) || accept1(parser, YP_TOKEN_EQUAL_GREATER)) { if (parsed_bare_hash) { - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Unexpected bare hash."); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_EXPRESSION_BARE_HASH); } yp_keyword_hash_node_t *hash = yp_keyword_hash_node_create(parser); @@ -10799,12 +11426,12 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { operator = not_provided(parser); } - yp_node_t *value = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected a value in the hash literal."); + yp_node_t *value = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_HASH_VALUE); yp_node_t *assoc = (yp_node_t *) yp_assoc_node_create(parser, element, &operator, value); yp_keyword_hash_node_elements_append(hash, assoc); element = (yp_node_t *)hash; - if (accept(parser, YP_TOKEN_COMMA) && !match_type_p(parser, YP_TOKEN_BRACKET_RIGHT)) { + if (accept1(parser, YP_TOKEN_COMMA) && !match1(parser, YP_TOKEN_BRACKET_RIGHT)) { parse_assocs(parser, (yp_node_t *) hash); } @@ -10813,11 +11440,11 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { } yp_array_node_elements_append(array, element); - if (YP_NODE_TYPE_P(element, YP_NODE_MISSING_NODE)) break; + if (YP_NODE_TYPE_P(element, YP_MISSING_NODE)) break; } - accept(parser, YP_TOKEN_NEWLINE); - expect(parser, YP_TOKEN_BRACKET_RIGHT, "Expected a closing bracket for the array."); + accept1(parser, YP_TOKEN_NEWLINE); + expect1(parser, YP_TOKEN_BRACKET_RIGHT, YP_ERR_ARRAY_TERM); yp_array_node_close_set(array, &parser->previous); yp_accepts_block_stack_pop(parser); @@ -10827,53 +11454,62 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { case YP_TOKEN_PARENTHESIS_LEFT_PARENTHESES: { yp_token_t opening = parser->current; parser_lex(parser); - while (accept_any(parser, 2, YP_TOKEN_SEMICOLON, YP_TOKEN_NEWLINE)); + while (accept2(parser, YP_TOKEN_SEMICOLON, YP_TOKEN_NEWLINE)); // If this is the end of the file or we match a right parenthesis, then // we have an empty parentheses node, and we can immediately return. - if (match_any_type_p(parser, 2, YP_TOKEN_PARENTHESIS_RIGHT, YP_TOKEN_EOF)) { - expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected a closing parenthesis."); + if (match2(parser, YP_TOKEN_PARENTHESIS_RIGHT, YP_TOKEN_EOF)) { + expect1(parser, YP_TOKEN_PARENTHESIS_RIGHT, YP_ERR_EXPECT_RPAREN); return (yp_node_t *) yp_parentheses_node_create(parser, &opening, NULL, &parser->previous); } - // Otherwise, we're going to parse the first statement in the list of - // statements within the parentheses. + // Otherwise, we're going to parse the first statement in the list + // of statements within the parentheses. yp_accepts_block_stack_push(parser, true); - yp_node_t *statement = parse_expression(parser, YP_BINDING_POWER_STATEMENT, "Expected to be able to parse an expression."); - while (accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)); + yp_node_t *statement = parse_expression(parser, YP_BINDING_POWER_STATEMENT, YP_ERR_CANNOT_PARSE_EXPRESSION); + + // Determine if this statement is followed by a terminator. In the + // case of a single statement, this is fine. But in the case of + // multiple statements it's required. + bool terminator_found = accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); + if (terminator_found) { + while (accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)); + } - // If we hit a right parenthesis, then we're done parsing the parentheses - // node, and we can check which kind of node we should return. - if (match_type_p(parser, YP_TOKEN_PARENTHESIS_RIGHT)) { + // If we hit a right parenthesis, then we're done parsing the + // parentheses node, and we can check which kind of node we should + // return. + if (match1(parser, YP_TOKEN_PARENTHESIS_RIGHT)) { if (opening.type == YP_TOKEN_PARENTHESIS_LEFT_PARENTHESES) { lex_state_set(parser, YP_LEX_STATE_ENDARG); } parser_lex(parser); yp_accepts_block_stack_pop(parser); - // If we have a single statement and are ending on a right parenthesis, - // then we need to check if this is possibly a multiple assignment node. - if (binding_power == YP_BINDING_POWER_STATEMENT && YP_NODE_TYPE_P(statement, YP_NODE_MULTI_WRITE_NODE)) { - yp_multi_write_node_t *multi_statement = (yp_multi_write_node_t *) statement; - - if (multi_statement->value == NULL) { - yp_location_t lparen_loc = { .start = opening.start, .end = opening.end }; - yp_location_t rparen_loc = { .start = parser->previous.start, .end = parser->previous.end }; - yp_multi_write_node_t *multi_write; - - if (multi_statement->lparen_loc.start == NULL) { - multi_write = (yp_multi_write_node_t *) statement; - multi_write->base.location.start = lparen_loc.start; - multi_write->base.location.end = rparen_loc.end; - multi_write->lparen_loc = lparen_loc; - multi_write->rparen_loc = rparen_loc; - } else { - yp_token_t operator = not_provided(parser); - multi_write = yp_multi_write_node_create(parser, &operator, NULL, &lparen_loc, &rparen_loc); - yp_multi_write_node_targets_append(multi_write, statement); - } + // If we have a single statement and are ending on a right + // parenthesis, then we need to check if this is possibly a + // multiple target node. + if (YP_NODE_TYPE_P(statement, YP_MULTI_TARGET_NODE)) { + yp_multi_target_node_t *multi_target; + if (((yp_multi_target_node_t *) statement)->lparen_loc.start == NULL) { + multi_target = (yp_multi_target_node_t *) statement; + } else { + multi_target = yp_multi_target_node_create(parser); + yp_multi_target_node_targets_append(multi_target, statement); + } + + yp_location_t lparen_loc = YP_LOCATION_TOKEN_VALUE(&opening); + yp_location_t rparen_loc = YP_LOCATION_TOKEN_VALUE(&parser->previous); - return parse_targets(parser, (yp_node_t *) multi_write, YP_BINDING_POWER_INDEX); + multi_target->lparen_loc = lparen_loc; + multi_target->rparen_loc = rparen_loc; + multi_target->base.location.start = lparen_loc.start; + multi_target->base.location.end = rparen_loc.end; + + if (match1(parser, YP_TOKEN_COMMA)) { + return parse_targets_validate(parser, (yp_node_t *) multi_target, YP_BINDING_POWER_INDEX); + } else { + return parse_target_validate(parser, (yp_node_t *) multi_target); } } @@ -10886,35 +11522,52 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { return (yp_node_t *) yp_parentheses_node_create(parser, &opening, (yp_node_t *) statements, &parser->previous); } - // If we have more than one statement in the set of parentheses, then we - // are going to parse all of them as a list of statements. We'll do that - // here. + // If we have more than one statement in the set of parentheses, + // then we are going to parse all of them as a list of statements. + // We'll do that here. context_push(parser, YP_CONTEXT_PARENS); yp_statements_node_t *statements = yp_statements_node_create(parser); yp_statements_node_body_append(statements, statement); - while (!match_type_p(parser, YP_TOKEN_PARENTHESIS_RIGHT)) { - // Ignore semicolon without statements before them - if (accept_any(parser, 2, YP_TOKEN_SEMICOLON, YP_TOKEN_NEWLINE)) continue; + // If we didn't find a terminator and we didn't find a right + // parenthesis, then this is a syntax error. + if (!terminator_found) { + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.start, YP_ERR_EXPECT_EOL_AFTER_STATEMENT); + } - yp_node_t *node = parse_expression(parser, YP_BINDING_POWER_STATEMENT, "Expected to be able to parse an expression."); + // Parse each statement within the parentheses. + while (true) { + yp_node_t *node = parse_expression(parser, YP_BINDING_POWER_STATEMENT, YP_ERR_CANNOT_PARSE_EXPRESSION); yp_statements_node_body_append(statements, node); - // If we're recovering from a syntax error, then we need to stop parsing the - // statements now. + // If we're recovering from a syntax error, then we need to stop + // parsing the statements now. if (parser->recovering) { - // If this is the level of context where the recovery has happened, then - // we can mark the parser as done recovering. - if (match_type_p(parser, YP_TOKEN_PARENTHESIS_RIGHT)) parser->recovering = false; + // If this is the level of context where the recovery has + // happened, then we can mark the parser as done recovering. + if (match1(parser, YP_TOKEN_PARENTHESIS_RIGHT)) parser->recovering = false; break; } - if (!accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)) break; + // If we couldn't parse an expression at all, then we need to + // bail out of the loop. + if (YP_NODE_TYPE_P(node, YP_MISSING_NODE)) break; + + // If we successfully parsed a statement, then we are going to + // need terminator to delimit them. + if (accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)) { + while (accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)); + if (match1(parser, YP_TOKEN_PARENTHESIS_RIGHT)) break; + } else if (match1(parser, YP_TOKEN_PARENTHESIS_RIGHT)) { + break; + } else { + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.start, YP_ERR_EXPECT_EOL_AFTER_STATEMENT); + } } context_pop(parser); yp_accepts_block_stack_pop(parser); - expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected a closing parenthesis."); + expect1(parser, YP_TOKEN_PARENTHESIS_RIGHT, YP_ERR_EXPECT_RPAREN); return (yp_node_t *) yp_parentheses_node_create(parser, &opening, (yp_node_t *) statements, &parser->previous); } @@ -10923,13 +11576,13 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser_lex(parser); yp_hash_node_t *node = yp_hash_node_create(parser, &parser->previous); - if (!match_any_type_p(parser, 2, YP_TOKEN_BRACE_RIGHT, YP_TOKEN_EOF)) { + if (!match2(parser, YP_TOKEN_BRACE_RIGHT, YP_TOKEN_EOF)) { parse_assocs(parser, (yp_node_t *) node); - accept(parser, YP_TOKEN_NEWLINE); + accept1(parser, YP_TOKEN_NEWLINE); } yp_accepts_block_stack_pop(parser); - expect(parser, YP_TOKEN_BRACE_RIGHT, "Expected a closing delimiter for a hash literal."); + expect1(parser, YP_TOKEN_BRACE_RIGHT, YP_ERR_HASH_TERM); yp_hash_node_closing_loc_set(node, &parser->previous); return (yp_node_t *) node; @@ -10946,15 +11599,23 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { content.start = content.start + 1; yp_token_t closing = not_provided(parser); + yp_node_t *node = (yp_node_t *) yp_char_literal_node_create_and_unescape(parser, &opening, &content, &closing, YP_UNESCAPE_ALL); + + // Characters can be followed by strings in which case they are + // automatically concatenated. + if (match1(parser, YP_TOKEN_STRING_BEGIN)) { + yp_node_t *concat = parse_strings(parser); + return (yp_node_t *) yp_string_concat_node_create(parser, node, concat); + } - return (yp_node_t *) yp_char_literal_node_create_and_unescape(parser, &opening, &content, &closing, YP_UNESCAPE_ALL); + return node; } case YP_TOKEN_CLASS_VARIABLE: { parser_lex(parser); yp_node_t *node = (yp_node_t *) yp_class_variable_read_node_create(parser, &parser->previous); - if (binding_power == YP_BINDING_POWER_STATEMENT && match_type_p(parser, YP_TOKEN_COMMA)) { - node = parse_targets(parser, node, YP_BINDING_POWER_INDEX); + if (binding_power == YP_BINDING_POWER_STATEMENT && match1(parser, YP_TOKEN_COMMA)) { + node = parse_targets_validate(parser, node, YP_BINDING_POWER_INDEX); } return node; @@ -10966,9 +11627,9 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { // If a constant is immediately followed by parentheses, then this is in // fact a method call, not a constant read. if ( - match_type_p(parser, YP_TOKEN_PARENTHESIS_LEFT) || - (binding_power <= YP_BINDING_POWER_ASSIGNMENT && (token_begins_expression_p(parser->current.type) || match_any_type_p(parser, 3, YP_TOKEN_UAMPERSAND, YP_TOKEN_USTAR, YP_TOKEN_USTAR_STAR))) || - (yp_accepts_block_stack_p(parser) && match_any_type_p(parser, 2, YP_TOKEN_KEYWORD_DO, YP_TOKEN_BRACE_LEFT)) + match1(parser, YP_TOKEN_PARENTHESIS_LEFT) || + (binding_power <= YP_BINDING_POWER_ASSIGNMENT && (token_begins_expression_p(parser->current.type) || match3(parser, YP_TOKEN_UAMPERSAND, YP_TOKEN_USTAR, YP_TOKEN_USTAR_STAR))) || + (yp_accepts_block_stack_p(parser) && match2(parser, YP_TOKEN_KEYWORD_DO, YP_TOKEN_BRACE_LEFT)) ) { yp_arguments_t arguments = YP_EMPTY_ARGUMENTS; parse_arguments_list(parser, &arguments, true); @@ -10977,10 +11638,10 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_node_t *node = (yp_node_t *) yp_constant_read_node_create(parser, &parser->previous); - if ((binding_power == YP_BINDING_POWER_STATEMENT) && match_type_p(parser, YP_TOKEN_COMMA)) { + if ((binding_power == YP_BINDING_POWER_STATEMENT) && match1(parser, YP_TOKEN_COMMA)) { // If we get here, then we have a comma immediately following a // constant, so we're going to parse this as a multiple assignment. - node = parse_targets(parser, node, YP_BINDING_POWER_INDEX); + node = parse_targets_validate(parser, node, YP_BINDING_POWER_INDEX); } return node; @@ -10989,13 +11650,13 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser_lex(parser); yp_token_t delimiter = parser->previous; - expect(parser, YP_TOKEN_CONSTANT, "Expected a constant after ::."); + expect1(parser, YP_TOKEN_CONSTANT, YP_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT); yp_node_t *constant = (yp_node_t *) yp_constant_read_node_create(parser, &parser->previous); yp_node_t *node = (yp_node_t *)yp_constant_path_node_create(parser, NULL, &delimiter, constant); - if ((binding_power == YP_BINDING_POWER_STATEMENT) && match_type_p(parser, YP_TOKEN_COMMA)) { - node = parse_targets(parser, node, YP_BINDING_POWER_INDEX); + if ((binding_power == YP_BINDING_POWER_STATEMENT) && match1(parser, YP_TOKEN_COMMA)) { + node = parse_targets_validate(parser, node, YP_BINDING_POWER_INDEX); } return node; @@ -11005,7 +11666,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_token_t operator = parser->current; parser_lex(parser); - yp_node_t *right = parse_expression(parser, binding_power, "Expected a value after the operator."); + yp_node_t *right = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); return (yp_node_t *) yp_range_node_create(parser, NULL, &operator, right); } case YP_TOKEN_FLOAT: @@ -11024,8 +11685,8 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser_lex(parser); yp_node_t *node = (yp_node_t *) yp_numbered_reference_read_node_create(parser, &parser->previous); - if (binding_power == YP_BINDING_POWER_STATEMENT && match_type_p(parser, YP_TOKEN_COMMA)) { - node = parse_targets(parser, node, YP_BINDING_POWER_INDEX); + if (binding_power == YP_BINDING_POWER_STATEMENT && match1(parser, YP_TOKEN_COMMA)) { + node = parse_targets_validate(parser, node, YP_BINDING_POWER_INDEX); } return node; @@ -11034,8 +11695,8 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser_lex(parser); yp_node_t *node = (yp_node_t *) yp_global_variable_read_node_create(parser, &parser->previous); - if (binding_power == YP_BINDING_POWER_STATEMENT && match_type_p(parser, YP_TOKEN_COMMA)) { - node = parse_targets(parser, node, YP_BINDING_POWER_INDEX); + if (binding_power == YP_BINDING_POWER_STATEMENT && match1(parser, YP_TOKEN_COMMA)) { + node = parse_targets_validate(parser, node, YP_BINDING_POWER_INDEX); } return node; @@ -11044,8 +11705,8 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser_lex(parser); yp_node_t *node = (yp_node_t *) yp_back_reference_read_node_create(parser, &parser->previous); - if (binding_power == YP_BINDING_POWER_STATEMENT && match_type_p(parser, YP_TOKEN_COMMA)) { - node = parse_targets(parser, node, YP_BINDING_POWER_INDEX); + if (binding_power == YP_BINDING_POWER_STATEMENT && match1(parser, YP_TOKEN_COMMA)) { + node = parse_targets_validate(parser, node, YP_BINDING_POWER_INDEX); } return node; @@ -11055,7 +11716,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_token_t identifier = parser->previous; yp_node_t *node = parse_variable_call(parser); - if (YP_NODE_TYPE_P(node, YP_NODE_CALL_NODE)) { + if (YP_NODE_TYPE_P(node, YP_CALL_NODE)) { // If parse_variable_call returned with a call node, then we // know the identifier is not in the local table. In that case // we need to check if there are arguments following the @@ -11074,7 +11735,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { call->block = arguments.block; if (arguments.block != NULL) { - call->base.location.end = arguments.block->base.location.end; + call->base.location.end = arguments.block->location.end; } else if (arguments.closing_loc.start == NULL) { if (arguments.arguments != NULL) { call->base.location.end = arguments.arguments->base.location.end; @@ -11090,8 +11751,8 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { // can still be a method call if it is followed by arguments or // a block, so we need to check for that here. if ( - (binding_power <= YP_BINDING_POWER_ASSIGNMENT && (token_begins_expression_p(parser->current.type) || match_any_type_p(parser, 3, YP_TOKEN_UAMPERSAND, YP_TOKEN_USTAR, YP_TOKEN_USTAR_STAR))) || - (yp_accepts_block_stack_p(parser) && match_any_type_p(parser, 2, YP_TOKEN_KEYWORD_DO, YP_TOKEN_BRACE_LEFT)) + (binding_power <= YP_BINDING_POWER_ASSIGNMENT && (token_begins_expression_p(parser->current.type) || match3(parser, YP_TOKEN_UAMPERSAND, YP_TOKEN_USTAR, YP_TOKEN_USTAR_STAR))) || + (yp_accepts_block_stack_p(parser) && match2(parser, YP_TOKEN_KEYWORD_DO, YP_TOKEN_BRACE_LEFT)) ) { yp_arguments_t arguments = YP_EMPTY_ARGUMENTS; parse_arguments_list(parser, &arguments, true); @@ -11102,91 +11763,149 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { } } - if ((binding_power == YP_BINDING_POWER_STATEMENT) && match_type_p(parser, YP_TOKEN_COMMA)) { - node = parse_targets(parser, node, YP_BINDING_POWER_INDEX); + if ((binding_power == YP_BINDING_POWER_STATEMENT) && match1(parser, YP_TOKEN_COMMA)) { + node = parse_targets_validate(parser, node, YP_BINDING_POWER_INDEX); } return node; } case YP_TOKEN_HEREDOC_START: { + // Here we have found a heredoc. We'll parse it and add it to the + // list of strings. assert(parser->lex_modes.current->mode == YP_LEX_HEREDOC); yp_heredoc_quote_t quote = parser->lex_modes.current->as.heredoc.quote; yp_heredoc_indent_t indent = parser->lex_modes.current->as.heredoc.indent; - yp_node_t *node; - if (quote == YP_HEREDOC_QUOTE_BACKTICK) { - node = (yp_node_t *) yp_interpolated_xstring_node_create(parser, &parser->current, &parser->current); - } else { - node = (yp_node_t *) yp_interpolated_string_node_create(parser, &parser->current, NULL, &parser->current); - } - parser_lex(parser); + yp_token_t opening = parser->previous; + + yp_node_t *node; yp_node_t *part; - while (!match_any_type_p(parser, 2, YP_TOKEN_HEREDOC_END, YP_TOKEN_EOF)) { - if ((part = parse_string_part(parser)) == NULL) continue; + if (match2(parser, YP_TOKEN_HEREDOC_END, YP_TOKEN_EOF)) { + // If we get here, then we have an empty heredoc. We'll create + // an empty content token and return an empty string node. + lex_state_set(parser, YP_LEX_STATE_END); + expect1(parser, YP_TOKEN_HEREDOC_END, YP_ERR_HEREDOC_TERM); + yp_token_t content = parse_strings_empty_content(parser->previous.start); if (quote == YP_HEREDOC_QUOTE_BACKTICK) { - yp_interpolated_xstring_node_append((yp_interpolated_x_string_node_t *) node, part); + node = (yp_node_t *) yp_xstring_node_create_and_unescape(parser, &opening, &content, &parser->previous); } else { - yp_interpolated_string_node_append((yp_interpolated_string_node_t *) node, part); + node = (yp_node_t *) yp_string_node_create_and_unescape(parser, &opening, &content, &parser->previous, YP_UNESCAPE_NONE); } - } - lex_state_set(parser, YP_LEX_STATE_END); - expect(parser, YP_TOKEN_HEREDOC_END, "Expected a closing delimiter for heredoc."); + node->location.end = opening.end; + } else if ((part = parse_string_part(parser)) == NULL) { + // If we get here, then we tried to find something in the + // heredoc but couldn't actually parse anything, so we'll just + // return a missing node. + node = (yp_node_t *) yp_missing_node_create(parser, parser->previous.start, parser->previous.end); + } else if (YP_NODE_TYPE_P(part, YP_STRING_NODE) && match2(parser, YP_TOKEN_HEREDOC_END, YP_TOKEN_EOF)) { + // If we get here, then the part that we parsed was plain string + // content and we're at the end of the heredoc, so we can return + // just a string node with the heredoc opening and closing as + // its opening and closing. + yp_string_node_t *cast = (yp_string_node_t *) part; + + cast->opening_loc = YP_LOCATION_TOKEN_VALUE(&opening); + cast->closing_loc = YP_LOCATION_TOKEN_VALUE(&parser->current); + cast->base.location = cast->opening_loc; + + if (quote == YP_HEREDOC_QUOTE_BACKTICK) { + assert(sizeof(yp_string_node_t) == sizeof(yp_x_string_node_t)); + cast->base.type = YP_X_STRING_NODE; + } - if (quote == YP_HEREDOC_QUOTE_BACKTICK) { - assert(YP_NODE_TYPE_P(node, YP_NODE_INTERPOLATED_X_STRING_NODE)); - yp_interpolated_xstring_node_closing_set(((yp_interpolated_x_string_node_t *) node), &parser->previous); - node->location = ((yp_interpolated_x_string_node_t *) node)->opening_loc; + lex_state_set(parser, YP_LEX_STATE_END); + expect1(parser, YP_TOKEN_HEREDOC_END, YP_ERR_HEREDOC_TERM); + + node = (yp_node_t *) cast; + + if (indent == YP_HEREDOC_INDENT_TILDE) { + int common_whitespace = parse_heredoc_common_whitespace_for_single_node(parser, node, -1); + parse_heredoc_dedent_single_node(parser, &cast->unescaped, true, common_whitespace, quote); + } } else { - assert(YP_NODE_TYPE_P(node, YP_NODE_INTERPOLATED_STRING_NODE)); - yp_interpolated_string_node_closing_set((yp_interpolated_string_node_t *) node, &parser->previous); - node->location = ((yp_interpolated_string_node_t *) node)->opening_loc; - } + // If we get here, then we have multiple parts in the heredoc, + // so we'll need to create an interpolated string node to hold + // them all. + yp_node_list_t parts = YP_EMPTY_NODE_LIST; + yp_node_list_append(&parts, part); + + while (!match2(parser, YP_TOKEN_HEREDOC_END, YP_TOKEN_EOF)) { + if ((part = parse_string_part(parser)) != NULL) { + yp_node_list_append(&parts, part); + } + } + + // Now that we have all of the parts, create the correct type of + // interpolated node. + if (quote == YP_HEREDOC_QUOTE_BACKTICK) { + yp_interpolated_x_string_node_t *cast = yp_interpolated_xstring_node_create(parser, &opening, &opening); + cast->parts = parts; + + lex_state_set(parser, YP_LEX_STATE_END); + expect1(parser, YP_TOKEN_HEREDOC_END, YP_ERR_HEREDOC_TERM); + + yp_interpolated_xstring_node_closing_set(cast, &parser->previous); + cast->base.location = cast->opening_loc; + node = (yp_node_t *) cast; + } else { + yp_interpolated_string_node_t *cast = yp_interpolated_string_node_create(parser, &opening, &parts, &opening); + + lex_state_set(parser, YP_LEX_STATE_END); + expect1(parser, YP_TOKEN_HEREDOC_END, YP_ERR_HEREDOC_TERM); - // If this is a heredoc that is indented with a ~, then we need to dedent - // each line by the common leading whitespace. - if (indent == YP_HEREDOC_INDENT_TILDE) { - parse_heredoc_dedent(parser, node, quote); + yp_interpolated_string_node_closing_set(cast, &parser->previous); + cast->base.location = cast->opening_loc; + node = (yp_node_t *) cast; + } + + // If this is a heredoc that is indented with a ~, then we need + // to dedent each line by the common leading whitespace. + if (indent == YP_HEREDOC_INDENT_TILDE) { + parse_heredoc_dedent(parser, node, quote); + } } - // If there's a string immediately following this heredoc, then it's a - // concatenatation. In this case we'll parse the next string and create a - // node in the tree that concatenates the two strings. - if (parser->current.type == YP_TOKEN_STRING_BEGIN) { - return (yp_node_t *) yp_string_concat_node_create( - parser, - node, - parse_expression(parser, YP_BINDING_POWER_CALL, "Expected string on the right side of concatenation.") - ); - } else { - return node; + if (match1(parser, YP_TOKEN_STRING_BEGIN)) { + yp_node_t *concat = parse_strings(parser); + return (yp_node_t *) yp_string_concat_node_create(parser, node, concat); } + + return node; } case YP_TOKEN_INSTANCE_VARIABLE: { parser_lex(parser); yp_node_t *node = (yp_node_t *) yp_instance_variable_read_node_create(parser, &parser->previous); - if (binding_power == YP_BINDING_POWER_STATEMENT && match_type_p(parser, YP_TOKEN_COMMA)) { - node = parse_targets(parser, node, YP_BINDING_POWER_INDEX); + if (binding_power == YP_BINDING_POWER_STATEMENT && match1(parser, YP_TOKEN_COMMA)) { + node = parse_targets_validate(parser, node, YP_BINDING_POWER_INDEX); } return node; } - case YP_TOKEN_INTEGER: + case YP_TOKEN_INTEGER: { + yp_node_flags_t base = parser->integer_base; parser_lex(parser); - return (yp_node_t *) yp_integer_node_create(parser, &parser->previous); - case YP_TOKEN_INTEGER_IMAGINARY: + return (yp_node_t *) yp_integer_node_create(parser, base, &parser->previous); + } + case YP_TOKEN_INTEGER_IMAGINARY: { + yp_node_flags_t base = parser->integer_base; parser_lex(parser); - return (yp_node_t *) yp_integer_node_imaginary_create(parser, &parser->previous); - case YP_TOKEN_INTEGER_RATIONAL: + return (yp_node_t *) yp_integer_node_imaginary_create(parser, base, &parser->previous); + } + case YP_TOKEN_INTEGER_RATIONAL: { + yp_node_flags_t base = parser->integer_base; parser_lex(parser); - return (yp_node_t *) yp_integer_node_rational_create(parser, &parser->previous); - case YP_TOKEN_INTEGER_RATIONAL_IMAGINARY: + return (yp_node_t *) yp_integer_node_rational_create(parser, base, &parser->previous); + } + case YP_TOKEN_INTEGER_RATIONAL_IMAGINARY: { + yp_node_flags_t base = parser->integer_base; parser_lex(parser); - return (yp_node_t *) yp_integer_node_rational_imaginary_create(parser, &parser->previous); + return (yp_node_t *) yp_integer_node_rational_imaginary_create(parser, base, &parser->previous); + } case YP_TOKEN_KEYWORD___ENCODING__: parser_lex(parser); return (yp_node_t *) yp_source_encoding_node_create(parser, &parser->previous); @@ -11204,48 +11923,49 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_node_t *old_name = parse_alias_argument(parser, false); switch (YP_NODE_TYPE(new_name)) { - case YP_NODE_SYMBOL_NODE: - case YP_NODE_INTERPOLATED_SYMBOL_NODE: { - if (!YP_NODE_TYPE_P(old_name, YP_NODE_SYMBOL_NODE) && !YP_NODE_TYPE_P(old_name, YP_NODE_INTERPOLATED_SYMBOL_NODE)) { - yp_diagnostic_list_append(&parser->error_list, old_name->location.start, old_name->location.end, "Expected a bare word or symbol argument."); - } - break; - } - case YP_NODE_BACK_REFERENCE_READ_NODE: - case YP_NODE_NUMBERED_REFERENCE_READ_NODE: - case YP_NODE_GLOBAL_VARIABLE_READ_NODE: { - if (YP_NODE_TYPE_P(old_name, YP_NODE_BACK_REFERENCE_READ_NODE) || YP_NODE_TYPE_P(old_name, YP_NODE_NUMBERED_REFERENCE_READ_NODE) || YP_NODE_TYPE_P(old_name, YP_NODE_GLOBAL_VARIABLE_READ_NODE)) { - if (YP_NODE_TYPE_P(old_name, YP_NODE_NUMBERED_REFERENCE_READ_NODE)) { - yp_diagnostic_list_append(&parser->error_list, old_name->location.start, old_name->location.end, "Can't make alias for number variables."); + case YP_BACK_REFERENCE_READ_NODE: + case YP_NUMBERED_REFERENCE_READ_NODE: + case YP_GLOBAL_VARIABLE_READ_NODE: { + if (YP_NODE_TYPE_P(old_name, YP_BACK_REFERENCE_READ_NODE) || YP_NODE_TYPE_P(old_name, YP_NUMBERED_REFERENCE_READ_NODE) || YP_NODE_TYPE_P(old_name, YP_GLOBAL_VARIABLE_READ_NODE)) { + if (YP_NODE_TYPE_P(old_name, YP_NUMBERED_REFERENCE_READ_NODE)) { + yp_diagnostic_list_append(&parser->error_list, old_name->location.start, old_name->location.end, YP_ERR_ALIAS_ARGUMENT); } } else { - yp_diagnostic_list_append(&parser->error_list, old_name->location.start, old_name->location.end, "Expected a global variable."); + yp_diagnostic_list_append(&parser->error_list, old_name->location.start, old_name->location.end, YP_ERR_ALIAS_ARGUMENT); + } + + return (yp_node_t *) yp_alias_global_variable_node_create(parser, &keyword, new_name, old_name); + } + case YP_SYMBOL_NODE: + case YP_INTERPOLATED_SYMBOL_NODE: { + if (!YP_NODE_TYPE_P(old_name, YP_SYMBOL_NODE) && !YP_NODE_TYPE_P(old_name, YP_INTERPOLATED_SYMBOL_NODE)) { + yp_diagnostic_list_append(&parser->error_list, old_name->location.start, old_name->location.end, YP_ERR_ALIAS_ARGUMENT); } - break; } + /* fallthrough */ default: - break; + return (yp_node_t *) yp_alias_method_node_create(parser, &keyword, new_name, old_name); } - - return (yp_node_t *) yp_alias_node_create(parser, &keyword, new_name, old_name); } case YP_TOKEN_KEYWORD_CASE: { parser_lex(parser); yp_token_t case_keyword = parser->previous; yp_node_t *predicate = NULL; - if ( - accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON) || - match_any_type_p(parser, 3, YP_TOKEN_KEYWORD_WHEN, YP_TOKEN_KEYWORD_IN, YP_TOKEN_KEYWORD_END) || - !token_begins_expression_p(parser->current.type) - ) { + if (accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)) { + while (accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)); + predicate = NULL; + } else if (match3(parser, YP_TOKEN_KEYWORD_WHEN, YP_TOKEN_KEYWORD_IN, YP_TOKEN_KEYWORD_END)) { + predicate = NULL; + } else if (!token_begins_expression_p(parser->current.type)) { predicate = NULL; } else { - predicate = parse_expression(parser, YP_BINDING_POWER_COMPOSITION, "Expected a value after case keyword."); - while (accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)); + predicate = parse_expression(parser, YP_BINDING_POWER_COMPOSITION, YP_ERR_CASE_EXPRESSION_AFTER_CASE); + while (accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)); } - if (accept(parser, YP_TOKEN_KEYWORD_END)) { + if (accept1(parser, YP_TOKEN_KEYWORD_END)) { + yp_diagnostic_list_append(&parser->error_list, case_keyword.start, case_keyword.end, YP_ERR_CASE_MISSING_CONDITIONS); return (yp_node_t *) yp_case_node_create(parser, &case_keyword, predicate, NULL, &parser->previous); } @@ -11254,38 +11974,38 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_token_t end_keyword = not_provided(parser); yp_case_node_t *case_node = yp_case_node_create(parser, &case_keyword, predicate, NULL, &end_keyword); - if (match_type_p(parser, YP_TOKEN_KEYWORD_WHEN)) { + if (match1(parser, YP_TOKEN_KEYWORD_WHEN)) { // At this point we've seen a when keyword, so we know this is a // case-when node. We will continue to parse the when nodes until we hit // the end of the list. - while (accept(parser, YP_TOKEN_KEYWORD_WHEN)) { + while (accept1(parser, YP_TOKEN_KEYWORD_WHEN)) { yp_token_t when_keyword = parser->previous; yp_when_node_t *when_node = yp_when_node_create(parser, &when_keyword); do { - if (accept(parser, YP_TOKEN_USTAR)) { + if (accept1(parser, YP_TOKEN_USTAR)) { yp_token_t operator = parser->previous; - yp_node_t *expression = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected a value after `*' operator."); + yp_node_t *expression = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_EXPECT_EXPRESSION_AFTER_STAR); yp_splat_node_t *splat_node = yp_splat_node_create(parser, &operator, expression); yp_when_node_conditions_append(when_node, (yp_node_t *) splat_node); - if (YP_NODE_TYPE_P(expression, YP_NODE_MISSING_NODE)) break; + if (YP_NODE_TYPE_P(expression, YP_MISSING_NODE)) break; } else { - yp_node_t *condition = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected a value after when keyword."); + yp_node_t *condition = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_CASE_EXPRESSION_AFTER_WHEN); yp_when_node_conditions_append(when_node, condition); - if (YP_NODE_TYPE_P(condition, YP_NODE_MISSING_NODE)) break; + if (YP_NODE_TYPE_P(condition, YP_MISSING_NODE)) break; } - } while (accept(parser, YP_TOKEN_COMMA)); + } while (accept1(parser, YP_TOKEN_COMMA)); - if (accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)) { - accept(parser, YP_TOKEN_KEYWORD_THEN); + if (accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)) { + accept1(parser, YP_TOKEN_KEYWORD_THEN); } else { - expect(parser, YP_TOKEN_KEYWORD_THEN, "Expected a delimiter after the predicates of a `when' clause."); + expect1(parser, YP_TOKEN_KEYWORD_THEN, YP_ERR_EXPECT_WHEN_DELIMITER); } - if (!match_any_type_p(parser, 3, YP_TOKEN_KEYWORD_WHEN, YP_TOKEN_KEYWORD_ELSE, YP_TOKEN_KEYWORD_END)) { + if (!match3(parser, YP_TOKEN_KEYWORD_WHEN, YP_TOKEN_KEYWORD_ELSE, YP_TOKEN_KEYWORD_END)) { yp_statements_node_t *statements = parse_statements(parser, YP_CONTEXT_CASE_WHEN); if (statements != NULL) { yp_when_node_statements_set(when_node, statements); @@ -11297,7 +12017,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { } else { // At this point we expect that we're parsing a case-in node. We will // continue to parse the in nodes until we hit the end of the list. - while (match_type_p(parser, YP_TOKEN_KEYWORD_IN)) { + while (match1(parser, YP_TOKEN_KEYWORD_IN)) { bool previous_pattern_matching_newlines = parser->pattern_matching_newlines; parser->pattern_matching_newlines = true; @@ -11306,18 +12026,18 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser_lex(parser); yp_token_t in_keyword = parser->previous; - yp_node_t *pattern = parse_pattern(parser, true, "Expected a pattern after `in' keyword."); + yp_node_t *pattern = parse_pattern(parser, true, YP_ERR_PATTERN_EXPRESSION_AFTER_IN); parser->pattern_matching_newlines = previous_pattern_matching_newlines; // Since we're in the top-level of the case-in node we need to check // for guard clauses in the form of `if` or `unless` statements. - if (accept(parser, YP_TOKEN_KEYWORD_IF_MODIFIER)) { + if (accept1(parser, YP_TOKEN_KEYWORD_IF_MODIFIER)) { yp_token_t keyword = parser->previous; - yp_node_t *predicate = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected a value after guard keyword."); + yp_node_t *predicate = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_CONDITIONAL_IF_PREDICATE); pattern = (yp_node_t *) yp_if_node_modifier_create(parser, pattern, &keyword, predicate); - } else if (accept(parser, YP_TOKEN_KEYWORD_UNLESS_MODIFIER)) { + } else if (accept1(parser, YP_TOKEN_KEYWORD_UNLESS_MODIFIER)) { yp_token_t keyword = parser->previous; - yp_node_t *predicate = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected a value after guard keyword."); + yp_node_t *predicate = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_CONDITIONAL_UNLESS_PREDICATE); pattern = (yp_node_t *) yp_unless_node_modifier_create(parser, pattern, &keyword, predicate); } @@ -11325,21 +12045,21 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { // It can be a newline or semicolon optionally followed by a `then` // keyword. yp_token_t then_keyword; - if (accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)) { - if (accept(parser, YP_TOKEN_KEYWORD_THEN)) { + if (accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)) { + if (accept1(parser, YP_TOKEN_KEYWORD_THEN)) { then_keyword = parser->previous; } else { then_keyword = not_provided(parser); } } else { - expect(parser, YP_TOKEN_KEYWORD_THEN, "Expected a delimiter after the predicates of an `in' clause."); + expect1(parser, YP_TOKEN_KEYWORD_THEN, YP_ERR_EXPECT_WHEN_DELIMITER); then_keyword = parser->previous; } // Now we can actually parse the statements associated with the in // node. yp_statements_node_t *statements; - if (match_any_type_p(parser, 3, YP_TOKEN_KEYWORD_IN, YP_TOKEN_KEYWORD_ELSE, YP_TOKEN_KEYWORD_END)) { + if (match3(parser, YP_TOKEN_KEYWORD_IN, YP_TOKEN_KEYWORD_ELSE, YP_TOKEN_KEYWORD_END)) { statements = NULL; } else { statements = parse_statements(parser, YP_CONTEXT_CASE_IN); @@ -11352,16 +12072,18 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { } } - accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); - if (accept(parser, YP_TOKEN_KEYWORD_ELSE)) { - if (case_node->conditions.size < 1) { - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Unexpected else without no when clauses in case statement."); - } + // If we didn't parse any conditions (in or when) then we need to + // indicate that we have an error. + if (case_node->conditions.size == 0) { + yp_diagnostic_list_append(&parser->error_list, case_keyword.start, case_keyword.end, YP_ERR_CASE_MISSING_CONDITIONS); + } + accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); + if (accept1(parser, YP_TOKEN_KEYWORD_ELSE)) { yp_token_t else_keyword = parser->previous; yp_else_node_t *else_node; - if (!match_type_p(parser, YP_TOKEN_KEYWORD_END)) { + if (!match1(parser, YP_TOKEN_KEYWORD_END)) { else_node = yp_else_node_create(parser, &else_keyword, parse_statements(parser, YP_CONTEXT_ELSE), &parser->current); } else { else_node = yp_else_node_create(parser, &else_keyword, NULL, &parser->current); @@ -11370,7 +12092,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_case_node_consequent_set(case_node, else_node); } - expect(parser, YP_TOKEN_KEYWORD_END, "Expected case statement to end with an end keyword."); + expect1(parser, YP_TOKEN_KEYWORD_END, YP_ERR_CASE_TERM); yp_case_node_end_keyword_loc_set(case_node, &parser->previous); return (yp_node_t *) case_node; } @@ -11378,20 +12100,20 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser_lex(parser); yp_token_t begin_keyword = parser->previous; - accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); + accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); yp_statements_node_t *begin_statements = NULL; - if (!match_any_type_p(parser, 3, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE, YP_TOKEN_KEYWORD_END)) { + if (!match3(parser, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE, YP_TOKEN_KEYWORD_END)) { yp_accepts_block_stack_push(parser, true); begin_statements = parse_statements(parser, YP_CONTEXT_BEGIN); yp_accepts_block_stack_pop(parser); - accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); + accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); } yp_begin_node_t *begin_node = yp_begin_node_create(parser, &begin_keyword, begin_statements); parse_rescues(parser, begin_node); - expect(parser, YP_TOKEN_KEYWORD_END, "Expected `end` to close `begin` statement."); + expect1(parser, YP_TOKEN_KEYWORD_END, YP_ERR_BEGIN_TERM); begin_node->base.location.end = parser->previous.end; yp_begin_node_end_keyword_set(begin_node, &parser->previous); @@ -11400,7 +12122,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { &parser->error_list, begin_node->else_clause->base.location.start, begin_node->else_clause->base.location.end, - "else without rescue is useless" + YP_ERR_BEGIN_LONELY_ELSE ); } @@ -11410,11 +12132,11 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser_lex(parser); yp_token_t keyword = parser->previous; - expect(parser, YP_TOKEN_BRACE_LEFT, "Expected '{' after 'BEGIN'."); + expect1(parser, YP_TOKEN_BRACE_LEFT, YP_ERR_BEGIN_UPCASE_BRACE); yp_token_t opening = parser->previous; yp_statements_node_t *statements = parse_statements(parser, YP_CONTEXT_PREEXE); - expect(parser, YP_TOKEN_BRACE_RIGHT, "Expected '}' after 'BEGIN' statements."); + expect1(parser, YP_TOKEN_BRACE_RIGHT, YP_ERR_BEGIN_UPCASE_TERM); return (yp_node_t *) yp_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->previous); } case YP_TOKEN_KEYWORD_BREAK: @@ -11427,12 +12149,11 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { if ( token_begins_expression_p(parser->current.type) || - match_any_type_p(parser, 2, YP_TOKEN_USTAR, YP_TOKEN_USTAR_STAR) + match2(parser, YP_TOKEN_USTAR, YP_TOKEN_USTAR_STAR) ) { yp_binding_power_t binding_power = yp_binding_powers[parser->current.type].left; if (binding_power == YP_BINDING_POWER_UNSET || binding_power >= YP_BINDING_POWER_RANGE) { - arguments.arguments = yp_arguments_node_create(parser); parse_arguments(parser, &arguments, false, YP_TOKEN_EOF); } } @@ -11447,7 +12168,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { (parser->current_context->context == YP_CONTEXT_CLASS) || (parser->current_context->context == YP_CONTEXT_MODULE) ) { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Invalid return in class/module body"); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_RETURN_INVALID); } return (yp_node_t *) yp_return_node_create(parser, &keyword, arguments.arguments); } @@ -11483,26 +12204,26 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_token_t class_keyword = parser->previous; yp_do_loop_stack_push(parser, false); - if (accept(parser, YP_TOKEN_LESS_LESS)) { + if (accept1(parser, YP_TOKEN_LESS_LESS)) { yp_token_t operator = parser->previous; - yp_node_t *expression = parse_expression(parser, YP_BINDING_POWER_NOT, "Expected to find an expression after `<<`."); + yp_node_t *expression = parse_expression(parser, YP_BINDING_POWER_NOT, YP_ERR_EXPECT_EXPRESSION_AFTER_LESS_LESS); yp_parser_scope_push(parser, true); - accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); + accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); yp_node_t *statements = NULL; - if (!match_any_type_p(parser, 3, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE, YP_TOKEN_KEYWORD_END)) { + if (!match3(parser, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE, YP_TOKEN_KEYWORD_END)) { yp_accepts_block_stack_push(parser, true); statements = (yp_node_t *) parse_statements(parser, YP_CONTEXT_SCLASS); yp_accepts_block_stack_pop(parser); } - if (match_any_type_p(parser, 2, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE)) { - assert(statements == NULL || YP_NODE_TYPE_P(statements, YP_NODE_STATEMENTS_NODE)); + if (match2(parser, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE)) { + assert(statements == NULL || YP_NODE_TYPE_P(statements, YP_STATEMENTS_NODE)); statements = (yp_node_t *) parse_rescues_as_begin(parser, (yp_statements_node_t *) statements); } - expect(parser, YP_TOKEN_KEYWORD_END, "Expected `end` to close `class` statement."); + expect1(parser, YP_TOKEN_KEYWORD_END, YP_ERR_CLASS_TERM); yp_constant_id_list_t locals = parser->current_scope->locals; yp_parser_scope_pop(parser); @@ -11510,47 +12231,47 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { return (yp_node_t *) yp_singleton_class_node_create(parser, &locals, &class_keyword, &operator, expression, statements, &parser->previous); } - yp_node_t *constant_path = parse_expression(parser, YP_BINDING_POWER_INDEX, "Expected to find a class name after `class`."); + yp_node_t *constant_path = parse_expression(parser, YP_BINDING_POWER_INDEX, YP_ERR_CLASS_NAME); yp_token_t name = parser->previous; if (name.type != YP_TOKEN_CONSTANT) { - yp_diagnostic_list_append(&parser->error_list, name.start, name.end, "Expected a constant name after `class`."); + yp_diagnostic_list_append(&parser->error_list, name.start, name.end, YP_ERR_CLASS_NAME); } yp_token_t inheritance_operator; yp_node_t *superclass; - if (match_type_p(parser, YP_TOKEN_LESS)) { + if (match1(parser, YP_TOKEN_LESS)) { inheritance_operator = parser->current; lex_state_set(parser, YP_LEX_STATE_BEG); parser->command_start = true; parser_lex(parser); - superclass = parse_expression(parser, YP_BINDING_POWER_COMPOSITION, "Expected to find a superclass after `<`."); + superclass = parse_expression(parser, YP_BINDING_POWER_COMPOSITION, YP_ERR_CLASS_SUPERCLASS); } else { inheritance_operator = not_provided(parser); superclass = NULL; } yp_parser_scope_push(parser, true); - accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); + accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); yp_node_t *statements = NULL; - if (!match_any_type_p(parser, 3, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE, YP_TOKEN_KEYWORD_END)) { + if (!match3(parser, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE, YP_TOKEN_KEYWORD_END)) { yp_accepts_block_stack_push(parser, true); statements = (yp_node_t *) parse_statements(parser, YP_CONTEXT_CLASS); yp_accepts_block_stack_pop(parser); } - if (match_any_type_p(parser, 2, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE)) { - assert(statements == NULL || YP_NODE_TYPE_P(statements, YP_NODE_STATEMENTS_NODE)); + if (match2(parser, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE)) { + assert(statements == NULL || YP_NODE_TYPE_P(statements, YP_STATEMENTS_NODE)); statements = (yp_node_t *) parse_rescues_as_begin(parser, (yp_statements_node_t *) statements); } - expect(parser, YP_TOKEN_KEYWORD_END, "Expected `end` to close `class` statement."); + expect1(parser, YP_TOKEN_KEYWORD_END, YP_ERR_CLASS_TERM); if (context_def_p(parser)) { - yp_diagnostic_list_append(&parser->error_list, class_keyword.start, class_keyword.end, "Class definition in method body"); + yp_diagnostic_list_append(&parser->error_list, class_keyword.start, class_keyword.end, YP_ERR_CLASS_IN_METHOD); } yp_constant_id_list_t locals = parser->current_scope->locals; @@ -11563,7 +12284,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_node_t *receiver = NULL; yp_token_t operator = not_provided(parser); - yp_token_t name = not_provided(parser); + yp_token_t name = (yp_token_t) { .type = YP_TOKEN_MISSING, .start = def_keyword.end, .end = def_keyword.end }; context_push(parser, YP_CONTEXT_DEF_PARAMS); parser_lex(parser); @@ -11576,22 +12297,19 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { name = parser->previous; break; case YP_TOKEN_IDENTIFIER: { - yp_parser_scope_push(parser, true); parser_lex(parser); - if (match_any_type_p(parser, 2, YP_TOKEN_DOT, YP_TOKEN_COLON_COLON)) { + if (match2(parser, YP_TOKEN_DOT, YP_TOKEN_COLON_COLON)) { receiver = parse_variable_call(parser); + yp_parser_scope_push(parser, true); lex_state_set(parser, YP_LEX_STATE_FNAME); parser_lex(parser); operator = parser->previous; name = parse_method_definition_name(parser); - - if (name.type == YP_TOKEN_MISSING) { - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Expected a method name after receiver."); - } } else { + yp_parser_scope_push(parser, true); name = parser->previous; } @@ -11612,7 +12330,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser_lex(parser); yp_token_t identifier = parser->previous; - if (match_any_type_p(parser, 2, YP_TOKEN_DOT, YP_TOKEN_COLON_COLON)) { + if (match2(parser, YP_TOKEN_DOT, YP_TOKEN_COLON_COLON)) { lex_state_set(parser, YP_LEX_STATE_FNAME); parser_lex(parser); operator = parser->previous; @@ -11656,9 +12374,6 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { } name = parse_method_definition_name(parser); - if (name.type == YP_TOKEN_MISSING) { - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Expected a method name after receiver."); - } } else { name = identifier; } @@ -11667,13 +12382,13 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { case YP_TOKEN_PARENTHESIS_LEFT: { parser_lex(parser); yp_token_t lparen = parser->previous; - yp_node_t *expression = parse_expression(parser, YP_BINDING_POWER_STATEMENT, "Expected to be able to parse receiver."); + yp_node_t *expression = parse_expression(parser, YP_BINDING_POWER_STATEMENT, YP_ERR_DEF_RECEIVER); - expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected closing ')' for receiver."); + expect1(parser, YP_TOKEN_PARENTHESIS_RIGHT, YP_ERR_EXPECT_RPAREN); yp_token_t rparen = parser->previous; lex_state_set(parser, YP_LEX_STATE_FNAME); - expect_any(parser, "Expected '.' or '::' after receiver", 2, YP_TOKEN_DOT, YP_TOKEN_COLON_COLON); + expect2(parser, YP_TOKEN_DOT, YP_TOKEN_COLON_COLON, YP_ERR_DEF_RECEIVER_TERM); operator = parser->previous; receiver = (yp_node_t *) yp_parentheses_node_create(parser, &lparen, expression, &rparen); @@ -11685,13 +12400,15 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { default: yp_parser_scope_push(parser, true); name = parse_method_definition_name(parser); - - if (name.type == YP_TOKEN_MISSING) { - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Expected a method name after receiver."); - } break; } + // If, after all that, we were unable to find a method name, add an + // error to the error list. + if (name.type == YP_TOKEN_MISSING) { + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_DEF_NAME); + } + yp_token_t lparen; yp_token_t rparen; yp_parameters_node_t *params; @@ -11701,7 +12418,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser_lex(parser); lparen = parser->previous; - if (match_type_p(parser, YP_TOKEN_PARENTHESIS_RIGHT)) { + if (match1(parser, YP_TOKEN_PARENTHESIS_RIGHT)) { params = NULL; } else { params = parse_parameters(parser, YP_BINDING_POWER_DEFINED, true, false, true); @@ -11710,7 +12427,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { lex_state_set(parser, YP_LEX_STATE_BEG); parser->command_start = true; - expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected ')' after left parenthesis."); + expect1(parser, YP_TOKEN_PARENTHESIS_RIGHT, YP_ERR_DEF_PARAMS_TERM_PAREN); rparen = parser->previous; break; } @@ -11739,20 +12456,20 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_token_t equal; yp_token_t end_keyword; - if (accept(parser, YP_TOKEN_EQUAL)) { + if (accept1(parser, YP_TOKEN_EQUAL)) { if (token_is_setter_name(&name)) { - yp_diagnostic_list_append(&parser->error_list, name.start, name.end, "Setter method cannot be defined in an endless method definition"); + yp_diagnostic_list_append(&parser->error_list, name.start, name.end, YP_ERR_DEF_ENDLESS_SETTER); } equal = parser->previous; context_push(parser, YP_CONTEXT_DEF); statements = (yp_node_t *) yp_statements_node_create(parser); - yp_node_t *statement = parse_expression(parser, YP_BINDING_POWER_DEFINED + 1, "Expected to be able to parse body of endless method definition."); + yp_node_t *statement = parse_expression(parser, YP_BINDING_POWER_DEFINED + 1, YP_ERR_DEF_ENDLESS); - if (accept(parser, YP_TOKEN_KEYWORD_RESCUE_MODIFIER)) { + if (accept1(parser, YP_TOKEN_KEYWORD_RESCUE_MODIFIER)) { yp_token_t rescue_keyword = parser->previous; - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the rescue keyword."); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_RESCUE_MODIFIER_VALUE); yp_rescue_modifier_node_t *rescue_node = yp_rescue_modifier_node_create(parser, statement, &rescue_keyword, value); statement = (yp_node_t *)rescue_node; } @@ -11766,28 +12483,28 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { if (lparen.type == YP_TOKEN_NOT_PROVIDED) { lex_state_set(parser, YP_LEX_STATE_BEG); parser->command_start = true; - expect_any(parser, "Expected a terminator after the parameters", 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); + expect2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON, YP_ERR_DEF_PARAMS_TERM); } else { - accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); + accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); } yp_accepts_block_stack_push(parser, true); yp_do_loop_stack_push(parser, false); - if (!match_any_type_p(parser, 3, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE, YP_TOKEN_KEYWORD_END)) { + if (!match3(parser, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE, YP_TOKEN_KEYWORD_END)) { yp_accepts_block_stack_push(parser, true); statements = (yp_node_t *) parse_statements(parser, YP_CONTEXT_DEF); yp_accepts_block_stack_pop(parser); } - if (match_any_type_p(parser, 2, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE)) { - assert(statements == NULL || YP_NODE_TYPE_P(statements, YP_NODE_STATEMENTS_NODE)); + if (match2(parser, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE)) { + assert(statements == NULL || YP_NODE_TYPE_P(statements, YP_STATEMENTS_NODE)); statements = (yp_node_t *) parse_rescues_as_begin(parser, (yp_statements_node_t *) statements); } yp_accepts_block_stack_pop(parser); yp_do_loop_stack_pop(parser); - expect(parser, YP_TOKEN_KEYWORD_END, "Expected `end` to close `def` statement."); + expect1(parser, YP_TOKEN_KEYWORD_END, YP_ERR_DEF_TERM); end_keyword = parser->previous; } @@ -11817,20 +12534,20 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_token_t rparen; yp_node_t *expression; - if (accept(parser, YP_TOKEN_PARENTHESIS_LEFT)) { + if (accept1(parser, YP_TOKEN_PARENTHESIS_LEFT)) { lparen = parser->previous; - expression = parse_expression(parser, YP_BINDING_POWER_COMPOSITION, "Expected expression after `defined?`."); + expression = parse_expression(parser, YP_BINDING_POWER_COMPOSITION, YP_ERR_DEFINED_EXPRESSION); if (parser->recovering) { rparen = not_provided(parser); } else { - expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected ')' after 'defined?' expression."); + expect1(parser, YP_TOKEN_PARENTHESIS_RIGHT, YP_ERR_EXPECT_RPAREN); rparen = parser->previous; } } else { lparen = not_provided(parser); rparen = not_provided(parser); - expression = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected expression after `defined?`."); + expression = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_DEFINED_EXPRESSION); } return (yp_node_t *) yp_defined_node_create( @@ -11838,18 +12555,18 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { &lparen, expression, &rparen, - &(yp_location_t) { .start = keyword.start, .end = keyword.end } + &YP_LOCATION_TOKEN_VALUE(&keyword) ); } case YP_TOKEN_KEYWORD_END_UPCASE: { parser_lex(parser); yp_token_t keyword = parser->previous; - expect(parser, YP_TOKEN_BRACE_LEFT, "Expected '{' after 'END'."); + expect1(parser, YP_TOKEN_BRACE_LEFT, YP_ERR_END_UPCASE_BRACE); yp_token_t opening = parser->previous; yp_statements_node_t *statements = parse_statements(parser, YP_CONTEXT_POSTEXE); - expect(parser, YP_TOKEN_BRACE_RIGHT, "Expected '}' after 'END' statements."); + expect1(parser, YP_TOKEN_BRACE_RIGHT, YP_ERR_END_UPCASE_TERM); return (yp_node_t *) yp_post_execution_node_create(parser, &keyword, &opening, statements, &parser->previous); } case YP_TOKEN_KEYWORD_FALSE: @@ -11858,29 +12575,53 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { case YP_TOKEN_KEYWORD_FOR: { parser_lex(parser); yp_token_t for_keyword = parser->previous; + yp_node_t *index; + + // First, parse out the first index expression. + if (accept1(parser, YP_TOKEN_USTAR)) { + yp_token_t star_operator = parser->previous; + yp_node_t *name = NULL; + + if (token_begins_expression_p(parser->current.type)) { + name = parse_expression(parser, YP_BINDING_POWER_INDEX, YP_ERR_EXPECT_EXPRESSION_AFTER_STAR); + } + + index = (yp_node_t *) yp_splat_node_create(parser, &star_operator, name); + } else if (token_begins_expression_p(parser->current.type)) { + index = parse_expression(parser, YP_BINDING_POWER_INDEX, YP_ERR_EXPECT_EXPRESSION_AFTER_COMMA); + } else { + yp_diagnostic_list_append(&parser->error_list, for_keyword.start, for_keyword.end, YP_ERR_FOR_INDEX); + index = (yp_node_t *) yp_missing_node_create(parser, for_keyword.start, for_keyword.end); + } + + // Now, if there are multiple index expressions, parse them out. + if (match1(parser, YP_TOKEN_COMMA)) { + index = parse_targets(parser, index, YP_BINDING_POWER_INDEX); + } else { + index = parse_target(parser, index); + } - yp_node_t *index = parse_targets(parser, NULL, YP_BINDING_POWER_INDEX); yp_do_loop_stack_push(parser, true); - expect(parser, YP_TOKEN_KEYWORD_IN, "Expected keyword in."); + expect1(parser, YP_TOKEN_KEYWORD_IN, YP_ERR_FOR_IN); yp_token_t in_keyword = parser->previous; - yp_node_t *collection = parse_expression(parser, YP_BINDING_POWER_COMPOSITION, "Expected collection."); + yp_node_t *collection = parse_expression(parser, YP_BINDING_POWER_COMPOSITION, YP_ERR_FOR_COLLECTION); yp_do_loop_stack_pop(parser); yp_token_t do_keyword; - if (accept(parser, YP_TOKEN_KEYWORD_DO_LOOP)) { + if (accept1(parser, YP_TOKEN_KEYWORD_DO_LOOP)) { do_keyword = parser->previous; } else { do_keyword = not_provided(parser); } - accept_any(parser, 2, YP_TOKEN_SEMICOLON, YP_TOKEN_NEWLINE); + accept2(parser, YP_TOKEN_SEMICOLON, YP_TOKEN_NEWLINE); yp_statements_node_t *statements = NULL; - if (!accept(parser, YP_TOKEN_KEYWORD_END)) { + if (!accept1(parser, YP_TOKEN_KEYWORD_END)) { statements = parse_statements(parser, YP_CONTEXT_FOR); - expect(parser, YP_TOKEN_KEYWORD_END, "Expected `end` to close for loop."); + expect1(parser, YP_TOKEN_KEYWORD_END, YP_ERR_FOR_TERM); } return (yp_node_t *) yp_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, &do_keyword, &parser->previous); @@ -11893,17 +12634,17 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_undef_node_t *undef = yp_undef_node_create(parser, &parser->previous); yp_node_t *name = parse_undef_argument(parser); - if (YP_NODE_TYPE_P(name, YP_NODE_MISSING_NODE)) { + if (YP_NODE_TYPE_P(name, YP_MISSING_NODE)) { yp_node_destroy(parser, name); } else { yp_undef_node_append(undef, name); - while (match_type_p(parser, YP_TOKEN_COMMA)) { + while (match1(parser, YP_TOKEN_COMMA)) { lex_state_set(parser, YP_LEX_STATE_FNAME | YP_LEX_STATE_FITEM); parser_lex(parser); name = parse_undef_argument(parser); - if (YP_NODE_TYPE_P(name, YP_NODE_MISSING_NODE)) { + if (YP_NODE_TYPE_P(name, YP_MISSING_NODE)) { yp_node_destroy(parser, name); break; } @@ -11921,26 +12662,26 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_arguments_t arguments = YP_EMPTY_ARGUMENTS; yp_node_t *receiver = NULL; - accept(parser, YP_TOKEN_NEWLINE); + accept1(parser, YP_TOKEN_NEWLINE); - if (accept(parser, YP_TOKEN_PARENTHESIS_LEFT)) { - arguments.opening_loc = ((yp_location_t) { .start = parser->previous.start, .end = parser->previous.end }); + if (accept1(parser, YP_TOKEN_PARENTHESIS_LEFT)) { + arguments.opening_loc = YP_LOCATION_TOKEN_VALUE(&parser->previous); - if (accept(parser, YP_TOKEN_PARENTHESIS_RIGHT)) { - arguments.closing_loc = ((yp_location_t) { .start = parser->previous.start, .end = parser->previous.end }); + if (accept1(parser, YP_TOKEN_PARENTHESIS_RIGHT)) { + arguments.closing_loc = YP_LOCATION_TOKEN_VALUE(&parser->previous); } else { - receiver = parse_expression(parser, YP_BINDING_POWER_COMPOSITION, "Expected expression after `not`."); - yp_flip_flop(receiver); + receiver = parse_expression(parser, YP_BINDING_POWER_COMPOSITION, YP_ERR_NOT_EXPRESSION); + yp_conditional_predicate(receiver); if (!parser->recovering) { - accept(parser, YP_TOKEN_NEWLINE); - expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected ')' after 'not' expression."); - arguments.closing_loc = ((yp_location_t) { .start = parser->previous.start, .end = parser->previous.end }); + accept1(parser, YP_TOKEN_NEWLINE); + expect1(parser, YP_TOKEN_PARENTHESIS_RIGHT, YP_ERR_EXPECT_RPAREN); + arguments.closing_loc = YP_LOCATION_TOKEN_VALUE(&parser->previous); } } } else { - receiver = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected expression after `not`."); - yp_flip_flop(receiver); + receiver = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_NOT_EXPRESSION); + yp_conditional_predicate(receiver); } return (yp_node_t *) yp_call_node_not_create(parser, receiver, &message, &arguments); @@ -11952,20 +12693,20 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser_lex(parser); yp_token_t module_keyword = parser->previous; - yp_node_t *constant_path = parse_expression(parser, YP_BINDING_POWER_INDEX, "Expected to find a module name after `module`."); + yp_node_t *constant_path = parse_expression(parser, YP_BINDING_POWER_INDEX, YP_ERR_MODULE_NAME); yp_token_t name; // If we can recover from a syntax error that occurred while parsing // the name of the module, then we'll handle that here. - if (YP_NODE_TYPE_P(constant_path, YP_NODE_MISSING_NODE)) { + if (YP_NODE_TYPE_P(constant_path, YP_MISSING_NODE)) { yp_token_t missing = (yp_token_t) { .type = YP_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end }; return (yp_node_t *) yp_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing); } - while (accept(parser, YP_TOKEN_COLON_COLON)) { + while (accept1(parser, YP_TOKEN_COLON_COLON)) { yp_token_t double_colon = parser->previous; - expect(parser, YP_TOKEN_CONSTANT, "Expected to find a module name after `::`."); + expect1(parser, YP_TOKEN_CONSTANT, YP_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT); yp_node_t *constant = (yp_node_t *) yp_constant_read_node_create(parser, &parser->previous); constant_path = (yp_node_t *) yp_constant_path_node_create(parser, constant_path, &double_colon, constant); @@ -11976,31 +12717,31 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { // syntax error. We handle that here as well. name = parser->previous; if (name.type != YP_TOKEN_CONSTANT) { - yp_diagnostic_list_append(&parser->error_list, name.start, name.end, "Expected to find a module name after `module`."); + yp_diagnostic_list_append(&parser->error_list, name.start, name.end, YP_ERR_MODULE_NAME); } yp_parser_scope_push(parser, true); - accept_any(parser, 2, YP_TOKEN_SEMICOLON, YP_TOKEN_NEWLINE); + accept2(parser, YP_TOKEN_SEMICOLON, YP_TOKEN_NEWLINE); yp_node_t *statements = NULL; - if (!match_any_type_p(parser, 3, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE, YP_TOKEN_KEYWORD_END)) { + if (!match3(parser, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE, YP_TOKEN_KEYWORD_END)) { yp_accepts_block_stack_push(parser, true); statements = (yp_node_t *) parse_statements(parser, YP_CONTEXT_MODULE); yp_accepts_block_stack_pop(parser); } - if (match_any_type_p(parser, 2, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE)) { - assert(statements == NULL || YP_NODE_TYPE_P(statements, YP_NODE_STATEMENTS_NODE)); + if (match2(parser, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE)) { + assert(statements == NULL || YP_NODE_TYPE_P(statements, YP_STATEMENTS_NODE)); statements = (yp_node_t *) parse_rescues_as_begin(parser, (yp_statements_node_t *) statements); } yp_constant_id_list_t locals = parser->current_scope->locals; yp_parser_scope_pop(parser); - expect(parser, YP_TOKEN_KEYWORD_END, "Expected `end` to close `module` statement."); + expect1(parser, YP_TOKEN_KEYWORD_END, YP_ERR_MODULE_TERM); if (context_def_p(parser)) { - yp_diagnostic_list_append(&parser->error_list, module_keyword.start, module_keyword.end, "Module definition in method body"); + yp_diagnostic_list_append(&parser->error_list, module_keyword.start, module_keyword.end, YP_ERR_MODULE_IN_METHOD); } return (yp_node_t *) yp_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->previous); @@ -12025,18 +12766,18 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser_lex(parser); yp_token_t keyword = parser->previous; - yp_node_t *predicate = parse_expression(parser, YP_BINDING_POWER_COMPOSITION, "Expected predicate expression after `until`."); + yp_node_t *predicate = parse_expression(parser, YP_BINDING_POWER_COMPOSITION, YP_ERR_CONDITIONAL_UNTIL_PREDICATE); yp_do_loop_stack_pop(parser); - accept_any(parser, 3, YP_TOKEN_KEYWORD_DO_LOOP, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); + accept3(parser, YP_TOKEN_KEYWORD_DO_LOOP, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); yp_statements_node_t *statements = NULL; - if (!accept(parser, YP_TOKEN_KEYWORD_END)) { + if (!accept1(parser, YP_TOKEN_KEYWORD_END)) { yp_accepts_block_stack_push(parser, true); statements = parse_statements(parser, YP_CONTEXT_UNTIL); yp_accepts_block_stack_pop(parser); - accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); - expect(parser, YP_TOKEN_KEYWORD_END, "Expected `end` to close `until` statement."); + accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); + expect1(parser, YP_TOKEN_KEYWORD_END, YP_ERR_UNTIL_TERM); } return (yp_node_t *) yp_until_node_create(parser, &keyword, &parser->previous, predicate, statements, 0); @@ -12046,18 +12787,18 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser_lex(parser); yp_token_t keyword = parser->previous; - yp_node_t *predicate = parse_expression(parser, YP_BINDING_POWER_COMPOSITION, "Expected predicate expression after `while`."); + yp_node_t *predicate = parse_expression(parser, YP_BINDING_POWER_COMPOSITION, YP_ERR_CONDITIONAL_WHILE_PREDICATE); yp_do_loop_stack_pop(parser); - accept_any(parser, 3, YP_TOKEN_KEYWORD_DO_LOOP, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); + accept3(parser, YP_TOKEN_KEYWORD_DO_LOOP, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); yp_statements_node_t *statements = NULL; - if (!accept(parser, YP_TOKEN_KEYWORD_END)) { + if (!accept1(parser, YP_TOKEN_KEYWORD_END)) { yp_accepts_block_stack_push(parser, true); statements = parse_statements(parser, YP_CONTEXT_WHILE); yp_accepts_block_stack_pop(parser); - accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); - expect(parser, YP_TOKEN_KEYWORD_END, "Expected `end` to close `while` statement."); + accept2(parser, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON); + expect1(parser, YP_TOKEN_KEYWORD_END, YP_ERR_WHILE_TERM); } return (yp_node_t *) yp_while_node_create(parser, &keyword, &parser->previous, predicate, statements, 0); @@ -12066,11 +12807,11 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser_lex(parser); yp_array_node_t *array = yp_array_node_create(parser, &parser->previous); - while (!match_any_type_p(parser, 2, YP_TOKEN_STRING_END, YP_TOKEN_EOF)) { - accept(parser, YP_TOKEN_WORDS_SEP); - if (match_type_p(parser, YP_TOKEN_STRING_END)) break; + while (!match2(parser, YP_TOKEN_STRING_END, YP_TOKEN_EOF)) { + accept1(parser, YP_TOKEN_WORDS_SEP); + if (match1(parser, YP_TOKEN_STRING_END)) break; - expect(parser, YP_TOKEN_STRING_CONTENT, "Expected a symbol in a `%i` list."); + expect1(parser, YP_TOKEN_STRING_CONTENT, YP_ERR_LIST_I_LOWER_ELEMENT); yp_token_t opening = not_provided(parser); yp_token_t closing = not_provided(parser); @@ -12079,7 +12820,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_array_node_elements_append(array, symbol); } - expect(parser, YP_TOKEN_STRING_END, "Expected a closing delimiter for a `%i` list."); + expect1(parser, YP_TOKEN_STRING_END, YP_ERR_LIST_I_LOWER_TERM); yp_array_node_close_set(array, &parser->previous); return (yp_node_t *) array; @@ -12092,7 +12833,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { // list of elements. yp_node_t *current = NULL; - while (!match_any_type_p(parser, 2, YP_TOKEN_STRING_END, YP_TOKEN_EOF)) { + while (!match2(parser, YP_TOKEN_STRING_END, YP_TOKEN_EOF)) { switch (parser->current.type) { case YP_TOKEN_WORDS_SEP: { if (current == NULL) { @@ -12118,13 +12859,13 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { // to create a new string node and set that to the current. parser_lex(parser); current = (yp_node_t *) yp_symbol_node_create_and_unescape(parser, &opening, &parser->previous, &closing, YP_UNESCAPE_ALL); - } else if (YP_NODE_TYPE_P(current, YP_NODE_INTERPOLATED_SYMBOL_NODE)) { + } else if (YP_NODE_TYPE_P(current, YP_INTERPOLATED_SYMBOL_NODE)) { // If we hit string content and the current node is an // interpolated string, then we need to append the string content // to the list of child nodes. yp_node_t *part = parse_string_part(parser); yp_interpolated_symbol_node_append((yp_interpolated_symbol_node_t *) current, part); - } else if (YP_NODE_TYPE_P(current, YP_NODE_SYMBOL_NODE)) { + } else if (YP_NODE_TYPE_P(current, YP_SYMBOL_NODE)) { // If we hit string content and the current node is a string node, // then we need to convert the current node into an interpolated // string and add the string content to the list of child nodes. @@ -12152,7 +12893,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_token_t opening = not_provided(parser); yp_token_t closing = not_provided(parser); current = (yp_node_t *) yp_interpolated_symbol_node_create(parser, &opening, NULL, &closing); - } else if (YP_NODE_TYPE_P(current, YP_NODE_SYMBOL_NODE)) { + } else if (YP_NODE_TYPE_P(current, YP_SYMBOL_NODE)) { // If we hit an embedded variable and the current node is a string // node, then we'll convert the current into an interpolated // string and add the string node to the list of parts. @@ -12186,7 +12927,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_token_t opening = not_provided(parser); yp_token_t closing = not_provided(parser); current = (yp_node_t *) yp_interpolated_symbol_node_create(parser, &opening, NULL, &closing); - } else if (YP_NODE_TYPE_P(current, YP_NODE_SYMBOL_NODE)) { + } else if (YP_NODE_TYPE_P(current, YP_SYMBOL_NODE)) { // If we hit an embedded expression and the current node is a // string node, then we'll convert the current into an // interpolated string and add the string node to the list of @@ -12200,7 +12941,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { interpolated->base.location.start = current->location.start; start_location_set = true; current = (yp_node_t *) interpolated; - } else if (YP_NODE_TYPE_P(current, YP_NODE_INTERPOLATED_SYMBOL_NODE)) { + } else if (YP_NODE_TYPE_P(current, YP_INTERPOLATED_SYMBOL_NODE)) { // If we hit an embedded expression and the current node is an // interpolated string, then we'll just continue on. } else { @@ -12215,7 +12956,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { break; } default: - expect(parser, YP_TOKEN_STRING_CONTENT, "Expected a symbol in a `%I` list."); + expect1(parser, YP_TOKEN_STRING_CONTENT, YP_ERR_LIST_I_UPPER_ELEMENT); parser_lex(parser); break; } @@ -12226,7 +12967,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_array_node_elements_append(array, current); } - expect(parser, YP_TOKEN_STRING_END, "Expected a closing delimiter for a `%I` list."); + expect1(parser, YP_TOKEN_STRING_END, YP_ERR_LIST_I_UPPER_TERM); yp_array_node_close_set(array, &parser->previous); return (yp_node_t *) array; @@ -12236,21 +12977,21 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_array_node_t *array = yp_array_node_create(parser, &parser->previous); // skip all leading whitespaces - accept(parser, YP_TOKEN_WORDS_SEP); + accept1(parser, YP_TOKEN_WORDS_SEP); - while (!match_any_type_p(parser, 2, YP_TOKEN_STRING_END, YP_TOKEN_EOF)) { - accept(parser, YP_TOKEN_WORDS_SEP); - if (match_type_p(parser, YP_TOKEN_STRING_END)) break; + while (!match2(parser, YP_TOKEN_STRING_END, YP_TOKEN_EOF)) { + accept1(parser, YP_TOKEN_WORDS_SEP); + if (match1(parser, YP_TOKEN_STRING_END)) break; - expect(parser, YP_TOKEN_STRING_CONTENT, "Expected a string in a `%w` list."); + expect1(parser, YP_TOKEN_STRING_CONTENT, YP_ERR_LIST_W_LOWER_ELEMENT); yp_token_t opening = not_provided(parser); yp_token_t closing = not_provided(parser); - yp_node_t *string = (yp_node_t *) yp_string_node_create_and_unescape(parser, &opening, &parser->previous, &closing, YP_UNESCAPE_MINIMAL); + yp_node_t *string = (yp_node_t *) yp_string_node_create_and_unescape(parser, &opening, &parser->previous, &closing, YP_UNESCAPE_WHITESPACE); yp_array_node_elements_append(array, string); } - expect(parser, YP_TOKEN_STRING_END, "Expected a closing delimiter for a `%w` list."); + expect1(parser, YP_TOKEN_STRING_END, YP_ERR_LIST_W_LOWER_TERM); yp_array_node_close_set(array, &parser->previous); return (yp_node_t *) array; @@ -12263,7 +13004,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { // list of elements. yp_node_t *current = NULL; - while (!match_any_type_p(parser, 2, YP_TOKEN_STRING_END, YP_TOKEN_EOF)) { + while (!match2(parser, YP_TOKEN_STRING_END, YP_TOKEN_EOF)) { switch (parser->current.type) { case YP_TOKEN_WORDS_SEP: { if (current == NULL) { @@ -12285,13 +13026,13 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { // the first string content we've seen. In that case we're going // to create a new string node and set that to the current. current = parse_string_part(parser); - } else if (YP_NODE_TYPE_P(current, YP_NODE_INTERPOLATED_STRING_NODE)) { + } else if (YP_NODE_TYPE_P(current, YP_INTERPOLATED_STRING_NODE)) { // If we hit string content and the current node is an // interpolated string, then we need to append the string content // to the list of child nodes. yp_node_t *part = parse_string_part(parser); yp_interpolated_string_node_append((yp_interpolated_string_node_t *) current, part); - } else if (YP_NODE_TYPE_P(current, YP_NODE_STRING_NODE)) { + } else if (YP_NODE_TYPE_P(current, YP_STRING_NODE)) { // If we hit string content and the current node is a string node, // then we need to convert the current node into an interpolated // string and add the string content to the list of child nodes. @@ -12318,7 +13059,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_token_t opening = not_provided(parser); yp_token_t closing = not_provided(parser); current = (yp_node_t *) yp_interpolated_string_node_create(parser, &opening, NULL, &closing); - } else if (YP_NODE_TYPE_P(current, YP_NODE_STRING_NODE)) { + } else if (YP_NODE_TYPE_P(current, YP_STRING_NODE)) { // If we hit an embedded variable and the current node is a string // node, then we'll convert the current into an interpolated // string and add the string node to the list of parts. @@ -12344,7 +13085,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_token_t opening = not_provided(parser); yp_token_t closing = not_provided(parser); current = (yp_node_t *) yp_interpolated_string_node_create(parser, &opening, NULL, &closing); - } else if (YP_NODE_TYPE_P(current, YP_NODE_STRING_NODE)) { + } else if (YP_NODE_TYPE_P(current, YP_STRING_NODE)) { // If we hit an embedded expression and the current node is a // string node, then we'll convert the current into an // interpolated string and add the string node to the list of @@ -12354,7 +13095,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_interpolated_string_node_t *interpolated = yp_interpolated_string_node_create(parser, &opening, NULL, &closing); yp_interpolated_string_node_append(interpolated, current); current = (yp_node_t *) interpolated; - } else if (YP_NODE_TYPE_P(current, YP_NODE_INTERPOLATED_STRING_NODE)) { + } else if (YP_NODE_TYPE_P(current, YP_INTERPOLATED_STRING_NODE)) { // If we hit an embedded expression and the current node is an // interpolated string, then we'll just continue on. } else { @@ -12366,7 +13107,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { break; } default: - expect(parser, YP_TOKEN_STRING_CONTENT, "Expected a string in a `%W` list."); + expect1(parser, YP_TOKEN_STRING_CONTENT, YP_ERR_LIST_W_UPPER_ELEMENT); parser_lex(parser); break; } @@ -12377,7 +13118,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_array_node_elements_append(array, current); } - expect(parser, YP_TOKEN_STRING_END, "Expected a closing delimiter for a `%W` list."); + expect1(parser, YP_TOKEN_STRING_END, YP_ERR_LIST_W_UPPER_TERM); yp_array_node_close_set(array, &parser->previous); return (yp_node_t *) array; @@ -12386,7 +13127,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_token_t opening = parser->current; parser_lex(parser); - if (match_type_p(parser, YP_TOKEN_REGEXP_END)) { + if (match1(parser, YP_TOKEN_REGEXP_END)) { // If we get here, then we have an end immediately after a start. In // that case we'll create an empty content token and return an // uninterpolated regular expression. @@ -12402,7 +13143,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_interpolated_regular_expression_node_t *node; - if (match_type_p(parser, YP_TOKEN_STRING_CONTENT)) { + if (match1(parser, YP_TOKEN_STRING_CONTENT)) { // In this case we've hit string content so we know the regular // expression at least has something in it. We'll need to check if the // following token is the end (in which case we can return a plain @@ -12413,7 +13154,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { // If we hit an end, then we can create a regular expression node // without interpolation, which can be represented more succinctly and // more easily compiled. - if (accept(parser, YP_TOKEN_REGEXP_END)) { + if (accept1(parser, YP_TOKEN_REGEXP_END)) { return (yp_node_t *) yp_regular_expression_node_create_and_unescape(parser, &opening, &content, &parser->previous, YP_UNESCAPE_ALL); } @@ -12434,14 +13175,14 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { // Now that we're here and we have interpolation, we'll parse all of the // parts into the list. - while (!match_any_type_p(parser, 2, YP_TOKEN_REGEXP_END, YP_TOKEN_EOF)) { + while (!match2(parser, YP_TOKEN_REGEXP_END, YP_TOKEN_EOF)) { yp_node_t *part = parse_string_part(parser); if (part != NULL) { yp_interpolated_regular_expression_node_append(node, part); } } - expect(parser, YP_TOKEN_REGEXP_END, "Expected a closing delimiter for a regular expression."); + expect1(parser, YP_TOKEN_REGEXP_END, YP_ERR_REGEXP_TERM); yp_interpolated_regular_expression_node_closing_set(node, &parser->previous); return (yp_node_t *) node; @@ -12455,7 +13196,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { // interpolation or not, even though it is allowed. Still, we want to be // able to return a string node without interpolation if we can since // it'll be faster. - if (match_type_p(parser, YP_TOKEN_STRING_END)) { + if (match1(parser, YP_TOKEN_STRING_END)) { // If we get here, then we have an end immediately after a start. In // that case we'll create an empty content token and return an // uninterpolated string. @@ -12471,7 +13212,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_interpolated_x_string_node_t *node; - if (match_type_p(parser, YP_TOKEN_STRING_CONTENT)) { + if (match1(parser, YP_TOKEN_STRING_CONTENT)) { // In this case we've hit string content so we know the string at least // has something in it. We'll need to check if the following token is // the end (in which case we can return a plain string) or if it's not @@ -12479,7 +13220,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_token_t content = parser->current; parser_lex(parser); - if (accept(parser, YP_TOKEN_STRING_END)) { + if (accept1(parser, YP_TOKEN_STRING_END)) { return (yp_node_t *) yp_xstring_node_create_and_unescape(parser, &opening, &content, &parser->previous); } @@ -12498,14 +13239,14 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { node = yp_interpolated_xstring_node_create(parser, &opening, &opening); } - while (!match_any_type_p(parser, 2, YP_TOKEN_STRING_END, YP_TOKEN_EOF)) { + while (!match2(parser, YP_TOKEN_STRING_END, YP_TOKEN_EOF)) { yp_node_t *part = parse_string_part(parser); if (part != NULL) { yp_interpolated_xstring_node_append(node, part); } } - expect(parser, YP_TOKEN_STRING_END, "Expected a closing delimiter for an xstring."); + expect1(parser, YP_TOKEN_STRING_END, YP_ERR_XSTRING_TERM); yp_interpolated_xstring_node_closing_set(node, &parser->previous); return (yp_node_t *) node; } @@ -12513,8 +13254,8 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser_lex(parser); // * operators at the beginning of expressions are only valid in the - // context of a multiple assignment. We enforce that here. We'll still lex - // past it though and create a missing node place. + // context of a multiple assignment. We enforce that here. We'll + // still lex past it though and create a missing node place. if (binding_power != YP_BINDING_POWER_STATEMENT) { return (yp_node_t *) yp_missing_node_create(parser, parser->previous.start, parser->previous.end); } @@ -12523,27 +13264,32 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_node_t *name = NULL; if (token_begins_expression_p(parser->current.type)) { - name = parse_expression(parser, YP_BINDING_POWER_INDEX, "Expected an expression after '*'."); + name = parse_expression(parser, YP_BINDING_POWER_INDEX, YP_ERR_EXPECT_EXPRESSION_AFTER_STAR); } yp_node_t *splat = (yp_node_t *) yp_splat_node_create(parser, &operator, name); - return parse_targets(parser, splat, YP_BINDING_POWER_INDEX); + + if (match1(parser, YP_TOKEN_COMMA)) { + return parse_targets_validate(parser, splat, YP_BINDING_POWER_INDEX); + } else { + return parse_target_validate(parser, splat); + } } case YP_TOKEN_BANG: { parser_lex(parser); yp_token_t operator = parser->previous; - yp_node_t *receiver = parse_expression(parser, yp_binding_powers[parser->previous.type].right, "Expected a receiver after unary !."); + yp_node_t *receiver = parse_expression(parser, yp_binding_powers[parser->previous.type].right, YP_ERR_UNARY_RECEIVER_BANG); yp_call_node_t *node = yp_call_node_unary_create(parser, &operator, receiver, "!"); - yp_flip_flop(receiver); + yp_conditional_predicate(receiver); return (yp_node_t *) node; } case YP_TOKEN_TILDE: { parser_lex(parser); yp_token_t operator = parser->previous; - yp_node_t *receiver = parse_expression(parser, yp_binding_powers[parser->previous.type].right, "Expected a receiver after unary ~."); + yp_node_t *receiver = parse_expression(parser, yp_binding_powers[parser->previous.type].right, YP_ERR_UNARY_RECEIVER_TILDE); yp_call_node_t *node = yp_call_node_unary_create(parser, &operator, receiver, "~"); return (yp_node_t *) node; @@ -12552,7 +13298,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser_lex(parser); yp_token_t operator = parser->previous; - yp_node_t *receiver = parse_expression(parser, yp_binding_powers[parser->previous.type].right, "Expected a receiver after unary -."); + yp_node_t *receiver = parse_expression(parser, yp_binding_powers[parser->previous.type].right, YP_ERR_UNARY_RECEIVER_MINUS); yp_call_node_t *node = yp_call_node_unary_create(parser, &operator, receiver, "-@"); return (yp_node_t *) node; @@ -12561,18 +13307,25 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser_lex(parser); yp_token_t operator = parser->previous; - yp_node_t *node = parse_expression(parser, yp_binding_powers[parser->previous.type].right, "Expected a receiver after unary -."); + yp_node_t *node = parse_expression(parser, yp_binding_powers[parser->previous.type].right, YP_ERR_UNARY_RECEIVER_MINUS); - switch (YP_NODE_TYPE(node)) { - case YP_NODE_INTEGER_NODE: - case YP_NODE_FLOAT_NODE: - case YP_NODE_RATIONAL_NODE: - case YP_NODE_IMAGINARY_NODE: - parse_negative_numeric(node); - break; - default: - node = (yp_node_t *) yp_call_node_unary_create(parser, &operator, node, "-@"); - break; + if (accept1(parser, YP_TOKEN_STAR_STAR)) { + yp_token_t exponent_operator = parser->previous; + yp_node_t *exponent = parse_expression(parser, yp_binding_powers[exponent_operator.type].right, YP_ERR_EXPECT_ARGUMENT); + node = (yp_node_t *) yp_call_node_binary_create(parser, node, &exponent_operator, exponent); + node = (yp_node_t *) yp_call_node_unary_create(parser, &operator, node, "-@"); + } else { + switch (YP_NODE_TYPE(node)) { + case YP_INTEGER_NODE: + case YP_FLOAT_NODE: + case YP_RATIONAL_NODE: + case YP_IMAGINARY_NODE: + parse_negative_numeric(node); + break; + default: + node = (yp_node_t *) yp_call_node_unary_create(parser, &operator, node, "-@"); + break; + } } return node; @@ -12590,22 +13343,24 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { switch (parser->current.type) { case YP_TOKEN_PARENTHESIS_LEFT: { + parser->current_scope->explicit_params = true; yp_token_t opening = parser->current; parser_lex(parser); - if (match_type_p(parser, YP_TOKEN_PARENTHESIS_RIGHT)) { + if (match1(parser, YP_TOKEN_PARENTHESIS_RIGHT)) { params = yp_block_parameters_node_create(parser, NULL, &opening); } else { params = parse_block_parameters(parser, false, &opening, true); } - accept(parser, YP_TOKEN_NEWLINE); - expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected ')' after left parenthesis."); + accept1(parser, YP_TOKEN_NEWLINE); + expect1(parser, YP_TOKEN_PARENTHESIS_RIGHT, YP_ERR_EXPECT_RPAREN); yp_block_parameters_node_closing_set(params, &parser->previous); break; } case YP_CASE_PARAMETER: { + parser->current_scope->explicit_params = true; yp_accepts_block_stack_push(parser, false); yp_token_t opening = not_provided(parser); params = parse_block_parameters(parser, false, &opening, true); @@ -12622,29 +13377,29 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { yp_node_t *body = NULL; parser->lambda_enclosure_nesting = previous_lambda_enclosure_nesting; - if (accept(parser, YP_TOKEN_LAMBDA_BEGIN)) { + if (accept1(parser, YP_TOKEN_LAMBDA_BEGIN)) { opening = parser->previous; - if (!accept(parser, YP_TOKEN_BRACE_RIGHT)) { + if (!accept1(parser, YP_TOKEN_BRACE_RIGHT)) { body = (yp_node_t *) parse_statements(parser, YP_CONTEXT_LAMBDA_BRACES); - expect(parser, YP_TOKEN_BRACE_RIGHT, "Expecting '}' to close lambda block."); + expect1(parser, YP_TOKEN_BRACE_RIGHT, YP_ERR_LAMBDA_TERM_BRACE); } } else { - expect(parser, YP_TOKEN_KEYWORD_DO, "Expected a 'do' keyword or a '{' to open lambda block."); + expect1(parser, YP_TOKEN_KEYWORD_DO, YP_ERR_LAMBDA_OPEN); opening = parser->previous; - if (!match_any_type_p(parser, 3, YP_TOKEN_KEYWORD_END, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE)) { + if (!match3(parser, YP_TOKEN_KEYWORD_END, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE)) { yp_accepts_block_stack_push(parser, true); body = (yp_node_t *) parse_statements(parser, YP_CONTEXT_LAMBDA_DO_END); yp_accepts_block_stack_pop(parser); } - if (match_any_type_p(parser, 2, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE)) { - assert(body == NULL || YP_NODE_TYPE_P(body, YP_NODE_STATEMENTS_NODE)); + if (match2(parser, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE)) { + assert(body == NULL || YP_NODE_TYPE_P(body, YP_STATEMENTS_NODE)); body = (yp_node_t *) parse_rescues_as_begin(parser, (yp_statements_node_t *) body); } - expect(parser, YP_TOKEN_KEYWORD_END, "Expecting 'end' keyword to close lambda block."); + expect1(parser, YP_TOKEN_KEYWORD_END, YP_ERR_LAMBDA_TERM_END); } yp_constant_id_list_t locals = parser->current_scope->locals; @@ -12656,162 +13411,13 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { parser_lex(parser); yp_token_t operator = parser->previous; - yp_node_t *receiver = parse_expression(parser, yp_binding_powers[parser->previous.type].right, "Expected a receiver after unary +."); + yp_node_t *receiver = parse_expression(parser, yp_binding_powers[parser->previous.type].right, YP_ERR_UNARY_RECEIVER_PLUS); yp_call_node_t *node = yp_call_node_unary_create(parser, &operator, receiver, "+@"); return (yp_node_t *) node; } - case YP_TOKEN_STRING_BEGIN: { - yp_node_t *result = NULL; - - while (match_type_p(parser, YP_TOKEN_STRING_BEGIN)) { - assert(parser->lex_modes.current->mode == YP_LEX_STRING); - bool lex_interpolation = parser->lex_modes.current->as.string.interpolation; - - yp_node_t *node = NULL; - yp_token_t opening = parser->current; - parser_lex(parser); - - if (accept(parser, YP_TOKEN_STRING_END)) { - // If we get here, then we have an end immediately after a - // start. In that case we'll create an empty content token - // and return an uninterpolated string. - yp_token_t content = (yp_token_t) { - .type = YP_TOKEN_STRING_CONTENT, - .start = parser->previous.start, - .end = parser->previous.start - }; - - node = (yp_node_t *) yp_string_node_create_and_unescape(parser, &opening, &content, &parser->previous, YP_UNESCAPE_NONE); - } else if (accept(parser, YP_TOKEN_LABEL_END)) { - // If we get here, then we have an end of a label - // immediately after a start. In that case we'll create an - // empty symbol node. - yp_token_t opening = not_provided(parser); - yp_token_t content = (yp_token_t) { - .type = YP_TOKEN_STRING_CONTENT, - .start = parser->previous.start, - .end = parser->previous.start - }; - - node = (yp_node_t *) yp_symbol_node_create(parser, &opening, &content, &parser->previous); - } else if (!lex_interpolation) { - // If we don't accept interpolation then we expect the - // string to start with a single string content node. - expect(parser, YP_TOKEN_STRING_CONTENT, "Expected string content after opening delimiter."); - yp_token_t content = parser->previous; - - // It is unfortunately possible to have multiple string - // content nodes in a row in the case that there's heredoc - // content in the middle of the string, like this cursed - // example: - // - // <<-END+'b - // a - // END - // c'+'d' - // - // In that case we need to switch to an interpolated string - // to be able to contain all of the parts. - if (match_type_p(parser, YP_TOKEN_STRING_CONTENT)) { - yp_node_list_t parts = YP_EMPTY_NODE_LIST; - - yp_token_t delimiters = not_provided(parser); - yp_node_t *part = (yp_node_t *) yp_string_node_create_and_unescape(parser, &delimiters, &content, &delimiters, YP_UNESCAPE_MINIMAL); - yp_node_list_append(&parts, part); - - while (accept(parser, YP_TOKEN_STRING_CONTENT)) { - part = (yp_node_t *) yp_string_node_create_and_unescape(parser, &delimiters, &parser->previous, &delimiters, YP_UNESCAPE_MINIMAL); - yp_node_list_append(&parts, part); - } - - expect(parser, YP_TOKEN_STRING_END, "Expected a closing delimiter for a string literal."); - node = (yp_node_t *) yp_interpolated_string_node_create(parser, &opening, &parts, &parser->previous); - } else if (accept(parser, YP_TOKEN_LABEL_END)) { - node = (yp_node_t *) yp_symbol_node_create_and_unescape(parser, &opening, &content, &parser->previous, YP_UNESCAPE_ALL); - } else { - expect(parser, YP_TOKEN_STRING_END, "Expected a closing delimiter for a string literal."); - node = (yp_node_t *) yp_string_node_create_and_unescape(parser, &opening, &content, &parser->previous, YP_UNESCAPE_MINIMAL); - } - } else if (match_type_p(parser, YP_TOKEN_STRING_CONTENT)) { - // In this case we've hit string content so we know the string at - // least has something in it. We'll need to check if the following - // token is the end (in which case we can return a plain string) or if - // it's not then it has interpolation. - yp_token_t content = parser->current; - parser_lex(parser); - - if (accept(parser, YP_TOKEN_STRING_END)) { - node = (yp_node_t *) yp_string_node_create_and_unescape(parser, &opening, &content, &parser->previous, YP_UNESCAPE_ALL); - } else if (accept(parser, YP_TOKEN_LABEL_END)) { - node = (yp_node_t *) yp_symbol_node_create_and_unescape(parser, &opening, &content, &parser->previous, YP_UNESCAPE_ALL); - } else { - // If we get here, then we have interpolation so we'll need to create - // a string or symbol node with interpolation. - yp_node_list_t parts = YP_EMPTY_NODE_LIST; - yp_token_t string_opening = not_provided(parser); - yp_token_t string_closing = not_provided(parser); - yp_node_t *part = (yp_node_t *) yp_string_node_create_and_unescape(parser, &string_opening, &parser->previous, &string_closing, YP_UNESCAPE_ALL); - yp_node_list_append(&parts, part); - - while (!match_any_type_p(parser, 3, YP_TOKEN_STRING_END, YP_TOKEN_LABEL_END, YP_TOKEN_EOF)) { - yp_node_t *part = parse_string_part(parser); - if (part != NULL) yp_node_list_append(&parts, part); - } - - if (accept(parser, YP_TOKEN_LABEL_END)) { - node = (yp_node_t *) yp_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous); - } else { - expect(parser, YP_TOKEN_STRING_END, "Expected a closing delimiter for an interpolated string."); - node = (yp_node_t *) yp_interpolated_string_node_create(parser, &opening, &parts, &parser->previous); - } - } - } else { - // If we get here, then the first part of the string is not plain string - // content, in which case we need to parse the string as an interpolated - // string. - yp_node_list_t parts = YP_EMPTY_NODE_LIST; - - while (!match_any_type_p(parser, 3, YP_TOKEN_STRING_END, YP_TOKEN_LABEL_END, YP_TOKEN_EOF)) { - yp_node_t *part = parse_string_part(parser); - if (part != NULL) yp_node_list_append(&parts, part); - } - - if (accept(parser, YP_TOKEN_LABEL_END)) { - node = (yp_node_t *) yp_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous); - } else { - expect(parser, YP_TOKEN_STRING_END, "Expected a closing delimiter for an interpolated string."); - node = (yp_node_t *) yp_interpolated_string_node_create(parser, &opening, &parts, &parser->previous); - } - } - - if (result == NULL) { - // If the node we just parsed is a symbol node, then we - // can't concatenate it with anything else, so we can now - // return that node. - if (YP_NODE_TYPE_P(node, YP_NODE_SYMBOL_NODE) || YP_NODE_TYPE_P(node, YP_NODE_INTERPOLATED_SYMBOL_NODE)) { - return node; - } - - // If we don't already have a node, then it's fine and we - // can just set the result to be the node we just parsed. - result = node; - } else { - // Otherwise we need to check the type of the node we just - // parsed. If it cannot be concatenated with the previous - // node, then we'll need to add a syntax error. - if (!YP_NODE_TYPE_P(node, YP_NODE_STRING_NODE) && !YP_NODE_TYPE_P(node, YP_NODE_INTERPOLATED_STRING_NODE)) { - yp_diagnostic_list_append(&parser->error_list, node->location.start, node->location.end, "Unexpected string concatenation."); - } - - // Either way we will create a concat node to hold the - // strings together. - result = (yp_node_t *) yp_string_concat_node_create(parser, result, node); - } - } - - return result; - } + case YP_TOKEN_STRING_BEGIN: + return parse_strings(parser); case YP_TOKEN_SYMBOL_BEGIN: { yp_lex_mode_t lex_mode = *parser->lex_modes.current; parser_lex(parser); @@ -12828,26 +13434,40 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) { } static inline yp_node_t * -parse_assignment_value(yp_parser_t *parser, yp_binding_power_t previous_binding_power, yp_binding_power_t binding_power, const char *message) { - yp_node_t *value = parse_starred_expression(parser, binding_power, message); +parse_assignment_value(yp_parser_t *parser, yp_binding_power_t previous_binding_power, yp_binding_power_t binding_power, yp_diagnostic_id_t diag_id) { + yp_node_t *value = parse_starred_expression(parser, binding_power, diag_id); - if (previous_binding_power == YP_BINDING_POWER_STATEMENT && (YP_NODE_TYPE_P(value, YP_NODE_SPLAT_NODE) || match_type_p(parser, YP_TOKEN_COMMA))) { + if (previous_binding_power == YP_BINDING_POWER_STATEMENT && (YP_NODE_TYPE_P(value, YP_SPLAT_NODE) || match1(parser, YP_TOKEN_COMMA))) { yp_token_t opening = not_provided(parser); yp_array_node_t *array = yp_array_node_create(parser, &opening); yp_array_node_elements_append(array, value); value = (yp_node_t *) array; - while (accept(parser, YP_TOKEN_COMMA)) { - yp_node_t *element = parse_starred_expression(parser, binding_power, "Expected an element for the array."); + while (accept1(parser, YP_TOKEN_COMMA)) { + yp_node_t *element = parse_starred_expression(parser, binding_power, YP_ERR_ARRAY_ELEMENT); yp_array_node_elements_append(array, element); - if (YP_NODE_TYPE_P(element, YP_NODE_MISSING_NODE)) break; + if (YP_NODE_TYPE_P(element, YP_MISSING_NODE)) break; } } return value; } +// Ensures a call node that is about to become a call operator node does not +// have a block attached. If it does, then we'll need to add an error message +// and destroy the block. Ideally we would keep the node around so that +// consumers would still have access to it, but we don't have a great structure +// for that at the moment. +static void +parse_call_operator_write_block(yp_parser_t *parser, yp_call_node_t *call_node, const yp_token_t *operator) { + if (call_node->block != NULL) { + yp_diagnostic_list_append(&parser->error_list, operator->start, operator->end, YP_ERR_OPERATOR_WRITE_BLOCK); + yp_node_destroy(parser, (yp_node_t *) call_node->block); + call_node->block = NULL; + } +} + static inline yp_node_t * parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t previous_binding_power, yp_binding_power_t binding_power) { yp_token_t token = parser->current; @@ -12855,7 +13475,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t switch (token.type) { case YP_TOKEN_EQUAL: { switch (YP_NODE_TYPE(node)) { - case YP_NODE_CALL_NODE: { + case YP_CALL_NODE: { // If we have no arguments to the call node and we need this // to be a target then this is either a method call or a // local variable write. This _must_ happen before the value @@ -12868,16 +13488,16 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t /* fallthrough */ case YP_CASE_WRITABLE: { parser_lex(parser); - yp_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, "Expected a value after =."); + yp_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_EQUAL); return parse_write(parser, node, &token, value); } - case YP_NODE_SPLAT_NODE: { + case YP_SPLAT_NODE: { yp_splat_node_t *splat_node = (yp_splat_node_t *) node; switch (YP_NODE_TYPE(splat_node->expression)) { case YP_CASE_WRITABLE: parser_lex(parser); - yp_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, "Expected a value after =."); + yp_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_EQUAL); return parse_write(parser, (yp_node_t *) splat_node, &token, value); default: break; @@ -12890,84 +13510,82 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t // In this case we have an = sign, but we don't know what it's for. We // need to treat it as an error. For now, we'll mark it as an error // and just skip right past it. - yp_diagnostic_list_append(&parser->error_list, token.start, token.end, "Unexpected `='."); + yp_diagnostic_list_append(&parser->error_list, token.start, token.end, YP_ERR_EXPECT_EXPRESSION_AFTER_EQUAL); return node; } } case YP_TOKEN_AMPERSAND_AMPERSAND_EQUAL: { switch (YP_NODE_TYPE(node)) { - case YP_NODE_BACK_REFERENCE_READ_NODE: - case YP_NODE_NUMBERED_REFERENCE_READ_NODE: - yp_diagnostic_list_append(&parser->error_list, node->location.start, node->location.end, "Can't set variable"); + case YP_BACK_REFERENCE_READ_NODE: + case YP_NUMBERED_REFERENCE_READ_NODE: + yp_diagnostic_list_append(&parser->error_list, node->location.start, node->location.end, YP_ERR_WRITE_TARGET_READONLY); /* fallthrough */ - case YP_NODE_GLOBAL_VARIABLE_READ_NODE: { + case YP_GLOBAL_VARIABLE_READ_NODE: { parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&="); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); yp_node_t *result = (yp_node_t *) yp_global_variable_and_write_node_create(parser, node, &token, value); yp_node_destroy(parser, node); return result; } - case YP_NODE_CLASS_VARIABLE_READ_NODE: { + case YP_CLASS_VARIABLE_READ_NODE: { parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&="); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); yp_node_t *result = (yp_node_t *) yp_class_variable_and_write_node_create(parser, (yp_class_variable_read_node_t *) node, &token, value); yp_node_destroy(parser, node); return result; } - case YP_NODE_CONSTANT_PATH_NODE: { + case YP_CONSTANT_PATH_NODE: { parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&="); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); return (yp_node_t *) yp_constant_path_and_write_node_create(parser, (yp_constant_path_node_t *) node, &token, value); } - case YP_NODE_CONSTANT_READ_NODE: { + case YP_CONSTANT_READ_NODE: { parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&="); - yp_node_t *result = (yp_node_t *) yp_constant_and_write_node_create(parser, node, &token, value); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); + yp_node_t *result = (yp_node_t *) yp_constant_and_write_node_create(parser, (yp_constant_read_node_t *) node, &token, value); yp_node_destroy(parser, node); return result; } - case YP_NODE_INSTANCE_VARIABLE_READ_NODE: { + case YP_INSTANCE_VARIABLE_READ_NODE: { parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&="); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); yp_node_t *result = (yp_node_t *) yp_instance_variable_and_write_node_create(parser, (yp_instance_variable_read_node_t *) node, &token, value); yp_node_destroy(parser, node); return result; } - case YP_NODE_LOCAL_VARIABLE_READ_NODE: { + case YP_LOCAL_VARIABLE_READ_NODE: { yp_local_variable_read_node_t *cast = (yp_local_variable_read_node_t *) node; parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&="); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); yp_node_t *result = (yp_node_t *) yp_local_variable_and_write_node_create(parser, node, &token, value, cast->name, cast->depth); yp_node_destroy(parser, node); return result; } - case YP_NODE_CALL_NODE: { - yp_call_node_t *call_node = (yp_call_node_t *) node; - + case YP_CALL_NODE: { // If we have a vcall (a method with no arguments and no // receiver that could have been a local variable) then we // will transform it into a local variable write. - if (yp_call_node_variable_call_p(call_node)) { - yp_location_t message_loc = call_node->message_loc; + if (yp_call_node_variable_call_p((yp_call_node_t *) node)) { + yp_location_t message_loc = ((yp_call_node_t *) node)->message_loc; yp_constant_id_t constant_id = yp_parser_local_add_location(parser, message_loc.start, message_loc.end); if (token_is_numbered_parameter(message_loc.start, message_loc.end)) { - yp_diagnostic_list_append(&parser->error_list, message_loc.start, message_loc.end, "reserved for numbered parameter"); + yp_diagnostic_list_append(&parser->error_list, message_loc.start, message_loc.end, YP_ERR_PARAMETER_NUMBERED_RESERVED); } parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&="); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); yp_node_t *result = (yp_node_t *) yp_local_variable_and_write_node_create(parser, node, &token, value, constant_id, 0); yp_node_destroy(parser, node); @@ -12977,12 +13595,15 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t parser_lex(parser); node = parse_target(parser, node); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&="); - return (yp_node_t *) yp_call_operator_and_write_node_create(parser, (yp_call_node_t *) node, &token, value); + assert(YP_NODE_TYPE_P(node, YP_CALL_NODE)); + parse_call_operator_write_block(parser, (yp_call_node_t *) node, &token); + + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); + return (yp_node_t *) yp_call_and_write_node_create(parser, (yp_call_node_t *) node, &token, value); } - case YP_NODE_MULTI_WRITE_NODE: { + case YP_MULTI_WRITE_NODE: { parser_lex(parser); - yp_diagnostic_list_append(&parser->error_list, token.start, token.end, "Cannot use `&&=' on a multi-write."); + yp_diagnostic_list_append(&parser->error_list, token.start, token.end, YP_ERR_AMPAMPEQ_MULTI_ASSIGN); return node; } default: @@ -12991,84 +13612,82 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t // In this case we have an &&= sign, but we don't know what it's for. // We need to treat it as an error. For now, we'll mark it as an error // and just skip right past it. - yp_diagnostic_list_append(&parser->error_list, token.start, token.end, "Unexpected `&&='."); + yp_diagnostic_list_append(&parser->error_list, token.start, token.end, YP_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); return node; } } case YP_TOKEN_PIPE_PIPE_EQUAL: { switch (YP_NODE_TYPE(node)) { - case YP_NODE_BACK_REFERENCE_READ_NODE: - case YP_NODE_NUMBERED_REFERENCE_READ_NODE: - yp_diagnostic_list_append(&parser->error_list, node->location.start, node->location.end, "Can't set variable"); + case YP_BACK_REFERENCE_READ_NODE: + case YP_NUMBERED_REFERENCE_READ_NODE: + yp_diagnostic_list_append(&parser->error_list, node->location.start, node->location.end, YP_ERR_WRITE_TARGET_READONLY); /* fallthrough */ - case YP_NODE_GLOBAL_VARIABLE_READ_NODE: { + case YP_GLOBAL_VARIABLE_READ_NODE: { parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||="); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); yp_node_t *result = (yp_node_t *) yp_global_variable_or_write_node_create(parser, node, &token, value); yp_node_destroy(parser, node); return result; } - case YP_NODE_CLASS_VARIABLE_READ_NODE: { + case YP_CLASS_VARIABLE_READ_NODE: { parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||="); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); yp_node_t *result = (yp_node_t *) yp_class_variable_or_write_node_create(parser, (yp_class_variable_read_node_t *) node, &token, value); yp_node_destroy(parser, node); return result; } - case YP_NODE_CONSTANT_PATH_NODE: { + case YP_CONSTANT_PATH_NODE: { parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||="); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); return (yp_node_t *) yp_constant_path_or_write_node_create(parser, (yp_constant_path_node_t *) node, &token, value); } - case YP_NODE_CONSTANT_READ_NODE: { + case YP_CONSTANT_READ_NODE: { parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||="); - yp_node_t *result = (yp_node_t *) yp_constant_or_write_node_create(parser, node, &token, value); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); + yp_node_t *result = (yp_node_t *) yp_constant_or_write_node_create(parser, (yp_constant_read_node_t *) node, &token, value); yp_node_destroy(parser, node); return result; } - case YP_NODE_INSTANCE_VARIABLE_READ_NODE: { + case YP_INSTANCE_VARIABLE_READ_NODE: { parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||="); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); yp_node_t *result = (yp_node_t *) yp_instance_variable_or_write_node_create(parser, (yp_instance_variable_read_node_t *) node, &token, value); yp_node_destroy(parser, node); return result; } - case YP_NODE_LOCAL_VARIABLE_READ_NODE: { + case YP_LOCAL_VARIABLE_READ_NODE: { yp_local_variable_read_node_t *cast = (yp_local_variable_read_node_t *) node; parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||="); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); yp_node_t *result = (yp_node_t *) yp_local_variable_or_write_node_create(parser, node, &token, value, cast->name, cast->depth); yp_node_destroy(parser, node); return result; } - case YP_NODE_CALL_NODE: { - yp_call_node_t *call_node = (yp_call_node_t *) node; - + case YP_CALL_NODE: { // If we have a vcall (a method with no arguments and no // receiver that could have been a local variable) then we // will transform it into a local variable write. - if (yp_call_node_variable_call_p(call_node)) { - yp_location_t message_loc = call_node->message_loc; + if (yp_call_node_variable_call_p((yp_call_node_t *) node)) { + yp_location_t message_loc = ((yp_call_node_t *) node)->message_loc; yp_constant_id_t constant_id = yp_parser_local_add_location(parser, message_loc.start, message_loc.end); if (token_is_numbered_parameter(message_loc.start, message_loc.end)) { - yp_diagnostic_list_append(&parser->error_list, message_loc.start, message_loc.end, "reserved for numbered parameter"); + yp_diagnostic_list_append(&parser->error_list, message_loc.start, message_loc.end, YP_ERR_PARAMETER_NUMBERED_RESERVED); } parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||="); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); yp_node_t *result = (yp_node_t *) yp_local_variable_or_write_node_create(parser, node, &token, value, constant_id, 0); yp_node_destroy(parser, node); @@ -13078,12 +13697,15 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t parser_lex(parser); node = parse_target(parser, node); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||="); - return (yp_node_t *) yp_call_operator_or_write_node_create(parser, (yp_call_node_t *) node, &token, value); + assert(YP_NODE_TYPE_P(node, YP_CALL_NODE)); + parse_call_operator_write_block(parser, (yp_call_node_t *) node, &token); + + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); + return (yp_node_t *) yp_call_or_write_node_create(parser, (yp_call_node_t *) node, &token, value); } - case YP_NODE_MULTI_WRITE_NODE: { + case YP_MULTI_WRITE_NODE: { parser_lex(parser); - yp_diagnostic_list_append(&parser->error_list, token.start, token.end, "Cannot use `||=' on a multi-write."); + yp_diagnostic_list_append(&parser->error_list, token.start, token.end, YP_ERR_PIPEPIPEEQ_MULTI_ASSIGN); return node; } default: @@ -13092,7 +13714,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t // In this case we have an ||= sign, but we don't know what it's for. // We need to treat it as an error. For now, we'll mark it as an error // and just skip right past it. - yp_diagnostic_list_append(&parser->error_list, token.start, token.end, "Unexpected `||='."); + yp_diagnostic_list_append(&parser->error_list, token.start, token.end, YP_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); return node; } } @@ -13108,93 +13730,94 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t case YP_TOKEN_STAR_EQUAL: case YP_TOKEN_STAR_STAR_EQUAL: { switch (YP_NODE_TYPE(node)) { - case YP_NODE_BACK_REFERENCE_READ_NODE: - case YP_NODE_NUMBERED_REFERENCE_READ_NODE: - yp_diagnostic_list_append(&parser->error_list, node->location.start, node->location.end, "Can't set variable"); + case YP_BACK_REFERENCE_READ_NODE: + case YP_NUMBERED_REFERENCE_READ_NODE: + yp_diagnostic_list_append(&parser->error_list, node->location.start, node->location.end, YP_ERR_WRITE_TARGET_READONLY); /* fallthrough */ - case YP_NODE_GLOBAL_VARIABLE_READ_NODE: { + case YP_GLOBAL_VARIABLE_READ_NODE: { parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator."); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); yp_node_t *result = (yp_node_t *) yp_global_variable_operator_write_node_create(parser, node, &token, value); yp_node_destroy(parser, node); return result; } - case YP_NODE_CLASS_VARIABLE_READ_NODE: { + case YP_CLASS_VARIABLE_READ_NODE: { parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator."); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); yp_node_t *result = (yp_node_t *) yp_class_variable_operator_write_node_create(parser, (yp_class_variable_read_node_t *) node, &token, value); yp_node_destroy(parser, node); return result; } - case YP_NODE_CONSTANT_PATH_NODE: { + case YP_CONSTANT_PATH_NODE: { parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator."); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); return (yp_node_t *) yp_constant_path_operator_write_node_create(parser, (yp_constant_path_node_t *) node, &token, value); } - case YP_NODE_CONSTANT_READ_NODE: { + case YP_CONSTANT_READ_NODE: { parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator."); - yp_node_t *result = (yp_node_t *) yp_constant_operator_write_node_create(parser, node, &token, value); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + yp_node_t *result = (yp_node_t *) yp_constant_operator_write_node_create(parser, (yp_constant_read_node_t *) node, &token, value); yp_node_destroy(parser, node); return result; } - case YP_NODE_INSTANCE_VARIABLE_READ_NODE: { + case YP_INSTANCE_VARIABLE_READ_NODE: { parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator."); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); yp_node_t *result = (yp_node_t *) yp_instance_variable_operator_write_node_create(parser, (yp_instance_variable_read_node_t *) node, &token, value); yp_node_destroy(parser, node); return result; } - case YP_NODE_LOCAL_VARIABLE_READ_NODE: { + case YP_LOCAL_VARIABLE_READ_NODE: { yp_local_variable_read_node_t *cast = (yp_local_variable_read_node_t *) node; parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator."); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); yp_node_t *result = (yp_node_t *) yp_local_variable_operator_write_node_create(parser, node, &token, value, cast->name, cast->depth); yp_node_destroy(parser, node); return result; } - case YP_NODE_CALL_NODE: { - yp_call_node_t *call_node = (yp_call_node_t *) node; - + case YP_CALL_NODE: { // If we have a vcall (a method with no arguments and no // receiver that could have been a local variable) then we // will transform it into a local variable write. - if (yp_call_node_variable_call_p(call_node)) { - yp_location_t message_loc = call_node->message_loc; + if (yp_call_node_variable_call_p((yp_call_node_t *) node)) { + yp_location_t message_loc = ((yp_call_node_t *) node)->message_loc; yp_constant_id_t constant_id = yp_parser_local_add_location(parser, message_loc.start, message_loc.end); if (token_is_numbered_parameter(message_loc.start, message_loc.end)) { - yp_diagnostic_list_append(&parser->error_list, message_loc.start, message_loc.end, "reserved for numbered parameter"); + yp_diagnostic_list_append(&parser->error_list, message_loc.start, message_loc.end, YP_ERR_PARAMETER_NUMBERED_RESERVED); } parser_lex(parser); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator."); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); yp_node_t *result = (yp_node_t *) yp_local_variable_operator_write_node_create(parser, node, &token, value, constant_id, 0); yp_node_destroy(parser, node); return result; } - node = parse_target(parser, node); parser_lex(parser); + node = parse_target(parser, node); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator."); + assert(YP_NODE_TYPE_P(node, YP_CALL_NODE)); + parse_call_operator_write_block(parser, (yp_call_node_t *) node, &token); + + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); return (yp_node_t *) yp_call_operator_write_node_create(parser, (yp_call_node_t *) node, &token, value); } - case YP_NODE_MULTI_WRITE_NODE: { + case YP_MULTI_WRITE_NODE: { parser_lex(parser); - yp_diagnostic_list_append(&parser->error_list, token.start, token.end, "Unexpected operator."); + yp_diagnostic_list_append(&parser->error_list, token.start, token.end, YP_ERR_OPERATOR_MULTI_ASSIGN); return node; } default: @@ -13203,7 +13826,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t // In this case we have an operator but we don't know what it's for. // We need to treat it as an error. For now, we'll mark it as an error // and just skip right past it. - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Unexpected operator."); + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); return node; } } @@ -13211,47 +13834,57 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t case YP_TOKEN_KEYWORD_AND: { parser_lex(parser); - yp_node_t *right = parse_expression(parser, binding_power, "Expected a value after the operator."); + yp_node_t *right = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); return (yp_node_t *) yp_and_node_create(parser, node, &token, right); } case YP_TOKEN_KEYWORD_OR: case YP_TOKEN_PIPE_PIPE: { parser_lex(parser); - yp_node_t *right = parse_expression(parser, binding_power, "Expected a value after the operator."); + yp_node_t *right = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); return (yp_node_t *) yp_or_node_create(parser, node, &token, right); } case YP_TOKEN_EQUAL_TILDE: { - // Note that we _must_ parse the value before adding the local variables - // in order to properly mirror the behavior of Ruby. For example, + // Note that we _must_ parse the value before adding the local + // variables in order to properly mirror the behavior of Ruby. For + // example, // // /(?bar)/ =~ foo // // In this case, `foo` should be a method call and not a local yet. parser_lex(parser); - yp_node_t *argument = parse_expression(parser, binding_power, "Expected a value after the operator."); + yp_node_t *argument = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + + // By default, we're going to create a call node and then return it. + yp_call_node_t *call = yp_call_node_binary_create(parser, node, &token, argument); + yp_node_t *result = (yp_node_t *) call; - // If the receiver of this =~ is a regular expression node, then we need - // to introduce local variables for it based on its named capture groups. - if (YP_NODE_TYPE_P(node, YP_NODE_REGULAR_EXPRESSION_NODE)) { + // If the receiver of this =~ is a regular expression node, then we + // need to introduce local variables for it based on its named + // capture groups. + if (YP_NODE_TYPE_P(node, YP_REGULAR_EXPRESSION_NODE)) { yp_string_list_t named_captures; yp_string_list_init(&named_captures); const yp_location_t *content_loc = &((yp_regular_expression_node_t *) node)->content_loc; + if (yp_regexp_named_capture_group_names(content_loc->start, (size_t) (content_loc->end - content_loc->start), &named_captures, parser->encoding_changed, &parser->encoding) && (named_captures.length > 0)) { + yp_match_write_node_t *match = yp_match_write_node_create(parser, call); - if (yp_regexp_named_capture_group_names(content_loc->start, (size_t) (content_loc->end - content_loc->start), &named_captures, parser->encoding_changed, &parser->encoding)) { for (size_t index = 0; index < named_captures.length; index++) { yp_string_t *name = &named_captures.strings[index]; assert(name->type == YP_STRING_SHARED); - yp_parser_local_add_location(parser, name->source, name->source + name->length); + yp_constant_id_t local = yp_parser_local_add_location(parser, name->source, name->source + name->length); + yp_constant_id_list_append(&match->locals, local); } + + result = (yp_node_t *) match; } yp_string_list_free(&named_captures); } - return (yp_node_t *) yp_call_node_binary_create(parser, node, &token, argument); + return result; } case YP_TOKEN_UAMPERSAND: case YP_TOKEN_USTAR: @@ -13280,7 +13913,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t case YP_TOKEN_STAR_STAR: { parser_lex(parser); - yp_node_t *argument = parse_expression(parser, binding_power, "Expected a value after the operator."); + yp_node_t *argument = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); return (yp_node_t *) yp_call_node_binary_create(parser, node, &token, argument); } case YP_TOKEN_AMPERSAND_DOT: @@ -13290,7 +13923,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t yp_arguments_t arguments = YP_EMPTY_ARGUMENTS; // This if statement handles the foo.() syntax. - if (match_type_p(parser, YP_TOKEN_PARENTHESIS_LEFT)) { + if (match1(parser, YP_TOKEN_PARENTHESIS_LEFT)) { parse_arguments_list(parser, &arguments, true); return (yp_node_t *) yp_call_node_shorthand_create(parser, node, &operator, &arguments); } @@ -13307,7 +13940,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t break; } default: { - yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Expected a valid method name"); + yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, YP_ERR_DEF_NAME); message = (yp_token_t) { .type = YP_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end }; } } @@ -13319,9 +13952,9 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t (previous_binding_power == YP_BINDING_POWER_STATEMENT) && arguments.arguments == NULL && arguments.opening_loc.start == NULL && - match_type_p(parser, YP_TOKEN_COMMA) + match1(parser, YP_TOKEN_COMMA) ) { - return parse_targets(parser, (yp_node_t *) call, YP_BINDING_POWER_INDEX); + return parse_targets_validate(parser, (yp_node_t *) call, YP_BINDING_POWER_INDEX); } else { return (yp_node_t *) call; } @@ -13332,7 +13965,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t yp_node_t *right = NULL; if (token_begins_expression_p(parser->current.type)) { - right = parse_expression(parser, binding_power, "Expected a value after the operator."); + right = parse_expression(parser, binding_power, YP_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); } return (yp_node_t *) yp_range_node_create(parser, node, &token, right); @@ -13341,14 +13974,14 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t yp_token_t keyword = parser->current; parser_lex(parser); - yp_node_t *predicate = parse_expression(parser, binding_power, "Expected a predicate after `if'."); + yp_node_t *predicate = parse_expression(parser, binding_power, YP_ERR_CONDITIONAL_IF_PREDICATE); return (yp_node_t *) yp_if_node_modifier_create(parser, node, &keyword, predicate); } case YP_TOKEN_KEYWORD_UNLESS_MODIFIER: { yp_token_t keyword = parser->current; parser_lex(parser); - yp_node_t *predicate = parse_expression(parser, binding_power, "Expected a predicate after `unless'."); + yp_node_t *predicate = parse_expression(parser, binding_power, YP_ERR_CONDITIONAL_UNLESS_PREDICATE); return (yp_node_t *) yp_unless_node_modifier_create(parser, node, &keyword, predicate); } case YP_TOKEN_KEYWORD_UNTIL_MODIFIER: { @@ -13356,20 +13989,20 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t yp_statements_node_t *statements = yp_statements_node_create(parser); yp_statements_node_body_append(statements, node); - yp_node_t *predicate = parse_expression(parser, binding_power, "Expected a predicate after 'until'"); - return (yp_node_t *) yp_until_node_modifier_create(parser, &token, predicate, statements, YP_NODE_TYPE_P(node, YP_NODE_BEGIN_NODE) ? YP_LOOP_FLAGS_BEGIN_MODIFIER : 0); + yp_node_t *predicate = parse_expression(parser, binding_power, YP_ERR_CONDITIONAL_UNTIL_PREDICATE); + return (yp_node_t *) yp_until_node_modifier_create(parser, &token, predicate, statements, YP_NODE_TYPE_P(node, YP_BEGIN_NODE) ? YP_LOOP_FLAGS_BEGIN_MODIFIER : 0); } case YP_TOKEN_KEYWORD_WHILE_MODIFIER: { parser_lex(parser); yp_statements_node_t *statements = yp_statements_node_create(parser); yp_statements_node_body_append(statements, node); - yp_node_t *predicate = parse_expression(parser, binding_power, "Expected a predicate after 'while'"); - return (yp_node_t *) yp_while_node_modifier_create(parser, &token, predicate, statements, YP_NODE_TYPE_P(node, YP_NODE_BEGIN_NODE) ? YP_LOOP_FLAGS_BEGIN_MODIFIER : 0); + yp_node_t *predicate = parse_expression(parser, binding_power, YP_ERR_CONDITIONAL_WHILE_PREDICATE); + return (yp_node_t *) yp_while_node_modifier_create(parser, &token, predicate, statements, YP_NODE_TYPE_P(node, YP_BEGIN_NODE) ? YP_LOOP_FLAGS_BEGIN_MODIFIER : 0); } case YP_TOKEN_QUESTION_MARK: { parser_lex(parser); - yp_node_t *true_expression = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected a value after '?'"); + yp_node_t *true_expression = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_TERNARY_EXPRESSION_TRUE); if (parser->recovering) { // If parsing the true expression of this ternary resulted in a syntax @@ -13384,11 +14017,11 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t return (yp_node_t *) yp_if_node_ternary_create(parser, node, true_expression, &colon, false_expression); } - accept(parser, YP_TOKEN_NEWLINE); - expect(parser, YP_TOKEN_COLON, "Expected ':' after true expression in ternary operator."); + accept1(parser, YP_TOKEN_NEWLINE); + expect1(parser, YP_TOKEN_COLON, YP_ERR_TERNARY_COLON); yp_token_t colon = parser->previous; - yp_node_t *false_expression = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected a value after ':'"); + yp_node_t *false_expression = parse_expression(parser, YP_BINDING_POWER_DEFINED, YP_ERR_TERNARY_EXPRESSION_FALSE); return (yp_node_t *) yp_if_node_ternary_create(parser, node, true_expression, &colon, false_expression); } @@ -13403,7 +14036,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t if ( (parser->current.type == YP_TOKEN_PARENTHESIS_LEFT) || - (token_begins_expression_p(parser->current.type) || match_any_type_p(parser, 3, YP_TOKEN_UAMPERSAND, YP_TOKEN_USTAR, YP_TOKEN_USTAR_STAR)) + (token_begins_expression_p(parser->current.type) || match3(parser, YP_TOKEN_UAMPERSAND, YP_TOKEN_USTAR, YP_TOKEN_USTAR_STAR)) ) { // If we have a constant immediately following a '::' operator, then // this can either be a constant path or a method call, depending on @@ -13423,8 +14056,8 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t } // If this is followed by a comma then it is a multiple assignment. - if (previous_binding_power == YP_BINDING_POWER_STATEMENT && match_type_p(parser, YP_TOKEN_COMMA)) { - return parse_targets(parser, path, YP_BINDING_POWER_INDEX); + if (previous_binding_power == YP_BINDING_POWER_STATEMENT && match1(parser, YP_TOKEN_COMMA)) { + return parse_targets_validate(parser, path, YP_BINDING_POWER_INDEX); } return path; @@ -13442,8 +14075,8 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t yp_call_node_t *call = yp_call_node_call_create(parser, node, &delimiter, &message, &arguments); // If this is followed by a comma then it is a multiple assignment. - if (previous_binding_power == YP_BINDING_POWER_STATEMENT && match_type_p(parser, YP_TOKEN_COMMA)) { - return parse_targets(parser, (yp_node_t *) call, YP_BINDING_POWER_INDEX); + if (previous_binding_power == YP_BINDING_POWER_STATEMENT && match1(parser, YP_TOKEN_COMMA)) { + return parse_targets_validate(parser, (yp_node_t *) call, YP_BINDING_POWER_INDEX); } return (yp_node_t *) call; @@ -13457,7 +14090,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t return (yp_node_t *) yp_call_node_shorthand_create(parser, node, &delimiter, &arguments); } default: { - yp_diagnostic_list_append(&parser->error_list, delimiter.start, delimiter.end, "Expected identifier or constant after '::'"); + yp_diagnostic_list_append(&parser->error_list, delimiter.start, delimiter.end, YP_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT); yp_node_t *child = (yp_node_t *) yp_missing_node_create(parser, delimiter.start, delimiter.end); return (yp_node_t *)yp_constant_path_node_create(parser, node, &delimiter, child); } @@ -13465,8 +14098,8 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t } case YP_TOKEN_KEYWORD_RESCUE_MODIFIER: { parser_lex(parser); - accept(parser, YP_TOKEN_NEWLINE); - yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the rescue keyword."); + accept1(parser, YP_TOKEN_NEWLINE); + yp_node_t *value = parse_expression(parser, binding_power, YP_ERR_RESCUE_MODIFIER_VALUE); return (yp_node_t *) yp_rescue_modifier_node_create(parser, node, &token, value); } @@ -13474,37 +14107,44 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t parser_lex(parser); yp_arguments_t arguments = YP_EMPTY_ARGUMENTS; - arguments.opening_loc = ((yp_location_t) { .start = parser->previous.start, .end = parser->previous.end }); + arguments.opening_loc = YP_LOCATION_TOKEN_VALUE(&parser->previous); - if (!accept(parser, YP_TOKEN_BRACKET_RIGHT)) { + if (!accept1(parser, YP_TOKEN_BRACKET_RIGHT)) { yp_accepts_block_stack_push(parser, true); - arguments.arguments = yp_arguments_node_create(parser); - parse_arguments(parser, &arguments, false, YP_TOKEN_BRACKET_RIGHT); yp_accepts_block_stack_pop(parser); - - expect(parser, YP_TOKEN_BRACKET_RIGHT, "Expected ']' to close the bracket expression."); + expect1(parser, YP_TOKEN_BRACKET_RIGHT, YP_ERR_EXPECT_RBRACKET); } - arguments.closing_loc = ((yp_location_t) { .start = parser->previous.start, .end = parser->previous.end }); + arguments.closing_loc = YP_LOCATION_TOKEN_VALUE(&parser->previous); // If we have a comma after the closing bracket then this is a multiple // assignment and we should parse the targets. - if (previous_binding_power == YP_BINDING_POWER_STATEMENT && match_type_p(parser, YP_TOKEN_COMMA)) { + if (previous_binding_power == YP_BINDING_POWER_STATEMENT && match1(parser, YP_TOKEN_COMMA)) { yp_call_node_t *aref = yp_call_node_aref_create(parser, node, &arguments); - return parse_targets(parser, (yp_node_t *) aref, YP_BINDING_POWER_INDEX); + return parse_targets_validate(parser, (yp_node_t *) aref, YP_BINDING_POWER_INDEX); } // If we're at the end of the arguments, we can now check if there is a // block node that starts with a {. If there is, then we can parse it and // add it to the arguments. - if (accept(parser, YP_TOKEN_BRACE_LEFT)) { - arguments.block = parse_block(parser); - } else if (yp_accepts_block_stack_p(parser) && accept(parser, YP_TOKEN_KEYWORD_DO)) { - arguments.block = parse_block(parser); + yp_block_node_t *block = NULL; + if (accept1(parser, YP_TOKEN_BRACE_LEFT)) { + block = parse_block(parser); + yp_arguments_validate_block(parser, &arguments, block); + } else if (yp_accepts_block_stack_p(parser) && accept1(parser, YP_TOKEN_KEYWORD_DO)) { + block = parse_block(parser); + } + + if (block != NULL) { + if (arguments.block != NULL) { + yp_diagnostic_list_append(&parser->error_list, block->base.location.start, block->base.location.end, YP_ERR_ARGUMENT_AFTER_BLOCK); + yp_arguments_node_arguments_append(arguments.arguments, arguments.block); + } + + arguments.block = (yp_node_t *) block; } - yp_arguments_validate(parser, &arguments); return (yp_node_t *) yp_call_node_aref_create(parser, node, &arguments); } case YP_TOKEN_KEYWORD_IN: { @@ -13517,7 +14157,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t parser_lex(parser); - yp_node_t *pattern = parse_pattern(parser, true, "Expected a pattern after `in'."); + yp_node_t *pattern = parse_pattern(parser, true, YP_ERR_PATTERN_EXPRESSION_AFTER_IN); parser->pattern_matching_newlines = previous_pattern_matching_newlines; return (yp_node_t *) yp_match_predicate_node_create(parser, node, pattern, &operator); @@ -13532,7 +14172,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t parser_lex(parser); - yp_node_t *pattern = parse_pattern(parser, true, "Expected a pattern after `=>'."); + yp_node_t *pattern = parse_pattern(parser, true, YP_ERR_PATTERN_EXPRESSION_AFTER_HROCKET); parser->pattern_matching_newlines = previous_pattern_matching_newlines; return (yp_node_t *) yp_match_required_node_create(parser, node, pattern, &operator); @@ -13550,15 +14190,15 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t // Consumers of this function should always check parser->recovering to // determine if they need to perform additional cleanup. static yp_node_t * -parse_expression(yp_parser_t *parser, yp_binding_power_t binding_power, const char *message) { +parse_expression(yp_parser_t *parser, yp_binding_power_t binding_power, yp_diagnostic_id_t diag_id) { yp_token_t recovery = parser->previous; yp_node_t *node = parse_expression_prefix(parser, binding_power); // If we found a syntax error, then the type of node returned by // parse_expression_prefix is going to be a missing node. In that case we need // to add the error message to the parser's error list. - if (YP_NODE_TYPE_P(node, YP_NODE_MISSING_NODE)) { - yp_diagnostic_list_append(&parser->error_list, recovery.end, recovery.end, message); + if (YP_NODE_TYPE_P(node, YP_MISSING_NODE)) { + yp_diagnostic_list_append(&parser->error_list, recovery.end, recovery.end, diag_id); return node; } @@ -13661,7 +14301,10 @@ yp_parser_metadata(yp_parser_t *parser, const char *metadata) { uint32_t local_size = yp_metadata_read_u32(metadata); metadata += 4; - yp_parser_local_add_location(parser, (const uint8_t *) metadata, (const uint8_t *) (metadata + local_size)); + uint8_t *constant = malloc(local_size); + memcpy(constant, metadata, local_size); + + yp_parser_local_add_owned(parser, constant, (size_t) local_size); metadata += local_size; } } @@ -13683,7 +14326,6 @@ yp_parser_init(yp_parser_t *parser, const uint8_t *source, size_t size, const ch *parser = (yp_parser_t) { .lex_state = YP_LEX_STATE_BEG, - .command_start = true, .enclosure_nesting = 0, .lambda_enclosure_nesting = -1, .brace_nesting = 0, @@ -13705,18 +14347,22 @@ yp_parser_init(yp_parser_t *parser, const uint8_t *source, size_t size, const ch .error_list = YP_LIST_EMPTY, .current_scope = NULL, .current_context = NULL, - .recovering = false, .encoding = yp_encoding_utf_8, - .encoding_changed = false, .encoding_changed_callback = NULL, .encoding_decode_callback = NULL, .encoding_comment_start = source, .lex_callback = NULL, - .pattern_matching_newlines = false, - .in_keyword_arg = false, .filepath_string = filepath_string, .constant_pool = YP_CONSTANT_POOL_EMPTY, - .newline_list = YP_NEWLINE_LIST_EMPTY + .newline_list = YP_NEWLINE_LIST_EMPTY, + .integer_base = 0, + .command_start = true, + .recovering = false, + .encoding_changed = false, + .pattern_matching_newlines = false, + .in_keyword_arg = false, + .semantic_token_seen = false, + .frozen_string_literal = false }; yp_accepts_block_stack_push(parser, true); @@ -13735,7 +14381,7 @@ yp_parser_init(yp_parser_t *parser, const uint8_t *source, size_t size, const ch // // This ratio will need to change if we add more constants to the constant // pool for another node type. - size_t constant_size = size / 95; + uint32_t constant_size = ((uint32_t) size) / 95; yp_constant_pool_init(&parser->constant_pool, constant_size < 4 ? 4 : constant_size); // Initialize the newline list. Similar to the constant pool, we're going to @@ -13800,6 +14446,15 @@ yp_parser_free(yp_parser_t *parser) { yp_constant_pool_free(&parser->constant_pool); yp_newline_list_free(&parser->newline_list); + while (parser->current_scope != NULL) { + // Normally, popping the scope doesn't free the locals since it is + // assumed that ownership has transferred to the AST. However if we have + // scopes while we're freeing the parser, it's likely they came from + // eval scopes and we need to free them explicitly here. + yp_constant_id_list_free(&parser->current_scope->locals); + yp_parser_scope_pop(parser); + } + while (parser->lex_modes.index >= YP_LEX_STACK_SIZE) { lex_mode_pop(parser); } @@ -13817,6 +14472,7 @@ yp_serialize(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) { yp_buffer_append_u8(buffer, YP_VERSION_MAJOR); yp_buffer_append_u8(buffer, YP_VERSION_MINOR); yp_buffer_append_u8(buffer, YP_VERSION_PATCH); + yp_buffer_append_u8(buffer, YP_SERIALIZE_ONLY_SEMANTICS_FIELDS ? 1 : 0); yp_serialize_content(parser, node, buffer); yp_buffer_append_str(buffer, "\0", 1); @@ -13837,6 +14493,10 @@ yp_parse_serialize(const uint8_t *source, size_t size, yp_buffer_t *buffer, cons yp_parser_free(&parser); } +#undef YP_LOCATION_NULL_VALUE +#undef YP_LOCATION_TOKEN_VALUE +#undef YP_LOCATION_NODE_VALUE +#undef YP_LOCATION_NODE_BASE_VALUE #undef YP_CASE_KEYWORD #undef YP_CASE_OPERATOR #undef YP_CASE_WRITABLE diff --git a/src/yarp/java/org/yarp/AbstractNodeVisitor.java b/src/yarp/java/org/yarp/AbstractNodeVisitor.java index c1752f3f6003..5fb6c7499229 100644 --- a/src/yarp/java/org/yarp/AbstractNodeVisitor.java +++ b/src/yarp/java/org/yarp/AbstractNodeVisitor.java @@ -12,7 +12,11 @@ public abstract class AbstractNodeVisitor { protected abstract T defaultVisit(Nodes.Node node); - public T visitAliasNode(Nodes.AliasNode node) { + public T visitAliasGlobalVariableNode(Nodes.AliasGlobalVariableNode node) { + return defaultVisit(node); + } + + public T visitAliasMethodNode(Nodes.AliasMethodNode node) { return defaultVisit(node); } @@ -56,6 +60,10 @@ public T visitBlockArgumentNode(Nodes.BlockArgumentNode node) { return defaultVisit(node); } + public T visitBlockLocalVariableNode(Nodes.BlockLocalVariableNode node) { + return defaultVisit(node); + } + public T visitBlockNode(Nodes.BlockNode node) { return defaultVisit(node); } @@ -72,19 +80,19 @@ public T visitBreakNode(Nodes.BreakNode node) { return defaultVisit(node); } - public T visitCallNode(Nodes.CallNode node) { + public T visitCallAndWriteNode(Nodes.CallAndWriteNode node) { return defaultVisit(node); } - public T visitCallOperatorAndWriteNode(Nodes.CallOperatorAndWriteNode node) { + public T visitCallNode(Nodes.CallNode node) { return defaultVisit(node); } - public T visitCallOperatorOrWriteNode(Nodes.CallOperatorOrWriteNode node) { + public T visitCallOperatorWriteNode(Nodes.CallOperatorWriteNode node) { return defaultVisit(node); } - public T visitCallOperatorWriteNode(Nodes.CallOperatorWriteNode node) { + public T visitCallOrWriteNode(Nodes.CallOrWriteNode node) { return defaultVisit(node); } @@ -268,6 +276,10 @@ public T visitImaginaryNode(Nodes.ImaginaryNode node) { return defaultVisit(node); } + public T visitImplicitNode(Nodes.ImplicitNode node) { + return defaultVisit(node); + } + public T visitInNode(Nodes.InNode node) { return defaultVisit(node); } @@ -300,6 +312,10 @@ public T visitIntegerNode(Nodes.IntegerNode node) { return defaultVisit(node); } + public T visitInterpolatedMatchLastLineNode(Nodes.InterpolatedMatchLastLineNode node) { + return defaultVisit(node); + } + public T visitInterpolatedRegularExpressionNode(Nodes.InterpolatedRegularExpressionNode node) { return defaultVisit(node); } @@ -356,6 +372,10 @@ public T visitLocalVariableWriteNode(Nodes.LocalVariableWriteNode node) { return defaultVisit(node); } + public T visitMatchLastLineNode(Nodes.MatchLastLineNode node) { + return defaultVisit(node); + } + public T visitMatchPredicateNode(Nodes.MatchPredicateNode node) { return defaultVisit(node); } @@ -364,6 +384,10 @@ public T visitMatchRequiredNode(Nodes.MatchRequiredNode node) { return defaultVisit(node); } + public T visitMatchWriteNode(Nodes.MatchWriteNode node) { + return defaultVisit(node); + } + public T visitMissingNode(Nodes.MissingNode node) { return defaultVisit(node); } @@ -372,6 +396,10 @@ public T visitModuleNode(Nodes.ModuleNode node) { return defaultVisit(node); } + public T visitMultiTargetNode(Nodes.MultiTargetNode node) { + return defaultVisit(node); + } + public T visitMultiWriteNode(Nodes.MultiWriteNode node) { return defaultVisit(node); } diff --git a/src/yarp/java/org/yarp/Loader.java b/src/yarp/java/org/yarp/Loader.java index 6108a1969754..ce5345810de0 100644 --- a/src/yarp/java/org/yarp/Loader.java +++ b/src/yarp/java/org/yarp/Loader.java @@ -7,12 +7,12 @@ /******************************************************************************/ package org.yarp; -import org.yarp.ParseResult; - import java.lang.Short; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.util.Locale; // GENERATED BY Loader.java.erb // @formatter:off @@ -22,38 +22,68 @@ public static ParseResult load(byte[] serialized, Nodes.Source source) { return new Loader(serialized, source).load(); } + // Overridable methods + + public Charset getEncodingCharset(String encodingName) { + encodingName = encodingName.toLowerCase(Locale.ROOT); + if (encodingName.equals("ascii-8bit")) { + return StandardCharsets.US_ASCII; + } + return Charset.forName(encodingName); + } + + public String bytesToName(byte[] bytes) { + return new String(bytes, encodingCharset).intern(); + } + private static final class ConstantPool { + private final Loader loader; private final byte[] source; private final int bufferOffset; - private final byte[][] cache; + private final String[] cache; - ConstantPool(byte[] source, int bufferOffset, int length) { + ConstantPool(Loader loader, byte[] source, int bufferOffset, int length) { + this.loader = loader; this.source = source; this.bufferOffset = bufferOffset; - cache = new byte[length][]; + cache = new String[length]; } - byte[] get(ByteBuffer buffer, int oneBasedIndex) { + String get(ByteBuffer buffer, int oneBasedIndex) { int index = oneBasedIndex - 1; - byte[] constant = cache[index]; + String constant = cache[index]; + if (constant == null) { int offset = bufferOffset + index * 8; int start = buffer.getInt(offset); int length = buffer.getInt(offset + 4); - constant = new byte[length]; - System.arraycopy(source, start, constant, 0, length); + byte[] bytes = new byte[length]; + + if (Integer.compareUnsigned(start, 0x7FFFFFFF) <= 0) { + System.arraycopy(source, start, bytes, 0, length); + } else { + int position = buffer.position(); + buffer.position(start & 0x7FFFFFFF); + buffer.get(bytes, 0, length); + buffer.position(position); + } + + constant = loader.bytesToName(bytes); cache[index] = constant; } + return constant; } } private final ByteBuffer buffer; - private ConstantPool constantPool; private final Nodes.Source source; + private String encodingName; + private Charset encodingCharset; + private ConstantPool constantPool; private Loader(byte[] serialized, Nodes.Source source) { this.buffer = ByteBuffer.wrap(serialized).order(ByteOrder.nativeOrder()); @@ -61,20 +91,23 @@ private Loader(byte[] serialized, Nodes.Source source) { } private ParseResult load() { - expect((byte) 'Y'); - expect((byte) 'A'); - expect((byte) 'R'); - expect((byte) 'P'); + expect((byte) 'Y', "incorrect YARP header"); + expect((byte) 'A', "incorrect YARP header"); + expect((byte) 'R', "incorrect YARP header"); + expect((byte) 'P', "incorrect YARP header"); + + expect((byte) 0, "YARP version does not match"); + expect((byte) 12, "YARP version does not match"); + expect((byte) 0, "YARP version does not match"); - expect((byte) 0); - expect((byte) 10); - expect((byte) 0); + expect((byte) 1, "Loader.java requires no location fields in the serialized output"); - // This loads the name of the encoding. We don't actually do anything - // with it just yet. + // This loads the name of the encoding. int encodingLength = loadVarInt(); - byte[] encodingName = new byte[encodingLength]; - buffer.get(encodingName); + byte[] encodingNameBytes = new byte[encodingLength]; + buffer.get(encodingNameBytes); + this.encodingName = new String(encodingNameBytes, StandardCharsets.US_ASCII); + this.encodingCharset = getEncodingCharset(this.encodingName); ParseResult.Comment[] comments = loadComments(); ParseResult.Error[] errors = loadSyntaxErrors(); @@ -82,7 +115,7 @@ private ParseResult load() { int constantPoolBufferOffset = buffer.getInt(); int constantPoolLength = loadVarInt(); - this.constantPool = new ConstantPool(source.bytes, constantPoolBufferOffset, constantPoolLength); + this.constantPool = new ConstantPool(this, source.bytes, constantPoolBufferOffset, constantPoolLength); Nodes.Node node = loadNode(); @@ -100,9 +133,9 @@ private ParseResult load() { private byte[] loadEmbeddedString() { int length = loadVarInt(); - byte[] string = new byte[length]; - buffer.get(string); - return string; + byte[] bytes = new byte[length]; + buffer.get(bytes); + return bytes; } private byte[] loadString() { @@ -110,9 +143,9 @@ private byte[] loadString() { case 1: int start = loadVarInt(); int length = loadVarInt(); - byte[] string = new byte[length]; - System.arraycopy(source.bytes, start, string, 0, length); - return string; + byte[] bytes = new byte[length]; + System.arraycopy(source.bytes, start, bytes, 0, length); + return bytes; case 2: return loadEmbeddedString(); default: @@ -178,28 +211,25 @@ private Nodes.Node loadOptionalNode() { } } - private Nodes.Location[] loadLocations() { - int length = loadVarInt(); - if (length == 0) { - return Nodes.Location.EMPTY_ARRAY; - } - Nodes.Location[] locations = new Nodes.Location[length]; - for (int i = 0; i < length; i++) { - locations[i] = loadLocation(); - } - return locations; + private String loadConstant() { + return constantPool.get(buffer, loadVarInt()); } - private byte[] loadConstant() { - return constantPool.get(buffer, loadVarInt()); + private String loadOptionalConstant() { + if (buffer.get(buffer.position()) != 0) { + return loadConstant(); + } else { + buffer.position(buffer.position() + 1); // continue after the 0 byte + return null; + } } - private byte[][] loadConstants() { + private String[] loadConstants() { int length = loadVarInt(); if (length == 0) { - return Nodes.EMPTY_BYTE_ARRAY_ARRAY; + return Nodes.EMPTY_STRING_ARRAY; } - byte[][] constants = new byte[length][]; + String[] constants = new String[length]; for (int i = 0; i < length; i++) { constants[i] = constantPool.get(buffer, loadVarInt()); } @@ -261,282 +291,296 @@ private Nodes.Node loadNode() { switch (type) { case 1: - return new Nodes.AliasNode(loadNode(), loadNode(), loadLocation(), startOffset, length); + return new Nodes.AliasGlobalVariableNode(loadNode(), loadNode(), startOffset, length); case 2: - return new Nodes.AlternationPatternNode(loadNode(), loadNode(), loadLocation(), startOffset, length); + return new Nodes.AliasMethodNode(loadNode(), loadNode(), startOffset, length); case 3: - return new Nodes.AndNode(loadNode(), loadNode(), loadLocation(), startOffset, length); + return new Nodes.AlternationPatternNode(loadNode(), loadNode(), startOffset, length); case 4: - return new Nodes.ArgumentsNode(loadNodes(), startOffset, length); + return new Nodes.AndNode(loadNode(), loadNode(), startOffset, length); case 5: - return new Nodes.ArrayNode(loadNodes(), loadOptionalLocation(), loadOptionalLocation(), startOffset, length); + return new Nodes.ArgumentsNode(loadNodes(), startOffset, length); case 6: - return new Nodes.ArrayPatternNode(loadOptionalNode(), loadNodes(), loadOptionalNode(), loadNodes(), loadOptionalLocation(), loadOptionalLocation(), startOffset, length); + return new Nodes.ArrayNode(loadNodes(), startOffset, length); case 7: - return new Nodes.AssocNode(loadNode(), loadOptionalNode(), loadOptionalLocation(), startOffset, length); + return new Nodes.ArrayPatternNode(loadOptionalNode(), loadNodes(), loadOptionalNode(), loadNodes(), startOffset, length); case 8: - return new Nodes.AssocSplatNode(loadOptionalNode(), loadLocation(), startOffset, length); + return new Nodes.AssocNode(loadNode(), loadOptionalNode(), startOffset, length); case 9: - return new Nodes.BackReferenceReadNode(startOffset, length); + return new Nodes.AssocSplatNode(loadOptionalNode(), startOffset, length); case 10: - return new Nodes.BeginNode(loadOptionalLocation(), (Nodes.StatementsNode) loadOptionalNode(), (Nodes.RescueNode) loadOptionalNode(), (Nodes.ElseNode) loadOptionalNode(), (Nodes.EnsureNode) loadOptionalNode(), loadOptionalLocation(), startOffset, length); + return new Nodes.BackReferenceReadNode(startOffset, length); case 11: - return new Nodes.BlockArgumentNode(loadOptionalNode(), loadLocation(), startOffset, length); + return new Nodes.BeginNode((Nodes.StatementsNode) loadOptionalNode(), (Nodes.RescueNode) loadOptionalNode(), (Nodes.ElseNode) loadOptionalNode(), (Nodes.EnsureNode) loadOptionalNode(), startOffset, length); case 12: - return new Nodes.BlockNode(loadConstants(), (Nodes.BlockParametersNode) loadOptionalNode(), loadOptionalNode(), loadLocation(), loadLocation(), startOffset, length); + return new Nodes.BlockArgumentNode(loadOptionalNode(), startOffset, length); case 13: - return new Nodes.BlockParameterNode(loadOptionalLocation(), loadLocation(), startOffset, length); + return new Nodes.BlockLocalVariableNode(loadConstant(), startOffset, length); case 14: - return new Nodes.BlockParametersNode((Nodes.ParametersNode) loadOptionalNode(), loadLocations(), loadOptionalLocation(), loadOptionalLocation(), startOffset, length); + return new Nodes.BlockNode(loadConstants(), (Nodes.BlockParametersNode) loadOptionalNode(), loadOptionalNode(), startOffset, length); case 15: - return new Nodes.BreakNode((Nodes.ArgumentsNode) loadOptionalNode(), loadLocation(), startOffset, length); + return new Nodes.BlockParameterNode(loadOptionalConstant(), startOffset, length); case 16: - return new Nodes.CallNode(loadOptionalNode(), loadOptionalLocation(), loadOptionalLocation(), loadOptionalLocation(), (Nodes.ArgumentsNode) loadOptionalNode(), loadOptionalLocation(), (Nodes.BlockNode) loadOptionalNode(), loadFlags(), loadString(), startOffset, length); + return new Nodes.BlockParametersNode((Nodes.ParametersNode) loadOptionalNode(), loadNodes(), startOffset, length); case 17: - return new Nodes.CallOperatorAndWriteNode((Nodes.CallNode) loadNode(), loadLocation(), loadNode(), startOffset, length); + return new Nodes.BreakNode((Nodes.ArgumentsNode) loadOptionalNode(), startOffset, length); case 18: - return new Nodes.CallOperatorOrWriteNode((Nodes.CallNode) loadNode(), loadNode(), loadLocation(), startOffset, length); + return new Nodes.CallAndWriteNode(loadOptionalNode(), (Nodes.ArgumentsNode) loadOptionalNode(), loadFlags(), loadString(), loadString(), loadNode(), startOffset, length); case 19: - return new Nodes.CallOperatorWriteNode((Nodes.CallNode) loadNode(), loadLocation(), loadNode(), loadConstant(), startOffset, length); + return new Nodes.CallNode(loadOptionalNode(), (Nodes.ArgumentsNode) loadOptionalNode(), loadOptionalNode(), loadFlags(), loadString(), startOffset, length); case 20: - return new Nodes.CapturePatternNode(loadNode(), loadNode(), loadLocation(), startOffset, length); + return new Nodes.CallOperatorWriteNode(loadOptionalNode(), (Nodes.ArgumentsNode) loadOptionalNode(), loadFlags(), loadString(), loadString(), loadConstant(), loadNode(), startOffset, length); case 21: - return new Nodes.CaseNode(loadOptionalNode(), loadNodes(), (Nodes.ElseNode) loadOptionalNode(), loadLocation(), loadLocation(), startOffset, length); + return new Nodes.CallOrWriteNode(loadOptionalNode(), (Nodes.ArgumentsNode) loadOptionalNode(), loadFlags(), loadString(), loadString(), loadNode(), startOffset, length); case 22: - return new Nodes.ClassNode(loadConstants(), loadLocation(), loadNode(), loadOptionalLocation(), loadOptionalNode(), loadOptionalNode(), loadLocation(), loadString(), startOffset, length); + return new Nodes.CapturePatternNode(loadNode(), loadNode(), startOffset, length); case 23: - return new Nodes.ClassVariableAndWriteNode(loadConstant(), loadLocation(), loadLocation(), loadNode(), startOffset, length); + return new Nodes.CaseNode(loadOptionalNode(), loadNodes(), (Nodes.ElseNode) loadOptionalNode(), startOffset, length); case 24: - return new Nodes.ClassVariableOperatorWriteNode(loadConstant(), loadLocation(), loadLocation(), loadNode(), loadConstant(), startOffset, length); + return new Nodes.ClassNode(loadConstants(), loadNode(), loadOptionalNode(), loadOptionalNode(), loadConstant(), startOffset, length); case 25: - return new Nodes.ClassVariableOrWriteNode(loadConstant(), loadLocation(), loadLocation(), loadNode(), startOffset, length); + return new Nodes.ClassVariableAndWriteNode(loadConstant(), loadNode(), startOffset, length); case 26: - return new Nodes.ClassVariableReadNode(loadConstant(), startOffset, length); + return new Nodes.ClassVariableOperatorWriteNode(loadConstant(), loadNode(), loadConstant(), startOffset, length); case 27: - return new Nodes.ClassVariableTargetNode(loadConstant(), startOffset, length); + return new Nodes.ClassVariableOrWriteNode(loadConstant(), loadNode(), startOffset, length); case 28: - return new Nodes.ClassVariableWriteNode(loadConstant(), loadLocation(), loadOptionalNode(), loadOptionalLocation(), startOffset, length); + return new Nodes.ClassVariableReadNode(loadConstant(), startOffset, length); case 29: - return new Nodes.ConstantAndWriteNode(loadLocation(), loadLocation(), loadNode(), startOffset, length); + return new Nodes.ClassVariableTargetNode(loadConstant(), startOffset, length); case 30: - return new Nodes.ConstantOperatorWriteNode(loadLocation(), loadLocation(), loadNode(), loadConstant(), startOffset, length); + return new Nodes.ClassVariableWriteNode(loadConstant(), loadNode(), startOffset, length); case 31: - return new Nodes.ConstantOrWriteNode(loadLocation(), loadLocation(), loadNode(), startOffset, length); + return new Nodes.ConstantAndWriteNode(loadConstant(), loadNode(), startOffset, length); case 32: - return new Nodes.ConstantPathAndWriteNode((Nodes.ConstantPathNode) loadNode(), loadLocation(), loadNode(), startOffset, length); + return new Nodes.ConstantOperatorWriteNode(loadConstant(), loadNode(), loadConstant(), startOffset, length); case 33: - return new Nodes.ConstantPathNode(loadOptionalNode(), loadNode(), loadLocation(), startOffset, length); + return new Nodes.ConstantOrWriteNode(loadConstant(), loadNode(), startOffset, length); case 34: - return new Nodes.ConstantPathOperatorWriteNode((Nodes.ConstantPathNode) loadNode(), loadLocation(), loadNode(), loadConstant(), startOffset, length); + return new Nodes.ConstantPathAndWriteNode((Nodes.ConstantPathNode) loadNode(), loadNode(), startOffset, length); case 35: - return new Nodes.ConstantPathOrWriteNode((Nodes.ConstantPathNode) loadNode(), loadLocation(), loadNode(), startOffset, length); + return new Nodes.ConstantPathNode(loadOptionalNode(), loadNode(), startOffset, length); case 36: - return new Nodes.ConstantPathTargetNode(loadOptionalNode(), loadNode(), loadLocation(), startOffset, length); + return new Nodes.ConstantPathOperatorWriteNode((Nodes.ConstantPathNode) loadNode(), loadNode(), loadConstant(), startOffset, length); case 37: - return new Nodes.ConstantPathWriteNode((Nodes.ConstantPathNode) loadNode(), loadLocation(), loadNode(), startOffset, length); + return new Nodes.ConstantPathOrWriteNode((Nodes.ConstantPathNode) loadNode(), loadNode(), startOffset, length); case 38: - return new Nodes.ConstantReadNode(startOffset, length); + return new Nodes.ConstantPathTargetNode(loadOptionalNode(), loadNode(), startOffset, length); case 39: - return new Nodes.ConstantTargetNode(startOffset, length); + return new Nodes.ConstantPathWriteNode((Nodes.ConstantPathNode) loadNode(), loadNode(), startOffset, length); case 40: - return new Nodes.ConstantWriteNode(loadLocation(), loadNode(), loadLocation(), startOffset, length); + return new Nodes.ConstantReadNode(loadConstant(), startOffset, length); case 41: - return new Nodes.DefNode(buffer.getInt(), loadLocation(), loadOptionalNode(), (Nodes.ParametersNode) loadOptionalNode(), loadOptionalNode(), loadConstants(), loadLocation(), loadOptionalLocation(), loadOptionalLocation(), loadOptionalLocation(), loadOptionalLocation(), loadOptionalLocation(), startOffset, length); + return new Nodes.ConstantTargetNode(loadConstant(), startOffset, length); case 42: - return new Nodes.DefinedNode(loadOptionalLocation(), loadNode(), loadOptionalLocation(), loadLocation(), startOffset, length); + return new Nodes.ConstantWriteNode(loadConstant(), loadNode(), startOffset, length); case 43: - return new Nodes.ElseNode(loadLocation(), (Nodes.StatementsNode) loadOptionalNode(), loadOptionalLocation(), startOffset, length); + return new Nodes.DefNode(buffer.getInt(), loadConstant(), loadOptionalNode(), (Nodes.ParametersNode) loadOptionalNode(), loadOptionalNode(), loadConstants(), startOffset, length); case 44: - return new Nodes.EmbeddedStatementsNode(loadLocation(), (Nodes.StatementsNode) loadOptionalNode(), loadLocation(), startOffset, length); + return new Nodes.DefinedNode(loadNode(), startOffset, length); case 45: - return new Nodes.EmbeddedVariableNode(loadLocation(), loadNode(), startOffset, length); + return new Nodes.ElseNode((Nodes.StatementsNode) loadOptionalNode(), startOffset, length); case 46: - return new Nodes.EnsureNode(loadLocation(), (Nodes.StatementsNode) loadOptionalNode(), loadLocation(), startOffset, length); + return new Nodes.EmbeddedStatementsNode((Nodes.StatementsNode) loadOptionalNode(), startOffset, length); case 47: - return new Nodes.FalseNode(startOffset, length); + return new Nodes.EmbeddedVariableNode(loadNode(), startOffset, length); case 48: - return new Nodes.FindPatternNode(loadOptionalNode(), loadNode(), loadNodes(), loadNode(), loadOptionalLocation(), loadOptionalLocation(), startOffset, length); + return new Nodes.EnsureNode((Nodes.StatementsNode) loadOptionalNode(), startOffset, length); case 49: - return new Nodes.FlipFlopNode(loadOptionalNode(), loadOptionalNode(), loadLocation(), loadFlags(), startOffset, length); + return new Nodes.FalseNode(startOffset, length); case 50: - return new Nodes.FloatNode(startOffset, length); + return new Nodes.FindPatternNode(loadOptionalNode(), loadNode(), loadNodes(), loadNode(), startOffset, length); case 51: - return new Nodes.ForNode(loadNode(), loadNode(), (Nodes.StatementsNode) loadOptionalNode(), loadLocation(), loadLocation(), loadOptionalLocation(), loadLocation(), startOffset, length); + return new Nodes.FlipFlopNode(loadOptionalNode(), loadOptionalNode(), loadFlags(), startOffset, length); case 52: - return new Nodes.ForwardingArgumentsNode(startOffset, length); + return new Nodes.FloatNode(startOffset, length); case 53: - return new Nodes.ForwardingParameterNode(startOffset, length); + return new Nodes.ForNode(loadNode(), loadNode(), (Nodes.StatementsNode) loadOptionalNode(), startOffset, length); case 54: - return new Nodes.ForwardingSuperNode((Nodes.BlockNode) loadOptionalNode(), startOffset, length); + return new Nodes.ForwardingArgumentsNode(startOffset, length); case 55: - return new Nodes.GlobalVariableAndWriteNode(loadConstant(), loadLocation(), loadLocation(), loadNode(), startOffset, length); + return new Nodes.ForwardingParameterNode(startOffset, length); case 56: - return new Nodes.GlobalVariableOperatorWriteNode(loadConstant(), loadLocation(), loadLocation(), loadNode(), loadConstant(), startOffset, length); + return new Nodes.ForwardingSuperNode((Nodes.BlockNode) loadOptionalNode(), startOffset, length); case 57: - return new Nodes.GlobalVariableOrWriteNode(loadConstant(), loadLocation(), loadLocation(), loadNode(), startOffset, length); + return new Nodes.GlobalVariableAndWriteNode(loadConstant(), loadNode(), startOffset, length); case 58: - return new Nodes.GlobalVariableReadNode(loadConstant(), startOffset, length); + return new Nodes.GlobalVariableOperatorWriteNode(loadConstant(), loadNode(), loadConstant(), startOffset, length); case 59: - return new Nodes.GlobalVariableTargetNode(loadConstant(), startOffset, length); + return new Nodes.GlobalVariableOrWriteNode(loadConstant(), loadNode(), startOffset, length); case 60: - return new Nodes.GlobalVariableWriteNode(loadConstant(), loadLocation(), loadNode(), loadLocation(), startOffset, length); + return new Nodes.GlobalVariableReadNode(loadConstant(), startOffset, length); case 61: - return new Nodes.HashNode(loadLocation(), loadNodes(), loadLocation(), startOffset, length); + return new Nodes.GlobalVariableTargetNode(loadConstant(), startOffset, length); case 62: - return new Nodes.HashPatternNode(loadOptionalNode(), loadNodes(), loadOptionalNode(), loadOptionalLocation(), loadOptionalLocation(), startOffset, length); + return new Nodes.GlobalVariableWriteNode(loadConstant(), loadNode(), startOffset, length); case 63: - return new Nodes.IfNode(loadOptionalLocation(), loadNode(), (Nodes.StatementsNode) loadOptionalNode(), loadOptionalNode(), loadOptionalLocation(), startOffset, length); + return new Nodes.HashNode(loadNodes(), startOffset, length); case 64: - return new Nodes.ImaginaryNode(loadNode(), startOffset, length); + return new Nodes.HashPatternNode(loadOptionalNode(), loadNodes(), loadOptionalNode(), startOffset, length); case 65: - return new Nodes.InNode(loadNode(), (Nodes.StatementsNode) loadOptionalNode(), loadLocation(), loadOptionalLocation(), startOffset, length); + return new Nodes.IfNode(loadNode(), (Nodes.StatementsNode) loadOptionalNode(), loadOptionalNode(), startOffset, length); case 66: - return new Nodes.InstanceVariableAndWriteNode(loadConstant(), loadLocation(), loadLocation(), loadNode(), startOffset, length); + return new Nodes.ImaginaryNode(loadNode(), startOffset, length); case 67: - return new Nodes.InstanceVariableOperatorWriteNode(loadConstant(), loadLocation(), loadLocation(), loadNode(), loadConstant(), startOffset, length); + return new Nodes.ImplicitNode(loadNode(), startOffset, length); case 68: - return new Nodes.InstanceVariableOrWriteNode(loadConstant(), loadLocation(), loadLocation(), loadNode(), startOffset, length); + return new Nodes.InNode(loadNode(), (Nodes.StatementsNode) loadOptionalNode(), startOffset, length); case 69: - return new Nodes.InstanceVariableReadNode(loadConstant(), startOffset, length); + return new Nodes.InstanceVariableAndWriteNode(loadConstant(), loadNode(), startOffset, length); case 70: - return new Nodes.InstanceVariableTargetNode(loadConstant(), startOffset, length); + return new Nodes.InstanceVariableOperatorWriteNode(loadConstant(), loadNode(), loadConstant(), startOffset, length); case 71: - return new Nodes.InstanceVariableWriteNode(loadConstant(), loadLocation(), loadNode(), loadLocation(), startOffset, length); + return new Nodes.InstanceVariableOrWriteNode(loadConstant(), loadNode(), startOffset, length); case 72: - return new Nodes.IntegerNode(startOffset, length); + return new Nodes.InstanceVariableReadNode(loadConstant(), startOffset, length); case 73: - return new Nodes.InterpolatedRegularExpressionNode(loadLocation(), loadNodes(), loadLocation(), loadFlags(), startOffset, length); + return new Nodes.InstanceVariableTargetNode(loadConstant(), startOffset, length); case 74: - return new Nodes.InterpolatedStringNode(loadOptionalLocation(), loadNodes(), loadOptionalLocation(), startOffset, length); + return new Nodes.InstanceVariableWriteNode(loadConstant(), loadNode(), startOffset, length); case 75: - return new Nodes.InterpolatedSymbolNode(loadOptionalLocation(), loadNodes(), loadOptionalLocation(), startOffset, length); + return new Nodes.IntegerNode(loadFlags(), startOffset, length); case 76: - return new Nodes.InterpolatedXStringNode(loadLocation(), loadNodes(), loadLocation(), startOffset, length); + return new Nodes.InterpolatedMatchLastLineNode(loadNodes(), loadFlags(), startOffset, length); case 77: - return new Nodes.KeywordHashNode(loadNodes(), startOffset, length); + return new Nodes.InterpolatedRegularExpressionNode(loadNodes(), loadFlags(), startOffset, length); case 78: - return new Nodes.KeywordParameterNode(loadLocation(), loadOptionalNode(), startOffset, length); + return new Nodes.InterpolatedStringNode(loadNodes(), startOffset, length); case 79: - return new Nodes.KeywordRestParameterNode(loadLocation(), loadOptionalLocation(), startOffset, length); + return new Nodes.InterpolatedSymbolNode(loadNodes(), startOffset, length); case 80: - return new Nodes.LambdaNode(loadConstants(), loadLocation(), loadLocation(), loadLocation(), (Nodes.BlockParametersNode) loadOptionalNode(), loadOptionalNode(), startOffset, length); + return new Nodes.InterpolatedXStringNode(loadNodes(), startOffset, length); case 81: - return new Nodes.LocalVariableAndWriteNode(loadLocation(), loadLocation(), loadNode(), loadConstant(), loadVarInt(), startOffset, length); + return new Nodes.KeywordHashNode(loadNodes(), startOffset, length); case 82: - return new Nodes.LocalVariableOperatorWriteNode(loadLocation(), loadLocation(), loadNode(), loadConstant(), loadConstant(), loadVarInt(), startOffset, length); + return new Nodes.KeywordParameterNode(loadConstant(), loadOptionalNode(), startOffset, length); case 83: - return new Nodes.LocalVariableOrWriteNode(loadLocation(), loadLocation(), loadNode(), loadConstant(), loadVarInt(), startOffset, length); + return new Nodes.KeywordRestParameterNode(loadOptionalConstant(), startOffset, length); case 84: - return new Nodes.LocalVariableReadNode(loadConstant(), loadVarInt(), startOffset, length); + return new Nodes.LambdaNode(loadConstants(), (Nodes.BlockParametersNode) loadOptionalNode(), loadOptionalNode(), startOffset, length); case 85: - return new Nodes.LocalVariableTargetNode(loadConstant(), loadVarInt(), startOffset, length); + return new Nodes.LocalVariableAndWriteNode(loadNode(), loadConstant(), loadVarInt(), startOffset, length); case 86: - return new Nodes.LocalVariableWriteNode(loadConstant(), loadVarInt(), loadLocation(), loadNode(), loadLocation(), startOffset, length); + return new Nodes.LocalVariableOperatorWriteNode(loadNode(), loadConstant(), loadConstant(), loadVarInt(), startOffset, length); case 87: - return new Nodes.MatchPredicateNode(loadNode(), loadNode(), loadLocation(), startOffset, length); + return new Nodes.LocalVariableOrWriteNode(loadNode(), loadConstant(), loadVarInt(), startOffset, length); case 88: - return new Nodes.MatchRequiredNode(loadNode(), loadNode(), loadLocation(), startOffset, length); + return new Nodes.LocalVariableReadNode(loadConstant(), loadVarInt(), startOffset, length); case 89: - return new Nodes.MissingNode(startOffset, length); + return new Nodes.LocalVariableTargetNode(loadConstant(), loadVarInt(), startOffset, length); case 90: - return new Nodes.ModuleNode(loadConstants(), loadLocation(), loadNode(), loadOptionalNode(), loadLocation(), loadString(), startOffset, length); + return new Nodes.LocalVariableWriteNode(loadConstant(), loadVarInt(), loadNode(), startOffset, length); case 91: - return new Nodes.MultiWriteNode(loadNodes(), loadOptionalLocation(), loadOptionalNode(), loadOptionalLocation(), loadOptionalLocation(), startOffset, length); + return new Nodes.MatchLastLineNode(loadLocation(), loadString(), loadFlags(), startOffset, length); case 92: - return new Nodes.NextNode((Nodes.ArgumentsNode) loadOptionalNode(), loadLocation(), startOffset, length); + return new Nodes.MatchPredicateNode(loadNode(), loadNode(), startOffset, length); case 93: - return new Nodes.NilNode(startOffset, length); + return new Nodes.MatchRequiredNode(loadNode(), loadNode(), startOffset, length); case 94: - return new Nodes.NoKeywordsParameterNode(loadLocation(), loadLocation(), startOffset, length); + return new Nodes.MatchWriteNode((Nodes.CallNode) loadNode(), loadConstants(), startOffset, length); case 95: - return new Nodes.NumberedReferenceReadNode(loadVarInt(), startOffset, length); + return new Nodes.MissingNode(startOffset, length); case 96: - return new Nodes.OptionalParameterNode(loadConstant(), loadLocation(), loadLocation(), loadNode(), startOffset, length); + return new Nodes.ModuleNode(loadConstants(), loadNode(), loadOptionalNode(), loadConstant(), startOffset, length); case 97: - return new Nodes.OrNode(loadNode(), loadNode(), loadLocation(), startOffset, length); + return new Nodes.MultiTargetNode(loadNodes(), startOffset, length); case 98: - return new Nodes.ParametersNode(loadNodes(), loadNodes(), loadNodes(), (Nodes.RestParameterNode) loadOptionalNode(), loadNodes(), loadOptionalNode(), (Nodes.BlockParameterNode) loadOptionalNode(), startOffset, length); + return new Nodes.MultiWriteNode(loadNodes(), loadNode(), startOffset, length); case 99: - return new Nodes.ParenthesesNode(loadOptionalNode(), loadLocation(), loadLocation(), startOffset, length); + return new Nodes.NextNode((Nodes.ArgumentsNode) loadOptionalNode(), startOffset, length); case 100: - return new Nodes.PinnedExpressionNode(loadNode(), loadLocation(), loadLocation(), loadLocation(), startOffset, length); + return new Nodes.NilNode(startOffset, length); case 101: - return new Nodes.PinnedVariableNode(loadNode(), loadLocation(), startOffset, length); + return new Nodes.NoKeywordsParameterNode(startOffset, length); case 102: - return new Nodes.PostExecutionNode((Nodes.StatementsNode) loadOptionalNode(), loadLocation(), loadLocation(), loadLocation(), startOffset, length); + return new Nodes.NumberedReferenceReadNode(loadVarInt(), startOffset, length); case 103: - return new Nodes.PreExecutionNode((Nodes.StatementsNode) loadOptionalNode(), loadLocation(), loadLocation(), loadLocation(), startOffset, length); + return new Nodes.OptionalParameterNode(loadConstant(), loadNode(), startOffset, length); case 104: - return new Nodes.ProgramNode(loadConstants(), (Nodes.StatementsNode) loadNode(), startOffset, length); + return new Nodes.OrNode(loadNode(), loadNode(), startOffset, length); case 105: - return new Nodes.RangeNode(loadOptionalNode(), loadOptionalNode(), loadLocation(), loadFlags(), startOffset, length); + return new Nodes.ParametersNode(loadNodes(), loadNodes(), (Nodes.RestParameterNode) loadOptionalNode(), loadNodes(), loadNodes(), loadOptionalNode(), (Nodes.BlockParameterNode) loadOptionalNode(), startOffset, length); case 106: - return new Nodes.RationalNode(loadNode(), startOffset, length); + return new Nodes.ParenthesesNode(loadOptionalNode(), startOffset, length); case 107: - return new Nodes.RedoNode(startOffset, length); + return new Nodes.PinnedExpressionNode(loadNode(), startOffset, length); case 108: - return new Nodes.RegularExpressionNode(loadLocation(), loadLocation(), loadLocation(), loadString(), loadFlags(), startOffset, length); + return new Nodes.PinnedVariableNode(loadNode(), startOffset, length); case 109: - return new Nodes.RequiredDestructuredParameterNode(loadNodes(), loadLocation(), loadLocation(), startOffset, length); + return new Nodes.PostExecutionNode((Nodes.StatementsNode) loadOptionalNode(), startOffset, length); case 110: - return new Nodes.RequiredParameterNode(loadConstant(), startOffset, length); + return new Nodes.PreExecutionNode((Nodes.StatementsNode) loadOptionalNode(), startOffset, length); case 111: - return new Nodes.RescueModifierNode(loadNode(), loadLocation(), loadNode(), startOffset, length); + return new Nodes.ProgramNode(loadConstants(), (Nodes.StatementsNode) loadNode(), startOffset, length); case 112: - return new Nodes.RescueNode(loadLocation(), loadNodes(), loadOptionalLocation(), loadOptionalNode(), (Nodes.StatementsNode) loadOptionalNode(), (Nodes.RescueNode) loadOptionalNode(), startOffset, length); + return new Nodes.RangeNode(loadOptionalNode(), loadOptionalNode(), loadFlags(), startOffset, length); case 113: - return new Nodes.RestParameterNode(loadLocation(), loadOptionalLocation(), startOffset, length); + return new Nodes.RationalNode(loadNode(), startOffset, length); case 114: - return new Nodes.RetryNode(startOffset, length); + return new Nodes.RedoNode(startOffset, length); case 115: - return new Nodes.ReturnNode(loadLocation(), (Nodes.ArgumentsNode) loadOptionalNode(), startOffset, length); + return new Nodes.RegularExpressionNode(loadLocation(), loadString(), loadFlags(), startOffset, length); case 116: - return new Nodes.SelfNode(startOffset, length); + return new Nodes.RequiredDestructuredParameterNode(loadNodes(), startOffset, length); case 117: - return new Nodes.SingletonClassNode(loadConstants(), loadLocation(), loadLocation(), loadNode(), loadOptionalNode(), loadLocation(), startOffset, length); + return new Nodes.RequiredParameterNode(loadConstant(), startOffset, length); case 118: - return new Nodes.SourceEncodingNode(startOffset, length); + return new Nodes.RescueModifierNode(loadNode(), loadNode(), startOffset, length); case 119: - return new Nodes.SourceFileNode(loadString(), startOffset, length); + return new Nodes.RescueNode(loadNodes(), loadOptionalNode(), (Nodes.StatementsNode) loadOptionalNode(), (Nodes.RescueNode) loadOptionalNode(), startOffset, length); case 120: - return new Nodes.SourceLineNode(startOffset, length); + return new Nodes.RestParameterNode(loadOptionalConstant(), startOffset, length); case 121: - return new Nodes.SplatNode(loadLocation(), loadOptionalNode(), startOffset, length); + return new Nodes.RetryNode(startOffset, length); case 122: - return new Nodes.StatementsNode(loadNodes(), startOffset, length); + return new Nodes.ReturnNode((Nodes.ArgumentsNode) loadOptionalNode(), startOffset, length); case 123: - return new Nodes.StringConcatNode(loadNode(), loadNode(), startOffset, length); + return new Nodes.SelfNode(startOffset, length); case 124: - return new Nodes.StringNode(loadOptionalLocation(), loadLocation(), loadOptionalLocation(), loadString(), startOffset, length); + return new Nodes.SingletonClassNode(loadConstants(), loadNode(), loadOptionalNode(), startOffset, length); case 125: - return new Nodes.SuperNode(loadLocation(), loadOptionalLocation(), (Nodes.ArgumentsNode) loadOptionalNode(), loadOptionalLocation(), (Nodes.BlockNode) loadOptionalNode(), startOffset, length); + return new Nodes.SourceEncodingNode(startOffset, length); case 126: - return new Nodes.SymbolNode(loadOptionalLocation(), loadOptionalLocation(), loadOptionalLocation(), loadString(), startOffset, length); + return new Nodes.SourceFileNode(loadString(), startOffset, length); case 127: - return new Nodes.TrueNode(startOffset, length); + return new Nodes.SourceLineNode(startOffset, length); case 128: - return new Nodes.UndefNode(loadNodes(), loadLocation(), startOffset, length); + return new Nodes.SplatNode(loadOptionalNode(), startOffset, length); case 129: - return new Nodes.UnlessNode(loadLocation(), loadNode(), (Nodes.StatementsNode) loadOptionalNode(), (Nodes.ElseNode) loadOptionalNode(), loadOptionalLocation(), startOffset, length); + return new Nodes.StatementsNode(loadNodes(), startOffset, length); case 130: - return new Nodes.UntilNode(loadLocation(), loadOptionalLocation(), loadNode(), (Nodes.StatementsNode) loadOptionalNode(), loadFlags(), startOffset, length); + return new Nodes.StringConcatNode(loadNode(), loadNode(), startOffset, length); case 131: - return new Nodes.WhenNode(loadLocation(), loadNodes(), (Nodes.StatementsNode) loadOptionalNode(), startOffset, length); + return new Nodes.StringNode(loadFlags(), loadOptionalLocation(), loadLocation(), loadString(), startOffset, length); case 132: - return new Nodes.WhileNode(loadLocation(), loadOptionalLocation(), loadNode(), (Nodes.StatementsNode) loadOptionalNode(), loadFlags(), startOffset, length); + return new Nodes.SuperNode((Nodes.ArgumentsNode) loadOptionalNode(), loadOptionalNode(), startOffset, length); case 133: - return new Nodes.XStringNode(loadLocation(), loadLocation(), loadLocation(), loadString(), startOffset, length); + return new Nodes.SymbolNode(loadString(), startOffset, length); case 134: - return new Nodes.YieldNode(loadLocation(), loadOptionalLocation(), (Nodes.ArgumentsNode) loadOptionalNode(), loadOptionalLocation(), startOffset, length); + return new Nodes.TrueNode(startOffset, length); + case 135: + return new Nodes.UndefNode(loadNodes(), startOffset, length); + case 136: + return new Nodes.UnlessNode(loadNode(), (Nodes.StatementsNode) loadOptionalNode(), (Nodes.ElseNode) loadOptionalNode(), startOffset, length); + case 137: + return new Nodes.UntilNode(loadNode(), (Nodes.StatementsNode) loadOptionalNode(), loadFlags(), startOffset, length); + case 138: + return new Nodes.WhenNode(loadNodes(), (Nodes.StatementsNode) loadOptionalNode(), startOffset, length); + case 139: + return new Nodes.WhileNode(loadNode(), (Nodes.StatementsNode) loadOptionalNode(), loadFlags(), startOffset, length); + case 140: + return new Nodes.XStringNode(loadString(), startOffset, length); + case 141: + return new Nodes.YieldNode((Nodes.ArgumentsNode) loadOptionalNode(), startOffset, length); default: throw new Error("Unknown node type: " + type); } } - private void expect(byte value) { + private void expect(byte value, String error) { byte b = buffer.get(); if (b != value) { - throw new Error("Expected " + value + " but was " + b + " at position " + buffer.position()); + throw new Error("Deserialization error: " + error + " (expected " + value + " but was " + b + " at position " + buffer.position() + ")"); } } diff --git a/src/yarp/java/org/yarp/Nodes.java b/src/yarp/java/org/yarp/Nodes.java index 56774d1f8653..84a8d88b1661 100644 --- a/src/yarp/java/org/yarp/Nodes.java +++ b/src/yarp/java/org/yarp/Nodes.java @@ -10,6 +10,7 @@ import java.lang.Override; import java.lang.String; import java.lang.StringBuilder; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; @@ -18,6 +19,7 @@ public abstract class Nodes { public static final byte[][] EMPTY_BYTE_ARRAY_ARRAY = {}; + public static final String[] EMPTY_STRING_ARRAY = {}; public static final class Location { @@ -124,20 +126,7 @@ public String toString() { return toString(""); } - private String toString(String indent) { - StringBuilder builder = new StringBuilder(); - builder.append(indent).append(this.getClass().getSimpleName()); - if (hasNewLineFlag()) { - builder.append("[Li]"); - } - builder.append('\n'); - for (Node child : childNodes()) { - if (child != null) { - builder.append(child.toString(indent + " ")); - } - } - return builder.toString(); - } + protected abstract String toString(String indent); } public static final class CallNodeFlags implements Comparable { @@ -191,6 +180,79 @@ public boolean isVariableCall() { } + public static final class IntegerBaseFlags implements Comparable { + + // 0b prefix + public static final short BINARY = 1 << 0; + + // 0o or 0 prefix + public static final short OCTAL = 1 << 1; + + // 0d or no prefix + public static final short DECIMAL = 1 << 2; + + // 0x prefix + public static final short HEXADECIMAL = 1 << 3; + + public static boolean isBinary(short flags) { + return (flags & BINARY) != 0; + } + + public static boolean isOctal(short flags) { + return (flags & OCTAL) != 0; + } + + public static boolean isDecimal(short flags) { + return (flags & DECIMAL) != 0; + } + + public static boolean isHexadecimal(short flags) { + return (flags & HEXADECIMAL) != 0; + } + + private final short flags; + + public IntegerBaseFlags(short flags) { + this.flags = flags; + } + + @Override + public int hashCode() { + return flags; + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof IntegerBaseFlags)) { + return false; + } + + return flags == ((IntegerBaseFlags) other).flags; + } + + @Override + public int compareTo(IntegerBaseFlags other) { + return flags - other.flags; + } + + public boolean isBinary() { + return (flags & BINARY) != 0; + } + + public boolean isOctal() { + return (flags & OCTAL) != 0; + } + + public boolean isDecimal() { + return (flags & DECIMAL) != 0; + } + + public boolean isHexadecimal() { + return (flags & HEXADECIMAL) != 0; + } + + } + public static final class LoopFlags implements Comparable { // a loop after a begin statement, so the body is executed first before the condition @@ -276,11 +338,11 @@ public static final class RegularExpressionFlags implements Comparable { + + // frozen by virtue of a frozen_string_literal comment + public static final short FROZEN = 1 << 0; + + public static boolean isFrozen(short flags) { + return (flags & FROZEN) != 0; + } + + private final short flags; + + public StringFlags(short flags) { + this.flags = flags; + } + + @Override + public int hashCode() { + return flags; + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof StringFlags)) { + return false; + } + + return flags == ((StringFlags) other).flags; + } + + @Override + public int compareTo(StringFlags other) { + return flags - other.flags; + } + + public boolean isFrozen() { + return (flags & FROZEN) != 0; + } + + } + + // Represents the use of the `alias` keyword to alias a global variable. + // + // alias $foo $bar + // ^^^^^^^^^^^^^^^ + public static final class AliasGlobalVariableNode extends Node { + public final Node new_name; + public final Node old_name; + + public AliasGlobalVariableNode(Node new_name, Node old_name, int startOffset, int length) { + super(startOffset, length); + this.new_name = new_name; + this.old_name = old_name; + } + + public void visitChildNodes(AbstractNodeVisitor visitor) { + this.new_name.accept(visitor); + this.old_name.accept(visitor); + } + + public Node[] childNodes() { + return new Node[] { this.new_name, this.old_name }; + } + + public T accept(AbstractNodeVisitor visitor) { + return visitor.visitAliasGlobalVariableNode(this); + } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("new_name: "); + builder.append(this.new_name.toString(nextIndent)); + builder.append(nextIndent); + builder.append("old_name: "); + builder.append(this.old_name.toString(nextIndent)); + return builder.toString(); + } + } + + // Represents the use of the `alias` keyword to alias a method. // // alias foo bar // ^^^^^^^^^^^^^ - public static final class AliasNode extends Node { + public static final class AliasMethodNode extends Node { public final Node new_name; public final Node old_name; - public final Location keyword_loc; - public AliasNode(Node new_name, Node old_name, Location keyword_loc, int startOffset, int length) { + public AliasMethodNode(Node new_name, Node old_name, int startOffset, int length) { super(startOffset, length); this.new_name = new_name; this.old_name = old_name; - this.keyword_loc = keyword_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -414,7 +560,25 @@ public Node[] childNodes() { } public T accept(AbstractNodeVisitor visitor) { - return visitor.visitAliasNode(this); + return visitor.visitAliasMethodNode(this); + } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("new_name: "); + builder.append(this.new_name.toString(nextIndent)); + builder.append(nextIndent); + builder.append("old_name: "); + builder.append(this.old_name.toString(nextIndent)); + return builder.toString(); } } @@ -425,13 +589,11 @@ public T accept(AbstractNodeVisitor visitor) { public static final class AlternationPatternNode extends Node { public final Node left; public final Node right; - public final Location operator_loc; - public AlternationPatternNode(Node left, Node right, Location operator_loc, int startOffset, int length) { + public AlternationPatternNode(Node left, Node right, int startOffset, int length) { super(startOffset, length); this.left = left; this.right = right; - this.operator_loc = operator_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -446,6 +608,24 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitAlternationPatternNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("left: "); + builder.append(this.left.toString(nextIndent)); + builder.append(nextIndent); + builder.append("right: "); + builder.append(this.right.toString(nextIndent)); + return builder.toString(); + } } // Represents the use of the `&&` operator or the `and` keyword. @@ -455,13 +635,11 @@ public T accept(AbstractNodeVisitor visitor) { public static final class AndNode extends Node { public final Node left; public final Node right; - public final Location operator_loc; - public AndNode(Node left, Node right, Location operator_loc, int startOffset, int length) { + public AndNode(Node left, Node right, int startOffset, int length) { super(startOffset, length); this.left = left; this.right = right; - this.operator_loc = operator_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -476,6 +654,24 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitAndNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("left: "); + builder.append(this.left.toString(nextIndent)); + builder.append(nextIndent); + builder.append("right: "); + builder.append(this.right.toString(nextIndent)); + return builder.toString(); + } } // Represents a set of arguments to a method or a keyword. @@ -503,6 +699,25 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitArgumentsNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + String nextNextIndent = nextIndent + " "; + builder.append(nextIndent); + builder.append("arguments: "); + builder.append('\n'); + for (Node child : this.arguments) { + builder.append(nextNextIndent).append(child.toString(nextNextIndent)); + } + return builder.toString(); + } } // Represents an array literal. This can be a regular array using brackets or @@ -512,16 +727,10 @@ public T accept(AbstractNodeVisitor visitor) { // ^^^^^^^^^ public static final class ArrayNode extends Node { public final Node[] elements; - /** optional (can be null) */ - public final Location opening_loc; - /** optional (can be null) */ - public final Location closing_loc; - public ArrayNode(Node[] elements, Location opening_loc, Location closing_loc, int startOffset, int length) { + public ArrayNode(Node[] elements, int startOffset, int length) { super(startOffset, length); this.elements = elements; - this.opening_loc = opening_loc; - this.closing_loc = closing_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -537,6 +746,25 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitArrayNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + String nextNextIndent = nextIndent + " "; + builder.append(nextIndent); + builder.append("elements: "); + builder.append('\n'); + for (Node child : this.elements) { + builder.append(nextNextIndent).append(child.toString(nextNextIndent)); + } + return builder.toString(); + } } // Represents an array pattern in pattern matching. @@ -562,19 +790,13 @@ public static final class ArrayPatternNode extends Node { /** optional (can be null) */ public final Node rest; public final Node[] posts; - /** optional (can be null) */ - public final Location opening_loc; - /** optional (can be null) */ - public final Location closing_loc; - public ArrayPatternNode(Node constant, Node[] requireds, Node rest, Node[] posts, Location opening_loc, Location closing_loc, int startOffset, int length) { + public ArrayPatternNode(Node constant, Node[] requireds, Node rest, Node[] posts, int startOffset, int length) { super(startOffset, length); this.constant = constant; this.requireds = requireds; this.rest = rest; this.posts = posts; - this.opening_loc = opening_loc; - this.closing_loc = closing_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -604,6 +826,37 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitArrayPatternNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + String nextNextIndent = nextIndent + " "; + builder.append(nextIndent); + builder.append("constant: "); + builder.append(this.constant == null ? "null\n" : this.constant.toString(nextIndent)); + builder.append(nextIndent); + builder.append("requireds: "); + builder.append('\n'); + for (Node child : this.requireds) { + builder.append(nextNextIndent).append(child.toString(nextNextIndent)); + } + builder.append(nextIndent); + builder.append("rest: "); + builder.append(this.rest == null ? "null\n" : this.rest.toString(nextIndent)); + builder.append(nextIndent); + builder.append("posts: "); + builder.append('\n'); + for (Node child : this.posts) { + builder.append(nextNextIndent).append(child.toString(nextNextIndent)); + } + return builder.toString(); + } } // Represents a hash key/value pair. @@ -614,14 +867,11 @@ public static final class AssocNode extends Node { public final Node key; /** optional (can be null) */ public final Node value; - /** optional (can be null) */ - public final Location operator_loc; - public AssocNode(Node key, Node value, Location operator_loc, int startOffset, int length) { + public AssocNode(Node key, Node value, int startOffset, int length) { super(startOffset, length); this.key = key; this.value = value; - this.operator_loc = operator_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -638,6 +888,24 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitAssocNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("key: "); + builder.append(this.key.toString(nextIndent)); + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value == null ? "null\n" : this.value.toString(nextIndent)); + return builder.toString(); + } } // Represents a splat in a hash literal. @@ -647,12 +915,10 @@ public T accept(AbstractNodeVisitor visitor) { public static final class AssocSplatNode extends Node { /** optional (can be null) */ public final Node value; - public final Location operator_loc; - public AssocSplatNode(Node value, Location operator_loc, int startOffset, int length) { + public AssocSplatNode(Node value, int startOffset, int length) { super(startOffset, length); this.value = value; - this.operator_loc = operator_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -668,6 +934,21 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitAssocSplatNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value == null ? "null\n" : this.value.toString(nextIndent)); + return builder.toString(); + } } // Represents reading a reference to a field in the previous match. @@ -690,6 +971,18 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitBackReferenceReadNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + return builder.toString(); + } } // Represents a begin statement. @@ -699,8 +992,6 @@ public T accept(AbstractNodeVisitor visitor) { // end // ^^^^^ public static final class BeginNode extends Node { - /** optional (can be null) */ - public final Location begin_keyword_loc; /** optional (can be null) */ public final StatementsNode statements; /** optional (can be null) */ @@ -709,17 +1000,13 @@ public static final class BeginNode extends Node { public final ElseNode else_clause; /** optional (can be null) */ public final EnsureNode ensure_clause; - /** optional (can be null) */ - public final Location end_keyword_loc; - public BeginNode(Location begin_keyword_loc, StatementsNode statements, RescueNode rescue_clause, ElseNode else_clause, EnsureNode ensure_clause, Location end_keyword_loc, int startOffset, int length) { + public BeginNode(StatementsNode statements, RescueNode rescue_clause, ElseNode else_clause, EnsureNode ensure_clause, int startOffset, int length) { super(startOffset, length); - this.begin_keyword_loc = begin_keyword_loc; this.statements = statements; this.rescue_clause = rescue_clause; this.else_clause = else_clause; this.ensure_clause = ensure_clause; - this.end_keyword_loc = end_keyword_loc; } @Override @@ -749,6 +1036,30 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitBeginNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("statements: "); + builder.append(this.statements == null ? "null\n" : this.statements.toString(nextIndent)); + builder.append(nextIndent); + builder.append("rescue_clause: "); + builder.append(this.rescue_clause == null ? "null\n" : this.rescue_clause.toString(nextIndent)); + builder.append(nextIndent); + builder.append("else_clause: "); + builder.append(this.else_clause == null ? "null\n" : this.else_clause.toString(nextIndent)); + builder.append(nextIndent); + builder.append("ensure_clause: "); + builder.append(this.ensure_clause == null ? "null\n" : this.ensure_clause.toString(nextIndent)); + return builder.toString(); + } } // Represents block method arguments. @@ -758,12 +1069,10 @@ public T accept(AbstractNodeVisitor visitor) { public static final class BlockArgumentNode extends Node { /** optional (can be null) */ public final Node expression; - public final Location operator_loc; - public BlockArgumentNode(Node expression, Location operator_loc, int startOffset, int length) { + public BlockArgumentNode(Node expression, int startOffset, int length) { super(startOffset, length); this.expression = expression; - this.operator_loc = operator_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -779,28 +1088,79 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitBlockArgumentNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("expression: "); + builder.append(this.expression == null ? "null\n" : this.expression.toString(nextIndent)); + return builder.toString(); + } } - // Represents a block of ruby code. + // Represents a block local variable. // - // [1, 2, 3].each { |i| puts x } - // ^^^^^^^^^^^^^^ - public static final class BlockNode extends Node { - public final byte[][] locals; + // a { |; b| } + // ^ + public static final class BlockLocalVariableNode extends Node { + public final String name; + + public BlockLocalVariableNode(String name, int startOffset, int length) { + super(startOffset, length); + this.name = name; + } + + public void visitChildNodes(AbstractNodeVisitor visitor) { + } + + public Node[] childNodes() { + return EMPTY_ARRAY; + } + + public T accept(AbstractNodeVisitor visitor) { + return visitor.visitBlockLocalVariableNode(this); + } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + return builder.toString(); + } + } + + // Represents a block of ruby code. + // + // [1, 2, 3].each { |i| puts x } + // ^^^^^^^^^^^^^^ + public static final class BlockNode extends Node { + public final String[] locals; /** optional (can be null) */ public final BlockParametersNode parameters; /** optional (can be null) */ public final Node body; - public final Location opening_loc; - public final Location closing_loc; - public BlockNode(byte[][] locals, BlockParametersNode parameters, Node body, Location opening_loc, Location closing_loc, int startOffset, int length) { + public BlockNode(String[] locals, BlockParametersNode parameters, Node body, int startOffset, int length) { super(startOffset, length); this.locals = locals; this.parameters = parameters; this.body = body; - this.opening_loc = opening_loc; - this.closing_loc = closing_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -819,6 +1179,31 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitBlockNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + String nextNextIndent = nextIndent + " "; + builder.append(nextIndent); + builder.append("locals: "); + builder.append('\n'); + for (String constant : this.locals) { + builder.append(nextNextIndent).append('"').append(constant).append('"').append('\n'); + } + builder.append(nextIndent); + builder.append("parameters: "); + builder.append(this.parameters == null ? "null\n" : this.parameters.toString(nextIndent)); + builder.append(nextIndent); + builder.append("body: "); + builder.append(this.body == null ? "null\n" : this.body.toString(nextIndent)); + return builder.toString(); + } } // Represents a block parameter to a method, block, or lambda definition. @@ -828,13 +1213,11 @@ public T accept(AbstractNodeVisitor visitor) { // end public static final class BlockParameterNode extends Node { /** optional (can be null) */ - public final Location name_loc; - public final Location operator_loc; + public final String name; - public BlockParameterNode(Location name_loc, Location operator_loc, int startOffset, int length) { + public BlockParameterNode(String name, int startOffset, int length) { super(startOffset, length); - this.name_loc = name_loc; - this.operator_loc = operator_loc; + this.name = name; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -847,6 +1230,22 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitBlockParameterNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append(this.name == null ? "null" : "\"" + this.name + "\""); + builder.append('\n'); + return builder.toString(); + } } // Represents a block's parameters declaration. @@ -860,33 +1259,55 @@ public T accept(AbstractNodeVisitor visitor) { public static final class BlockParametersNode extends Node { /** optional (can be null) */ public final ParametersNode parameters; - public final Location[] locals; - /** optional (can be null) */ - public final Location opening_loc; - /** optional (can be null) */ - public final Location closing_loc; + public final Node[] locals; - public BlockParametersNode(ParametersNode parameters, Location[] locals, Location opening_loc, Location closing_loc, int startOffset, int length) { + public BlockParametersNode(ParametersNode parameters, Node[] locals, int startOffset, int length) { super(startOffset, length); this.parameters = parameters; this.locals = locals; - this.opening_loc = opening_loc; - this.closing_loc = closing_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { if (this.parameters != null) { this.parameters.accept(visitor); } + for (Nodes.Node child : this.locals) { + child.accept(visitor); + } } public Node[] childNodes() { - return new Node[] { this.parameters }; + ArrayList childNodes = new ArrayList<>(); + childNodes.add(this.parameters); + childNodes.addAll(Arrays.asList(this.locals)); + return childNodes.toArray(EMPTY_ARRAY); } public T accept(AbstractNodeVisitor visitor) { return visitor.visitBlockParametersNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + String nextNextIndent = nextIndent + " "; + builder.append(nextIndent); + builder.append("parameters: "); + builder.append(this.parameters == null ? "null\n" : this.parameters.toString(nextIndent)); + builder.append(nextIndent); + builder.append("locals: "); + builder.append('\n'); + for (Node child : this.locals) { + builder.append(nextNextIndent).append(child.toString(nextNextIndent)); + } + return builder.toString(); + } } // Represents the use of the `break` keyword. @@ -896,12 +1317,10 @@ public T accept(AbstractNodeVisitor visitor) { public static final class BreakNode extends Node { /** optional (can be null) */ public final ArgumentsNode arguments; - public final Location keyword_loc; - public BreakNode(ArgumentsNode arguments, Location keyword_loc, int startOffset, int length) { + public BreakNode(ArgumentsNode arguments, int startOffset, int length) { super(startOffset, length); this.arguments = arguments; - this.keyword_loc = keyword_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -917,6 +1336,105 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitBreakNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("arguments: "); + builder.append(this.arguments == null ? "null\n" : this.arguments.toString(nextIndent)); + return builder.toString(); + } + } + + // Represents the use of the `&&=` operator on a call. + // + // foo.bar &&= value + // ^^^^^^^^^^^^^^^^^ + public static final class CallAndWriteNode extends Node { + /** optional (can be null) */ + public final Node receiver; + /** optional (can be null) */ + public final ArgumentsNode arguments; + public final short flags; + public final byte[] read_name; + public final byte[] write_name; + public final Node value; + + public CallAndWriteNode(Node receiver, ArgumentsNode arguments, short flags, byte[] read_name, byte[] write_name, Node value, int startOffset, int length) { + super(startOffset, length); + this.receiver = receiver; + this.arguments = arguments; + this.flags = flags; + this.read_name = read_name; + this.write_name = write_name; + this.value = value; + } + + public boolean isSafeNavigation() { + return CallNodeFlags.isSafeNavigation(this.flags); + } + + public boolean isVariableCall() { + return CallNodeFlags.isVariableCall(this.flags); + } + + public void visitChildNodes(AbstractNodeVisitor visitor) { + if (this.receiver != null) { + this.receiver.accept(visitor); + } + if (this.arguments != null) { + this.arguments.accept(visitor); + } + this.value.accept(visitor); + } + + public Node[] childNodes() { + return new Node[] { this.receiver, this.arguments, this.value }; + } + + public T accept(AbstractNodeVisitor visitor) { + return visitor.visitCallAndWriteNode(this); + } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("receiver: "); + builder.append(this.receiver == null ? "null\n" : this.receiver.toString(nextIndent)); + builder.append(nextIndent); + builder.append("arguments: "); + builder.append(this.arguments == null ? "null\n" : this.arguments.toString(nextIndent)); + builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + builder.append(nextIndent); + builder.append("read_name: "); + builder.append('"' + new String(this.read_name, StandardCharsets.UTF_8) + '"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("write_name: "); + builder.append('"' + new String(this.write_name, StandardCharsets.UTF_8) + '"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + return builder.toString(); + } } // Represents a method call, in all of the various forms that can take. @@ -942,28 +1460,16 @@ public static final class CallNode extends Node { /** optional (can be null) */ public final Node receiver; /** optional (can be null) */ - public final Location operator_loc; - /** optional (can be null) */ - public final Location message_loc; - /** optional (can be null) */ - public final Location opening_loc; - /** optional (can be null) */ public final ArgumentsNode arguments; /** optional (can be null) */ - public final Location closing_loc; - /** optional (can be null) */ - public final BlockNode block; + public final Node block; public final short flags; public final byte[] name; - public CallNode(Node receiver, Location operator_loc, Location message_loc, Location opening_loc, ArgumentsNode arguments, Location closing_loc, BlockNode block, short flags, byte[] name, int startOffset, int length) { + public CallNode(Node receiver, ArgumentsNode arguments, Node block, short flags, byte[] name, int startOffset, int length) { super(startOffset, length); this.receiver = receiver; - this.operator_loc = operator_loc; - this.message_loc = message_loc; - this.opening_loc = opening_loc; this.arguments = arguments; - this.closing_loc = closing_loc; this.block = block; this.flags = flags; this.name = name; @@ -996,35 +1502,124 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitCallNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("receiver: "); + builder.append(this.receiver == null ? "null\n" : this.receiver.toString(nextIndent)); + builder.append(nextIndent); + builder.append("arguments: "); + builder.append(this.arguments == null ? "null\n" : this.arguments.toString(nextIndent)); + builder.append(nextIndent); + builder.append("block: "); + builder.append(this.block == null ? "null\n" : this.block.toString(nextIndent)); + builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + builder.append(nextIndent); + builder.append("name: "); + builder.append('"' + new String(this.name, StandardCharsets.UTF_8) + '"'); + builder.append('\n'); + return builder.toString(); + } } - // Represents the use of the `&&=` operator on a call. + // Represents the use of an assignment operator on a call. // - // foo.bar &&= value - // ^^^^^^^^^^^^^^^^^ - public static final class CallOperatorAndWriteNode extends Node { - public final CallNode target; - public final Location operator_loc; + // foo.bar += baz + // ^^^^^^^^^^^^^^ + public static final class CallOperatorWriteNode extends Node { + /** optional (can be null) */ + public final Node receiver; + /** optional (can be null) */ + public final ArgumentsNode arguments; + public final short flags; + public final byte[] read_name; + public final byte[] write_name; + public final String operator; public final Node value; - public CallOperatorAndWriteNode(CallNode target, Location operator_loc, Node value, int startOffset, int length) { + public CallOperatorWriteNode(Node receiver, ArgumentsNode arguments, short flags, byte[] read_name, byte[] write_name, String operator, Node value, int startOffset, int length) { super(startOffset, length); - this.target = target; - this.operator_loc = operator_loc; + this.receiver = receiver; + this.arguments = arguments; + this.flags = flags; + this.read_name = read_name; + this.write_name = write_name; + this.operator = operator; this.value = value; } - + + public boolean isSafeNavigation() { + return CallNodeFlags.isSafeNavigation(this.flags); + } + + public boolean isVariableCall() { + return CallNodeFlags.isVariableCall(this.flags); + } + public void visitChildNodes(AbstractNodeVisitor visitor) { - this.target.accept(visitor); + if (this.receiver != null) { + this.receiver.accept(visitor); + } + if (this.arguments != null) { + this.arguments.accept(visitor); + } this.value.accept(visitor); } public Node[] childNodes() { - return new Node[] { this.target, this.value }; + return new Node[] { this.receiver, this.arguments, this.value }; } public T accept(AbstractNodeVisitor visitor) { - return visitor.visitCallOperatorAndWriteNode(this); + return visitor.visitCallOperatorWriteNode(this); + } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("receiver: "); + builder.append(this.receiver == null ? "null\n" : this.receiver.toString(nextIndent)); + builder.append(nextIndent); + builder.append("arguments: "); + builder.append(this.arguments == null ? "null\n" : this.arguments.toString(nextIndent)); + builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + builder.append(nextIndent); + builder.append("read_name: "); + builder.append('"' + new String(this.read_name, StandardCharsets.UTF_8) + '"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("write_name: "); + builder.append('"' + new String(this.write_name, StandardCharsets.UTF_8) + '"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("operator: "); + builder.append('"').append(this.operator).append('"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + return builder.toString(); } } @@ -1032,61 +1627,83 @@ public T accept(AbstractNodeVisitor visitor) { // // foo.bar ||= value // ^^^^^^^^^^^^^^^^^ - public static final class CallOperatorOrWriteNode extends Node { - public final CallNode target; + public static final class CallOrWriteNode extends Node { + /** optional (can be null) */ + public final Node receiver; + /** optional (can be null) */ + public final ArgumentsNode arguments; + public final short flags; + public final byte[] read_name; + public final byte[] write_name; public final Node value; - public final Location operator_loc; - public CallOperatorOrWriteNode(CallNode target, Node value, Location operator_loc, int startOffset, int length) { + public CallOrWriteNode(Node receiver, ArgumentsNode arguments, short flags, byte[] read_name, byte[] write_name, Node value, int startOffset, int length) { super(startOffset, length); - this.target = target; + this.receiver = receiver; + this.arguments = arguments; + this.flags = flags; + this.read_name = read_name; + this.write_name = write_name; this.value = value; - this.operator_loc = operator_loc; - } - - public void visitChildNodes(AbstractNodeVisitor visitor) { - this.target.accept(visitor); - this.value.accept(visitor); } - - public Node[] childNodes() { - return new Node[] { this.target, this.value }; + + public boolean isSafeNavigation() { + return CallNodeFlags.isSafeNavigation(this.flags); } - public T accept(AbstractNodeVisitor visitor) { - return visitor.visitCallOperatorOrWriteNode(this); - } - } - - // Represents the use of an assignment operator on a call. - // - // foo.bar += baz - // ^^^^^^^^^^^^^^ - public static final class CallOperatorWriteNode extends Node { - public final CallNode target; - public final Location operator_loc; - public final Node value; - public final byte[] operator; - - public CallOperatorWriteNode(CallNode target, Location operator_loc, Node value, byte[] operator, int startOffset, int length) { - super(startOffset, length); - this.target = target; - this.operator_loc = operator_loc; - this.value = value; - this.operator = operator; + public boolean isVariableCall() { + return CallNodeFlags.isVariableCall(this.flags); } - + public void visitChildNodes(AbstractNodeVisitor visitor) { - this.target.accept(visitor); + if (this.receiver != null) { + this.receiver.accept(visitor); + } + if (this.arguments != null) { + this.arguments.accept(visitor); + } this.value.accept(visitor); } public Node[] childNodes() { - return new Node[] { this.target, this.value }; + return new Node[] { this.receiver, this.arguments, this.value }; } public T accept(AbstractNodeVisitor visitor) { - return visitor.visitCallOperatorWriteNode(this); + return visitor.visitCallOrWriteNode(this); + } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("receiver: "); + builder.append(this.receiver == null ? "null\n" : this.receiver.toString(nextIndent)); + builder.append(nextIndent); + builder.append("arguments: "); + builder.append(this.arguments == null ? "null\n" : this.arguments.toString(nextIndent)); + builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + builder.append(nextIndent); + builder.append("read_name: "); + builder.append('"' + new String(this.read_name, StandardCharsets.UTF_8) + '"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("write_name: "); + builder.append('"' + new String(this.write_name, StandardCharsets.UTF_8) + '"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + return builder.toString(); } } @@ -1097,13 +1714,11 @@ public T accept(AbstractNodeVisitor visitor) { public static final class CapturePatternNode extends Node { public final Node value; public final Node target; - public final Location operator_loc; - public CapturePatternNode(Node value, Node target, Location operator_loc, int startOffset, int length) { + public CapturePatternNode(Node value, Node target, int startOffset, int length) { super(startOffset, length); this.value = value; this.target = target; - this.operator_loc = operator_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -1118,6 +1733,24 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitCapturePatternNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + builder.append(nextIndent); + builder.append("target: "); + builder.append(this.target.toString(nextIndent)); + return builder.toString(); + } } // Represents the use of a case statement. @@ -1132,16 +1765,12 @@ public static final class CaseNode extends Node { public final Node[] conditions; /** optional (can be null) */ public final ElseNode consequent; - public final Location case_keyword_loc; - public final Location end_keyword_loc; - public CaseNode(Node predicate, Node[] conditions, ElseNode consequent, Location case_keyword_loc, Location end_keyword_loc, int startOffset, int length) { + public CaseNode(Node predicate, Node[] conditions, ElseNode consequent, int startOffset, int length) { super(startOffset, length); this.predicate = predicate; this.conditions = conditions; this.consequent = consequent; - this.case_keyword_loc = case_keyword_loc; - this.end_keyword_loc = end_keyword_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -1167,6 +1796,31 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitCaseNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + String nextNextIndent = nextIndent + " "; + builder.append(nextIndent); + builder.append("predicate: "); + builder.append(this.predicate == null ? "null\n" : this.predicate.toString(nextIndent)); + builder.append(nextIndent); + builder.append("conditions: "); + builder.append('\n'); + for (Node child : this.conditions) { + builder.append(nextNextIndent).append(child.toString(nextNextIndent)); + } + builder.append(nextIndent); + builder.append("consequent: "); + builder.append(this.consequent == null ? "null\n" : this.consequent.toString(nextIndent)); + return builder.toString(); + } } // Represents a class declaration involving the `class` keyword. @@ -1174,27 +1828,20 @@ public T accept(AbstractNodeVisitor visitor) { // class Foo end // ^^^^^^^^^^^^^ public static final class ClassNode extends Node { - public final byte[][] locals; - public final Location class_keyword_loc; + public final String[] locals; public final Node constant_path; /** optional (can be null) */ - public final Location inheritance_operator_loc; - /** optional (can be null) */ public final Node superclass; /** optional (can be null) */ public final Node body; - public final Location end_keyword_loc; - public final byte[] name; + public final String name; - public ClassNode(byte[][] locals, Location class_keyword_loc, Node constant_path, Location inheritance_operator_loc, Node superclass, Node body, Location end_keyword_loc, byte[] name, int startOffset, int length) { + public ClassNode(String[] locals, Node constant_path, Node superclass, Node body, String name, int startOffset, int length) { super(startOffset, length); this.locals = locals; - this.class_keyword_loc = class_keyword_loc; this.constant_path = constant_path; - this.inheritance_operator_loc = inheritance_operator_loc; this.superclass = superclass; this.body = body; - this.end_keyword_loc = end_keyword_loc; this.name = name; } @@ -1215,6 +1862,38 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitClassNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + String nextNextIndent = nextIndent + " "; + builder.append(nextIndent); + builder.append("locals: "); + builder.append('\n'); + for (String constant : this.locals) { + builder.append(nextNextIndent).append('"').append(constant).append('"').append('\n'); + } + builder.append(nextIndent); + builder.append("constant_path: "); + builder.append(this.constant_path.toString(nextIndent)); + builder.append(nextIndent); + builder.append("superclass: "); + builder.append(this.superclass == null ? "null\n" : this.superclass.toString(nextIndent)); + builder.append(nextIndent); + builder.append("body: "); + builder.append(this.body == null ? "null\n" : this.body.toString(nextIndent)); + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + return builder.toString(); + } } // Represents the use of the `&&=` operator for assignment to a class variable. @@ -1222,16 +1901,12 @@ public T accept(AbstractNodeVisitor visitor) { // @@target &&= value // ^^^^^^^^^^^^^^^^ public static final class ClassVariableAndWriteNode extends Node { - public final byte[] name; - public final Location name_loc; - public final Location operator_loc; + public final String name; public final Node value; - public ClassVariableAndWriteNode(byte[] name, Location name_loc, Location operator_loc, Node value, int startOffset, int length) { + public ClassVariableAndWriteNode(String name, Node value, int startOffset, int length) { super(startOffset, length); this.name = name; - this.name_loc = name_loc; - this.operator_loc = operator_loc; this.value = value; } @@ -1246,6 +1921,25 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitClassVariableAndWriteNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + return builder.toString(); + } } // Represents assigning to a class variable using an operator that isn't `=`. @@ -1253,17 +1947,13 @@ public T accept(AbstractNodeVisitor visitor) { // @@target += value // ^^^^^^^^^^^^^^^^^ public static final class ClassVariableOperatorWriteNode extends Node { - public final byte[] name; - public final Location name_loc; - public final Location operator_loc; + public final String name; public final Node value; - public final byte[] operator; + public final String operator; - public ClassVariableOperatorWriteNode(byte[] name, Location name_loc, Location operator_loc, Node value, byte[] operator, int startOffset, int length) { + public ClassVariableOperatorWriteNode(String name, Node value, String operator, int startOffset, int length) { super(startOffset, length); this.name = name; - this.name_loc = name_loc; - this.operator_loc = operator_loc; this.value = value; this.operator = operator; } @@ -1279,6 +1969,29 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitClassVariableOperatorWriteNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + builder.append(nextIndent); + builder.append("operator: "); + builder.append('"').append(this.operator).append('"'); + builder.append('\n'); + return builder.toString(); + } } // Represents the use of the `||=` operator for assignment to a class variable. @@ -1286,16 +1999,12 @@ public T accept(AbstractNodeVisitor visitor) { // @@target ||= value // ^^^^^^^^^^^^^^^^^^ public static final class ClassVariableOrWriteNode extends Node { - public final byte[] name; - public final Location name_loc; - public final Location operator_loc; + public final String name; public final Node value; - public ClassVariableOrWriteNode(byte[] name, Location name_loc, Location operator_loc, Node value, int startOffset, int length) { + public ClassVariableOrWriteNode(String name, Node value, int startOffset, int length) { super(startOffset, length); this.name = name; - this.name_loc = name_loc; - this.operator_loc = operator_loc; this.value = value; } @@ -1310,6 +2019,25 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitClassVariableOrWriteNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + return builder.toString(); + } } // Represents referencing a class variable. @@ -1317,9 +2045,9 @@ public T accept(AbstractNodeVisitor visitor) { // @@foo // ^^^^^ public static final class ClassVariableReadNode extends Node { - public final byte[] name; + public final String name; - public ClassVariableReadNode(byte[] name, int startOffset, int length) { + public ClassVariableReadNode(String name, int startOffset, int length) { super(startOffset, length); this.name = name; } @@ -1334,6 +2062,22 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitClassVariableReadNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + return builder.toString(); + } } // Represents writing to a class variable in a context that doesn't have an explicit value. @@ -1341,9 +2085,9 @@ public T accept(AbstractNodeVisitor visitor) { // @@foo, @@bar = baz // ^^^^^ ^^^^^ public static final class ClassVariableTargetNode extends Node { - public final byte[] name; + public final String name; - public ClassVariableTargetNode(byte[] name, int startOffset, int length) { + public ClassVariableTargetNode(String name, int startOffset, int length) { super(startOffset, length); this.name = name; } @@ -1358,6 +2102,22 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitClassVariableTargetNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + return builder.toString(); + } } // Represents writing to a class variable. @@ -1365,25 +2125,17 @@ public T accept(AbstractNodeVisitor visitor) { // @@foo = 1 // ^^^^^^^^^ public static final class ClassVariableWriteNode extends Node { - public final byte[] name; - public final Location name_loc; - /** optional (can be null) */ + public final String name; public final Node value; - /** optional (can be null) */ - public final Location operator_loc; - public ClassVariableWriteNode(byte[] name, Location name_loc, Node value, Location operator_loc, int startOffset, int length) { + public ClassVariableWriteNode(String name, Node value, int startOffset, int length) { super(startOffset, length); this.name = name; - this.name_loc = name_loc; this.value = value; - this.operator_loc = operator_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { - if (this.value != null) { - this.value.accept(visitor); - } + this.value.accept(visitor); } public Node[] childNodes() { @@ -1393,6 +2145,25 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitClassVariableWriteNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + return builder.toString(); + } } // Represents the use of the `&&=` operator for assignment to a constant. @@ -1400,14 +2171,12 @@ public T accept(AbstractNodeVisitor visitor) { // Target &&= value // ^^^^^^^^^^^^^^^^ public static final class ConstantAndWriteNode extends Node { - public final Location name_loc; - public final Location operator_loc; + public final String name; public final Node value; - public ConstantAndWriteNode(Location name_loc, Location operator_loc, Node value, int startOffset, int length) { + public ConstantAndWriteNode(String name, Node value, int startOffset, int length) { super(startOffset, length); - this.name_loc = name_loc; - this.operator_loc = operator_loc; + this.name = name; this.value = value; } @@ -1422,6 +2191,25 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitConstantAndWriteNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + return builder.toString(); + } } // Represents assigning to a constant using an operator that isn't `=`. @@ -1429,15 +2217,13 @@ public T accept(AbstractNodeVisitor visitor) { // Target += value // ^^^^^^^^^^^^^^^ public static final class ConstantOperatorWriteNode extends Node { - public final Location name_loc; - public final Location operator_loc; + public final String name; public final Node value; - public final byte[] operator; + public final String operator; - public ConstantOperatorWriteNode(Location name_loc, Location operator_loc, Node value, byte[] operator, int startOffset, int length) { + public ConstantOperatorWriteNode(String name, Node value, String operator, int startOffset, int length) { super(startOffset, length); - this.name_loc = name_loc; - this.operator_loc = operator_loc; + this.name = name; this.value = value; this.operator = operator; } @@ -1453,6 +2239,29 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitConstantOperatorWriteNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + builder.append(nextIndent); + builder.append("operator: "); + builder.append('"').append(this.operator).append('"'); + builder.append('\n'); + return builder.toString(); + } } // Represents the use of the `||=` operator for assignment to a constant. @@ -1460,14 +2269,12 @@ public T accept(AbstractNodeVisitor visitor) { // Target ||= value // ^^^^^^^^^^^^^^^^ public static final class ConstantOrWriteNode extends Node { - public final Location name_loc; - public final Location operator_loc; + public final String name; public final Node value; - public ConstantOrWriteNode(Location name_loc, Location operator_loc, Node value, int startOffset, int length) { + public ConstantOrWriteNode(String name, Node value, int startOffset, int length) { super(startOffset, length); - this.name_loc = name_loc; - this.operator_loc = operator_loc; + this.name = name; this.value = value; } @@ -1482,6 +2289,25 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitConstantOrWriteNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + return builder.toString(); + } } // Represents the use of the `&&=` operator for assignment to a constant path. @@ -1490,13 +2316,11 @@ public T accept(AbstractNodeVisitor visitor) { // ^^^^^^^^^^^^^^^^^^^^^^^ public static final class ConstantPathAndWriteNode extends Node { public final ConstantPathNode target; - public final Location operator_loc; public final Node value; - public ConstantPathAndWriteNode(ConstantPathNode target, Location operator_loc, Node value, int startOffset, int length) { + public ConstantPathAndWriteNode(ConstantPathNode target, Node value, int startOffset, int length) { super(startOffset, length); this.target = target; - this.operator_loc = operator_loc; this.value = value; } @@ -1512,6 +2336,24 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitConstantPathAndWriteNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("target: "); + builder.append(this.target.toString(nextIndent)); + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + return builder.toString(); + } } // Represents accessing a constant through a path of `::` operators. @@ -1522,13 +2364,11 @@ public static final class ConstantPathNode extends Node { /** optional (can be null) */ public final Node parent; public final Node child; - public final Location delimiter_loc; - public ConstantPathNode(Node parent, Node child, Location delimiter_loc, int startOffset, int length) { + public ConstantPathNode(Node parent, Node child, int startOffset, int length) { super(startOffset, length); this.parent = parent; this.child = child; - this.delimiter_loc = delimiter_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -1545,6 +2385,24 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitConstantPathNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("parent: "); + builder.append(this.parent == null ? "null\n" : this.parent.toString(nextIndent)); + builder.append(nextIndent); + builder.append("child: "); + builder.append(this.child.toString(nextIndent)); + return builder.toString(); + } } // Represents assigning to a constant path using an operator that isn't `=`. @@ -1553,14 +2411,12 @@ public T accept(AbstractNodeVisitor visitor) { // ^^^^^^^^^^^^^^^^^^^^^^ public static final class ConstantPathOperatorWriteNode extends Node { public final ConstantPathNode target; - public final Location operator_loc; public final Node value; - public final byte[] operator; + public final String operator; - public ConstantPathOperatorWriteNode(ConstantPathNode target, Location operator_loc, Node value, byte[] operator, int startOffset, int length) { + public ConstantPathOperatorWriteNode(ConstantPathNode target, Node value, String operator, int startOffset, int length) { super(startOffset, length); this.target = target; - this.operator_loc = operator_loc; this.value = value; this.operator = operator; } @@ -1577,6 +2433,28 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitConstantPathOperatorWriteNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("target: "); + builder.append(this.target.toString(nextIndent)); + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + builder.append(nextIndent); + builder.append("operator: "); + builder.append('"').append(this.operator).append('"'); + builder.append('\n'); + return builder.toString(); + } } // Represents the use of the `||=` operator for assignment to a constant path. @@ -1585,13 +2463,11 @@ public T accept(AbstractNodeVisitor visitor) { // ^^^^^^^^^^^^^^^^^^^^^^^ public static final class ConstantPathOrWriteNode extends Node { public final ConstantPathNode target; - public final Location operator_loc; public final Node value; - public ConstantPathOrWriteNode(ConstantPathNode target, Location operator_loc, Node value, int startOffset, int length) { + public ConstantPathOrWriteNode(ConstantPathNode target, Node value, int startOffset, int length) { super(startOffset, length); this.target = target; - this.operator_loc = operator_loc; this.value = value; } @@ -1607,6 +2483,24 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitConstantPathOrWriteNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("target: "); + builder.append(this.target.toString(nextIndent)); + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + return builder.toString(); + } } // Represents writing to a constant path in a context that doesn't have an explicit value. @@ -1617,13 +2511,11 @@ public static final class ConstantPathTargetNode extends Node { /** optional (can be null) */ public final Node parent; public final Node child; - public final Location delimiter_loc; - public ConstantPathTargetNode(Node parent, Node child, Location delimiter_loc, int startOffset, int length) { + public ConstantPathTargetNode(Node parent, Node child, int startOffset, int length) { super(startOffset, length); this.parent = parent; this.child = child; - this.delimiter_loc = delimiter_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -1640,6 +2532,24 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitConstantPathTargetNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("parent: "); + builder.append(this.parent == null ? "null\n" : this.parent.toString(nextIndent)); + builder.append(nextIndent); + builder.append("child: "); + builder.append(this.child.toString(nextIndent)); + return builder.toString(); + } } // Represents writing to a constant path. @@ -1654,13 +2564,11 @@ public T accept(AbstractNodeVisitor visitor) { // ^^^^^^^^^^^^^^ public static final class ConstantPathWriteNode extends Node { public final ConstantPathNode target; - public final Location operator_loc; public final Node value; - public ConstantPathWriteNode(ConstantPathNode target, Location operator_loc, Node value, int startOffset, int length) { + public ConstantPathWriteNode(ConstantPathNode target, Node value, int startOffset, int length) { super(startOffset, length); this.target = target; - this.operator_loc = operator_loc; this.value = value; } @@ -1676,6 +2584,24 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitConstantPathWriteNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("target: "); + builder.append(this.target.toString(nextIndent)); + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + return builder.toString(); + } } // Represents referencing a constant. @@ -1683,9 +2609,11 @@ public T accept(AbstractNodeVisitor visitor) { // Foo // ^^^ public static final class ConstantReadNode extends Node { + public final String name; - public ConstantReadNode(int startOffset, int length) { + public ConstantReadNode(String name, int startOffset, int length) { super(startOffset, length); + this.name = name; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -1698,6 +2626,22 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitConstantReadNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + return builder.toString(); + } } // Represents writing to a constant in a context that doesn't have an explicit value. @@ -1705,9 +2649,11 @@ public T accept(AbstractNodeVisitor visitor) { // Foo, Bar = baz // ^^^ ^^^ public static final class ConstantTargetNode extends Node { + public final String name; - public ConstantTargetNode(int startOffset, int length) { + public ConstantTargetNode(String name, int startOffset, int length) { super(startOffset, length); + this.name = name; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -1720,6 +2666,22 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitConstantTargetNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + return builder.toString(); + } } // Represents writing to a constant. @@ -1727,15 +2689,13 @@ public T accept(AbstractNodeVisitor visitor) { // Foo = 1 // ^^^^^^^ public static final class ConstantWriteNode extends Node { - public final Location name_loc; + public final String name; public final Node value; - public final Location operator_loc; - public ConstantWriteNode(Location name_loc, Node value, Location operator_loc, int startOffset, int length) { + public ConstantWriteNode(String name, Node value, int startOffset, int length) { super(startOffset, length); - this.name_loc = name_loc; + this.name = name; this.value = value; - this.operator_loc = operator_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -1749,6 +2709,25 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitConstantWriteNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + return builder.toString(); + } } // Represents a method definition. @@ -1758,40 +2737,23 @@ public T accept(AbstractNodeVisitor visitor) { // ^^^^^^^^^^ public static final class DefNode extends Node { public final int serializedLength; - public final Location name_loc; + public final String name; /** optional (can be null) */ public final Node receiver; /** optional (can be null) */ public final ParametersNode parameters; /** optional (can be null) */ public final Node body; - public final byte[][] locals; - public final Location def_keyword_loc; - /** optional (can be null) */ - public final Location operator_loc; - /** optional (can be null) */ - public final Location lparen_loc; - /** optional (can be null) */ - public final Location rparen_loc; - /** optional (can be null) */ - public final Location equal_loc; - /** optional (can be null) */ - public final Location end_keyword_loc; + public final String[] locals; - public DefNode(int serializedLength, Location name_loc, Node receiver, ParametersNode parameters, Node body, byte[][] locals, Location def_keyword_loc, Location operator_loc, Location lparen_loc, Location rparen_loc, Location equal_loc, Location end_keyword_loc, int startOffset, int length) { + public DefNode(int serializedLength, String name, Node receiver, ParametersNode parameters, Node body, String[] locals, int startOffset, int length) { super(startOffset, length); this.serializedLength = serializedLength; - this.name_loc = name_loc; + this.name = name; this.receiver = receiver; this.parameters = parameters; this.body = body; this.locals = locals; - this.def_keyword_loc = def_keyword_loc; - this.operator_loc = operator_loc; - this.lparen_loc = lparen_loc; - this.rparen_loc = rparen_loc; - this.equal_loc = equal_loc; - this.end_keyword_loc = end_keyword_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -1813,6 +2775,38 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitDefNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + String nextNextIndent = nextIndent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("receiver: "); + builder.append(this.receiver == null ? "null\n" : this.receiver.toString(nextIndent)); + builder.append(nextIndent); + builder.append("parameters: "); + builder.append(this.parameters == null ? "null\n" : this.parameters.toString(nextIndent)); + builder.append(nextIndent); + builder.append("body: "); + builder.append(this.body == null ? "null\n" : this.body.toString(nextIndent)); + builder.append(nextIndent); + builder.append("locals: "); + builder.append('\n'); + for (String constant : this.locals) { + builder.append(nextNextIndent).append('"').append(constant).append('"').append('\n'); + } + return builder.toString(); + } } // Represents the use of the `defined?` keyword. @@ -1820,19 +2814,11 @@ public T accept(AbstractNodeVisitor visitor) { // defined?(a) // ^^^^^^^^^^^ public static final class DefinedNode extends Node { - /** optional (can be null) */ - public final Location lparen_loc; public final Node value; - /** optional (can be null) */ - public final Location rparen_loc; - public final Location keyword_loc; - public DefinedNode(Location lparen_loc, Node value, Location rparen_loc, Location keyword_loc, int startOffset, int length) { + public DefinedNode(Node value, int startOffset, int length) { super(startOffset, length); - this.lparen_loc = lparen_loc; this.value = value; - this.rparen_loc = rparen_loc; - this.keyword_loc = keyword_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -1846,6 +2832,21 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitDefinedNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + return builder.toString(); + } } // Represents an `else` clause in a `case`, `if`, or `unless` statement. @@ -1853,17 +2854,12 @@ public T accept(AbstractNodeVisitor visitor) { // if a then b else c end // ^^^^^^^^^^ public static final class ElseNode extends Node { - public final Location else_keyword_loc; /** optional (can be null) */ public final StatementsNode statements; - /** optional (can be null) */ - public final Location end_keyword_loc; - public ElseNode(Location else_keyword_loc, StatementsNode statements, Location end_keyword_loc, int startOffset, int length) { + public ElseNode(StatementsNode statements, int startOffset, int length) { super(startOffset, length); - this.else_keyword_loc = else_keyword_loc; this.statements = statements; - this.end_keyword_loc = end_keyword_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -1879,6 +2875,21 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitElseNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("statements: "); + builder.append(this.statements == null ? "null\n" : this.statements.toString(nextIndent)); + return builder.toString(); + } } // Represents an interpolated set of statements. @@ -1886,16 +2897,12 @@ public T accept(AbstractNodeVisitor visitor) { // "foo #{bar}" // ^^^^^^ public static final class EmbeddedStatementsNode extends Node { - public final Location opening_loc; /** optional (can be null) */ public final StatementsNode statements; - public final Location closing_loc; - public EmbeddedStatementsNode(Location opening_loc, StatementsNode statements, Location closing_loc, int startOffset, int length) { + public EmbeddedStatementsNode(StatementsNode statements, int startOffset, int length) { super(startOffset, length); - this.opening_loc = opening_loc; this.statements = statements; - this.closing_loc = closing_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -1911,6 +2918,21 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitEmbeddedStatementsNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("statements: "); + builder.append(this.statements == null ? "null\n" : this.statements.toString(nextIndent)); + return builder.toString(); + } } // Represents an interpolated variable. @@ -1918,12 +2940,10 @@ public T accept(AbstractNodeVisitor visitor) { // "foo #@bar" // ^^^^^ public static final class EmbeddedVariableNode extends Node { - public final Location operator_loc; public final Node variable; - public EmbeddedVariableNode(Location operator_loc, Node variable, int startOffset, int length) { + public EmbeddedVariableNode(Node variable, int startOffset, int length) { super(startOffset, length); - this.operator_loc = operator_loc; this.variable = variable; } @@ -1938,6 +2958,21 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitEmbeddedVariableNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("variable: "); + builder.append(this.variable.toString(nextIndent)); + return builder.toString(); + } } // Represents an `ensure` clause in a `begin` statement. @@ -1949,16 +2984,12 @@ public T accept(AbstractNodeVisitor visitor) { // bar // end public static final class EnsureNode extends Node { - public final Location ensure_keyword_loc; /** optional (can be null) */ public final StatementsNode statements; - public final Location end_keyword_loc; - public EnsureNode(Location ensure_keyword_loc, StatementsNode statements, Location end_keyword_loc, int startOffset, int length) { + public EnsureNode(StatementsNode statements, int startOffset, int length) { super(startOffset, length); - this.ensure_keyword_loc = ensure_keyword_loc; this.statements = statements; - this.end_keyword_loc = end_keyword_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -1974,6 +3005,21 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitEnsureNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("statements: "); + builder.append(this.statements == null ? "null\n" : this.statements.toString(nextIndent)); + return builder.toString(); + } } // Represents the use of the literal `false` keyword. @@ -1996,6 +3042,18 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitFalseNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + return builder.toString(); + } } // Represents a find pattern in pattern matching. @@ -2014,19 +3072,13 @@ public static final class FindPatternNode extends Node { public final Node left; public final Node[] requireds; public final Node right; - /** optional (can be null) */ - public final Location opening_loc; - /** optional (can be null) */ - public final Location closing_loc; - public FindPatternNode(Node constant, Node left, Node[] requireds, Node right, Location opening_loc, Location closing_loc, int startOffset, int length) { + public FindPatternNode(Node constant, Node left, Node[] requireds, Node right, int startOffset, int length) { super(startOffset, length); this.constant = constant; this.left = left; this.requireds = requireds; this.right = right; - this.opening_loc = opening_loc; - this.closing_loc = closing_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -2052,6 +3104,34 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitFindPatternNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + String nextNextIndent = nextIndent + " "; + builder.append(nextIndent); + builder.append("constant: "); + builder.append(this.constant == null ? "null\n" : this.constant.toString(nextIndent)); + builder.append(nextIndent); + builder.append("left: "); + builder.append(this.left.toString(nextIndent)); + builder.append(nextIndent); + builder.append("requireds: "); + builder.append('\n'); + for (Node child : this.requireds) { + builder.append(nextNextIndent).append(child.toString(nextNextIndent)); + } + builder.append(nextIndent); + builder.append("right: "); + builder.append(this.right.toString(nextIndent)); + return builder.toString(); + } } // Represents the use of the `..` or `...` operators to create flip flops. @@ -2063,14 +3143,12 @@ public static final class FlipFlopNode extends Node { public final Node left; /** optional (can be null) */ public final Node right; - public final Location operator_loc; public final short flags; - public FlipFlopNode(Node left, Node right, Location operator_loc, short flags, int startOffset, int length) { + public FlipFlopNode(Node left, Node right, short flags, int startOffset, int length) { super(startOffset, length); this.left = left; this.right = right; - this.operator_loc = operator_loc; this.flags = flags; } @@ -2094,6 +3172,28 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitFlipFlopNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("left: "); + builder.append(this.left == null ? "null\n" : this.left.toString(nextIndent)); + builder.append(nextIndent); + builder.append("right: "); + builder.append(this.right == null ? "null\n" : this.right.toString(nextIndent)); + builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + return builder.toString(); + } } // Represents a floating point number literal. @@ -2116,6 +3216,18 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitFloatNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + return builder.toString(); + } } // Represents the use of the `for` keyword. @@ -2127,21 +3239,12 @@ public static final class ForNode extends Node { public final Node collection; /** optional (can be null) */ public final StatementsNode statements; - public final Location for_keyword_loc; - public final Location in_keyword_loc; - /** optional (can be null) */ - public final Location do_keyword_loc; - public final Location end_keyword_loc; - public ForNode(Node index, Node collection, StatementsNode statements, Location for_keyword_loc, Location in_keyword_loc, Location do_keyword_loc, Location end_keyword_loc, int startOffset, int length) { + public ForNode(Node index, Node collection, StatementsNode statements, int startOffset, int length) { super(startOffset, length); this.index = index; this.collection = collection; this.statements = statements; - this.for_keyword_loc = for_keyword_loc; - this.in_keyword_loc = in_keyword_loc; - this.do_keyword_loc = do_keyword_loc; - this.end_keyword_loc = end_keyword_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -2159,6 +3262,27 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitForNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("index: "); + builder.append(this.index.toString(nextIndent)); + builder.append(nextIndent); + builder.append("collection: "); + builder.append(this.collection.toString(nextIndent)); + builder.append(nextIndent); + builder.append("statements: "); + builder.append(this.statements == null ? "null\n" : this.statements.toString(nextIndent)); + return builder.toString(); + } } // Represents forwarding all arguments to this method to another method. @@ -2183,6 +3307,18 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitForwardingArgumentsNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + return builder.toString(); + } } // Represents the use of the forwarding parameter in a method, block, or lambda declaration. @@ -2206,6 +3342,18 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitForwardingParameterNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + return builder.toString(); + } } // Represents the use of the `super` keyword without parentheses or arguments. @@ -2234,6 +3382,21 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitForwardingSuperNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("block: "); + builder.append(this.block == null ? "null\n" : this.block.toString(nextIndent)); + return builder.toString(); + } } // Represents the use of the `&&=` operator for assignment to a global variable. @@ -2241,16 +3404,12 @@ public T accept(AbstractNodeVisitor visitor) { // $target &&= value // ^^^^^^^^^^^^^^^^^ public static final class GlobalVariableAndWriteNode extends Node { - public final byte[] name; - public final Location name_loc; - public final Location operator_loc; + public final String name; public final Node value; - public GlobalVariableAndWriteNode(byte[] name, Location name_loc, Location operator_loc, Node value, int startOffset, int length) { + public GlobalVariableAndWriteNode(String name, Node value, int startOffset, int length) { super(startOffset, length); this.name = name; - this.name_loc = name_loc; - this.operator_loc = operator_loc; this.value = value; } @@ -2265,6 +3424,25 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitGlobalVariableAndWriteNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + return builder.toString(); + } } // Represents assigning to a global variable using an operator that isn't `=`. @@ -2272,17 +3450,13 @@ public T accept(AbstractNodeVisitor visitor) { // $target += value // ^^^^^^^^^^^^^^^^ public static final class GlobalVariableOperatorWriteNode extends Node { - public final byte[] name; - public final Location name_loc; - public final Location operator_loc; + public final String name; public final Node value; - public final byte[] operator; + public final String operator; - public GlobalVariableOperatorWriteNode(byte[] name, Location name_loc, Location operator_loc, Node value, byte[] operator, int startOffset, int length) { + public GlobalVariableOperatorWriteNode(String name, Node value, String operator, int startOffset, int length) { super(startOffset, length); this.name = name; - this.name_loc = name_loc; - this.operator_loc = operator_loc; this.value = value; this.operator = operator; } @@ -2298,6 +3472,29 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitGlobalVariableOperatorWriteNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + builder.append(nextIndent); + builder.append("operator: "); + builder.append('"').append(this.operator).append('"'); + builder.append('\n'); + return builder.toString(); + } } // Represents the use of the `||=` operator for assignment to a global variable. @@ -2305,16 +3502,12 @@ public T accept(AbstractNodeVisitor visitor) { // $target ||= value // ^^^^^^^^^^^^^^^^^ public static final class GlobalVariableOrWriteNode extends Node { - public final byte[] name; - public final Location name_loc; - public final Location operator_loc; + public final String name; public final Node value; - public GlobalVariableOrWriteNode(byte[] name, Location name_loc, Location operator_loc, Node value, int startOffset, int length) { + public GlobalVariableOrWriteNode(String name, Node value, int startOffset, int length) { super(startOffset, length); this.name = name; - this.name_loc = name_loc; - this.operator_loc = operator_loc; this.value = value; } @@ -2329,6 +3522,25 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitGlobalVariableOrWriteNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + return builder.toString(); + } } // Represents referencing a global variable. @@ -2336,9 +3548,9 @@ public T accept(AbstractNodeVisitor visitor) { // $foo // ^^^^ public static final class GlobalVariableReadNode extends Node { - public final byte[] name; + public final String name; - public GlobalVariableReadNode(byte[] name, int startOffset, int length) { + public GlobalVariableReadNode(String name, int startOffset, int length) { super(startOffset, length); this.name = name; } @@ -2353,6 +3565,22 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitGlobalVariableReadNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + return builder.toString(); + } } // Represents writing to a global variable in a context that doesn't have an explicit value. @@ -2360,9 +3588,9 @@ public T accept(AbstractNodeVisitor visitor) { // $foo, $bar = baz // ^^^^ ^^^^ public static final class GlobalVariableTargetNode extends Node { - public final byte[] name; + public final String name; - public GlobalVariableTargetNode(byte[] name, int startOffset, int length) { + public GlobalVariableTargetNode(String name, int startOffset, int length) { super(startOffset, length); this.name = name; } @@ -2377,6 +3605,22 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitGlobalVariableTargetNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + return builder.toString(); + } } // Represents writing to a global variable. @@ -2384,17 +3628,13 @@ public T accept(AbstractNodeVisitor visitor) { // $foo = 1 // ^^^^^^^^ public static final class GlobalVariableWriteNode extends Node { - public final byte[] name; - public final Location name_loc; + public final String name; public final Node value; - public final Location operator_loc; - public GlobalVariableWriteNode(byte[] name, Location name_loc, Node value, Location operator_loc, int startOffset, int length) { + public GlobalVariableWriteNode(String name, Node value, int startOffset, int length) { super(startOffset, length); this.name = name; - this.name_loc = name_loc; this.value = value; - this.operator_loc = operator_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -2408,6 +3648,25 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitGlobalVariableWriteNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + return builder.toString(); + } } // Represents a hash literal. @@ -2415,15 +3674,11 @@ public T accept(AbstractNodeVisitor visitor) { // { a => b } // ^^^^^^^^^^ public static final class HashNode extends Node { - public final Location opening_loc; public final Node[] elements; - public final Location closing_loc; - public HashNode(Location opening_loc, Node[] elements, Location closing_loc, int startOffset, int length) { + public HashNode(Node[] elements, int startOffset, int length) { super(startOffset, length); - this.opening_loc = opening_loc; this.elements = elements; - this.closing_loc = closing_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -2439,6 +3694,25 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitHashNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + String nextNextIndent = nextIndent + " "; + builder.append(nextIndent); + builder.append("elements: "); + builder.append('\n'); + for (Node child : this.elements) { + builder.append(nextNextIndent).append(child.toString(nextNextIndent)); + } + return builder.toString(); + } } // Represents a hash pattern in pattern matching. @@ -2454,18 +3728,12 @@ public static final class HashPatternNode extends Node { public final Node[] assocs; /** optional (can be null) */ public final Node kwrest; - /** optional (can be null) */ - public final Location opening_loc; - /** optional (can be null) */ - public final Location closing_loc; - public HashPatternNode(Node constant, Node[] assocs, Node kwrest, Location opening_loc, Location closing_loc, int startOffset, int length) { + public HashPatternNode(Node constant, Node[] assocs, Node kwrest, int startOffset, int length) { super(startOffset, length); this.constant = constant; this.assocs = assocs; this.kwrest = kwrest; - this.opening_loc = opening_loc; - this.closing_loc = closing_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -2491,6 +3759,31 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitHashPatternNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + String nextNextIndent = nextIndent + " "; + builder.append(nextIndent); + builder.append("constant: "); + builder.append(this.constant == null ? "null\n" : this.constant.toString(nextIndent)); + builder.append(nextIndent); + builder.append("assocs: "); + builder.append('\n'); + for (Node child : this.assocs) { + builder.append(nextNextIndent).append(child.toString(nextNextIndent)); + } + builder.append(nextIndent); + builder.append("kwrest: "); + builder.append(this.kwrest == null ? "null\n" : this.kwrest.toString(nextIndent)); + return builder.toString(); + } } // Represents the use of the `if` keyword, either in the block form or the modifier form. @@ -2501,23 +3794,17 @@ public T accept(AbstractNodeVisitor visitor) { // if foo then bar end // ^^^^^^^^^^^^^^^^^^^ public static final class IfNode extends Node { - /** optional (can be null) */ - public final Location if_keyword_loc; public final Node predicate; /** optional (can be null) */ public final StatementsNode statements; /** optional (can be null) */ public final Node consequent; - /** optional (can be null) */ - public final Location end_keyword_loc; - public IfNode(Location if_keyword_loc, Node predicate, StatementsNode statements, Node consequent, Location end_keyword_loc, int startOffset, int length) { + public IfNode(Node predicate, StatementsNode statements, Node consequent, int startOffset, int length) { super(startOffset, length); - this.if_keyword_loc = if_keyword_loc; this.predicate = predicate; this.statements = statements; this.consequent = consequent; - this.end_keyword_loc = end_keyword_loc; } @Override @@ -2542,6 +3829,27 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitIfNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("predicate: "); + builder.append(this.predicate.toString(nextIndent)); + builder.append(nextIndent); + builder.append("statements: "); + builder.append(this.statements == null ? "null\n" : this.statements.toString(nextIndent)); + builder.append(nextIndent); + builder.append("consequent: "); + builder.append(this.consequent == null ? "null\n" : this.consequent.toString(nextIndent)); + return builder.toString(); + } } // Represents an imaginary number literal. @@ -2567,6 +3875,65 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitImaginaryNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("numeric: "); + builder.append(this.numeric.toString(nextIndent)); + return builder.toString(); + } + } + + // Represents a node that is implicitly being added to the tree but doesn't + // correspond directly to a node in the source. + // + // { foo: } + // ^^^^ + // + // { Foo: } + // ^^^^ + public static final class ImplicitNode extends Node { + public final Node value; + + public ImplicitNode(Node value, int startOffset, int length) { + super(startOffset, length); + this.value = value; + } + + public void visitChildNodes(AbstractNodeVisitor visitor) { + this.value.accept(visitor); + } + + public Node[] childNodes() { + return new Node[] { this.value }; + } + + public T accept(AbstractNodeVisitor visitor) { + return visitor.visitImplicitNode(this); + } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + return builder.toString(); + } } // Represents the use of the `in` keyword in a case statement. @@ -2577,16 +3944,11 @@ public static final class InNode extends Node { public final Node pattern; /** optional (can be null) */ public final StatementsNode statements; - public final Location in_loc; - /** optional (can be null) */ - public final Location then_loc; - public InNode(Node pattern, StatementsNode statements, Location in_loc, Location then_loc, int startOffset, int length) { + public InNode(Node pattern, StatementsNode statements, int startOffset, int length) { super(startOffset, length); this.pattern = pattern; this.statements = statements; - this.in_loc = in_loc; - this.then_loc = then_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -2603,6 +3965,24 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitInNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("pattern: "); + builder.append(this.pattern.toString(nextIndent)); + builder.append(nextIndent); + builder.append("statements: "); + builder.append(this.statements == null ? "null\n" : this.statements.toString(nextIndent)); + return builder.toString(); + } } // Represents the use of the `&&=` operator for assignment to an instance variable. @@ -2610,16 +3990,12 @@ public T accept(AbstractNodeVisitor visitor) { // @target &&= value // ^^^^^^^^^^^^^^^^^ public static final class InstanceVariableAndWriteNode extends Node { - public final byte[] name; - public final Location name_loc; - public final Location operator_loc; + public final String name; public final Node value; - public InstanceVariableAndWriteNode(byte[] name, Location name_loc, Location operator_loc, Node value, int startOffset, int length) { + public InstanceVariableAndWriteNode(String name, Node value, int startOffset, int length) { super(startOffset, length); this.name = name; - this.name_loc = name_loc; - this.operator_loc = operator_loc; this.value = value; } @@ -2634,6 +4010,25 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitInstanceVariableAndWriteNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + return builder.toString(); + } } // Represents assigning to an instance variable using an operator that isn't `=`. @@ -2641,17 +4036,13 @@ public T accept(AbstractNodeVisitor visitor) { // @target += value // ^^^^^^^^^^^^^^^^ public static final class InstanceVariableOperatorWriteNode extends Node { - public final byte[] name; - public final Location name_loc; - public final Location operator_loc; + public final String name; public final Node value; - public final byte[] operator; + public final String operator; - public InstanceVariableOperatorWriteNode(byte[] name, Location name_loc, Location operator_loc, Node value, byte[] operator, int startOffset, int length) { + public InstanceVariableOperatorWriteNode(String name, Node value, String operator, int startOffset, int length) { super(startOffset, length); this.name = name; - this.name_loc = name_loc; - this.operator_loc = operator_loc; this.value = value; this.operator = operator; } @@ -2667,6 +4058,29 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitInstanceVariableOperatorWriteNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + builder.append(nextIndent); + builder.append("operator: "); + builder.append('"').append(this.operator).append('"'); + builder.append('\n'); + return builder.toString(); + } } // Represents the use of the `||=` operator for assignment to an instance variable. @@ -2674,16 +4088,12 @@ public T accept(AbstractNodeVisitor visitor) { // @target ||= value // ^^^^^^^^^^^^^^^^^ public static final class InstanceVariableOrWriteNode extends Node { - public final byte[] name; - public final Location name_loc; - public final Location operator_loc; + public final String name; public final Node value; - public InstanceVariableOrWriteNode(byte[] name, Location name_loc, Location operator_loc, Node value, int startOffset, int length) { + public InstanceVariableOrWriteNode(String name, Node value, int startOffset, int length) { super(startOffset, length); this.name = name; - this.name_loc = name_loc; - this.operator_loc = operator_loc; this.value = value; } @@ -2698,6 +4108,25 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitInstanceVariableOrWriteNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + return builder.toString(); + } } // Represents referencing an instance variable. @@ -2705,9 +4134,9 @@ public T accept(AbstractNodeVisitor visitor) { // @foo // ^^^^ public static final class InstanceVariableReadNode extends Node { - public final byte[] name; + public final String name; - public InstanceVariableReadNode(byte[] name, int startOffset, int length) { + public InstanceVariableReadNode(String name, int startOffset, int length) { super(startOffset, length); this.name = name; } @@ -2722,6 +4151,22 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitInstanceVariableReadNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + return builder.toString(); + } } // Represents writing to an instance variable in a context that doesn't have an explicit value. @@ -2729,9 +4174,9 @@ public T accept(AbstractNodeVisitor visitor) { // @foo, @bar = baz // ^^^^ ^^^^ public static final class InstanceVariableTargetNode extends Node { - public final byte[] name; + public final String name; - public InstanceVariableTargetNode(byte[] name, int startOffset, int length) { + public InstanceVariableTargetNode(String name, int startOffset, int length) { super(startOffset, length); this.name = name; } @@ -2746,6 +4191,22 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitInstanceVariableTargetNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + return builder.toString(); + } } // Represents writing to an instance variable. @@ -2753,17 +4214,13 @@ public T accept(AbstractNodeVisitor visitor) { // @foo = 1 // ^^^^^^^^ public static final class InstanceVariableWriteNode extends Node { - public final byte[] name; - public final Location name_loc; + public final String name; public final Node value; - public final Location operator_loc; - public InstanceVariableWriteNode(byte[] name, Location name_loc, Node value, Location operator_loc, int startOffset, int length) { + public InstanceVariableWriteNode(String name, Node value, int startOffset, int length) { super(startOffset, length); this.name = name; - this.name_loc = name_loc; this.value = value; - this.operator_loc = operator_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -2777,6 +4234,25 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitInstanceVariableWriteNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + return builder.toString(); + } } // Represents an integer number literal. @@ -2784,11 +4260,29 @@ public T accept(AbstractNodeVisitor visitor) { // 1 // ^ public static final class IntegerNode extends Node { + public final short flags; - public IntegerNode(int startOffset, int length) { + public IntegerNode(short flags, int startOffset, int length) { super(startOffset, length); + this.flags = flags; } - + + public boolean isBinary() { + return IntegerBaseFlags.isBinary(this.flags); + } + + public boolean isOctal() { + return IntegerBaseFlags.isOctal(this.flags); + } + + public boolean isDecimal() { + return IntegerBaseFlags.isDecimal(this.flags); + } + + public boolean isHexadecimal() { + return IntegerBaseFlags.isHexadecimal(this.flags); + } + public void visitChildNodes(AbstractNodeVisitor visitor) { } @@ -2799,23 +4293,37 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitIntegerNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + return builder.toString(); + } } - // Represents a regular expression literal that contains interpolation. + // Represents a regular expression literal that contains interpolation that + // is being used in the predicate of a conditional to implicitly match + // against the last line read by an IO object. // - // /foo #{bar} baz/ - // ^^^^^^^^^^^^^^^^ - public static final class InterpolatedRegularExpressionNode extends Node { - public final Location opening_loc; + // if /foo #{bar} baz/ then end + // ^^^^^^^^^^^^^^^^ + public static final class InterpolatedMatchLastLineNode extends Node { public final Node[] parts; - public final Location closing_loc; public final short flags; - public InterpolatedRegularExpressionNode(Location opening_loc, Node[] parts, Location closing_loc, short flags, int startOffset, int length) { + public InterpolatedMatchLastLineNode(Node[] parts, short flags, int startOffset, int length) { super(startOffset, length); - this.opening_loc = opening_loc; this.parts = parts; - this.closing_loc = closing_loc; this.flags = flags; } @@ -2823,14 +4331,106 @@ public boolean isIgnoreCase() { return RegularExpressionFlags.isIgnoreCase(this.flags); } + public boolean isExtended() { + return RegularExpressionFlags.isExtended(this.flags); + } + public boolean isMultiLine() { return RegularExpressionFlags.isMultiLine(this.flags); } + public boolean isEucJp() { + return RegularExpressionFlags.isEucJp(this.flags); + } + + public boolean isAscii8bit() { + return RegularExpressionFlags.isAscii8bit(this.flags); + } + + public boolean isWindows31j() { + return RegularExpressionFlags.isWindows31j(this.flags); + } + + public boolean isUtf8() { + return RegularExpressionFlags.isUtf8(this.flags); + } + + public boolean isOnce() { + return RegularExpressionFlags.isOnce(this.flags); + } + + @Override + public void setNewLineFlag(Source source, boolean[] newlineMarked) { + Node first = this.parts.length > 0 ? this.parts[0] : null; + if (first != null) { + first.setNewLineFlag(source, newlineMarked); + } + } + + public void visitChildNodes(AbstractNodeVisitor visitor) { + for (Nodes.Node child : this.parts) { + child.accept(visitor); + } + } + + public Node[] childNodes() { + return this.parts; + } + + public T accept(AbstractNodeVisitor visitor) { + return visitor.visitInterpolatedMatchLastLineNode(this); + } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + String nextNextIndent = nextIndent + " "; + builder.append(nextIndent); + builder.append("parts: "); + builder.append('\n'); + for (Node child : this.parts) { + builder.append(nextNextIndent).append(child.toString(nextNextIndent)); + } + builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + return builder.toString(); + } + } + + // Represents a regular expression literal that contains interpolation. + // + // /foo #{bar} baz/ + // ^^^^^^^^^^^^^^^^ + public static final class InterpolatedRegularExpressionNode extends Node { + public final Node[] parts; + public final short flags; + + public InterpolatedRegularExpressionNode(Node[] parts, short flags, int startOffset, int length) { + super(startOffset, length); + this.parts = parts; + this.flags = flags; + } + + public boolean isIgnoreCase() { + return RegularExpressionFlags.isIgnoreCase(this.flags); + } + public boolean isExtended() { return RegularExpressionFlags.isExtended(this.flags); } + public boolean isMultiLine() { + return RegularExpressionFlags.isMultiLine(this.flags); + } + public boolean isEucJp() { return RegularExpressionFlags.isEucJp(this.flags); } @@ -2872,6 +4472,29 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitInterpolatedRegularExpressionNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + String nextNextIndent = nextIndent + " "; + builder.append(nextIndent); + builder.append("parts: "); + builder.append('\n'); + for (Node child : this.parts) { + builder.append(nextNextIndent).append(child.toString(nextNextIndent)); + } + builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + return builder.toString(); + } } // Represents a string literal that contains interpolation. @@ -2879,17 +4502,11 @@ public T accept(AbstractNodeVisitor visitor) { // "foo #{bar} baz" // ^^^^^^^^^^^^^^^^ public static final class InterpolatedStringNode extends Node { - /** optional (can be null) */ - public final Location opening_loc; public final Node[] parts; - /** optional (can be null) */ - public final Location closing_loc; - public InterpolatedStringNode(Location opening_loc, Node[] parts, Location closing_loc, int startOffset, int length) { + public InterpolatedStringNode(Node[] parts, int startOffset, int length) { super(startOffset, length); - this.opening_loc = opening_loc; this.parts = parts; - this.closing_loc = closing_loc; } @Override @@ -2913,6 +4530,25 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitInterpolatedStringNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + String nextNextIndent = nextIndent + " "; + builder.append(nextIndent); + builder.append("parts: "); + builder.append('\n'); + for (Node child : this.parts) { + builder.append(nextNextIndent).append(child.toString(nextNextIndent)); + } + return builder.toString(); + } } // Represents a symbol literal that contains interpolation. @@ -2920,17 +4556,11 @@ public T accept(AbstractNodeVisitor visitor) { // :"foo #{bar} baz" // ^^^^^^^^^^^^^^^^^ public static final class InterpolatedSymbolNode extends Node { - /** optional (can be null) */ - public final Location opening_loc; public final Node[] parts; - /** optional (can be null) */ - public final Location closing_loc; - public InterpolatedSymbolNode(Location opening_loc, Node[] parts, Location closing_loc, int startOffset, int length) { + public InterpolatedSymbolNode(Node[] parts, int startOffset, int length) { super(startOffset, length); - this.opening_loc = opening_loc; this.parts = parts; - this.closing_loc = closing_loc; } @Override @@ -2954,6 +4584,25 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitInterpolatedSymbolNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + String nextNextIndent = nextIndent + " "; + builder.append(nextIndent); + builder.append("parts: "); + builder.append('\n'); + for (Node child : this.parts) { + builder.append(nextNextIndent).append(child.toString(nextNextIndent)); + } + return builder.toString(); + } } // Represents an xstring literal that contains interpolation. @@ -2961,15 +4610,11 @@ public T accept(AbstractNodeVisitor visitor) { // `foo #{bar} baz` // ^^^^^^^^^^^^^^^^ public static final class InterpolatedXStringNode extends Node { - public final Location opening_loc; public final Node[] parts; - public final Location closing_loc; - public InterpolatedXStringNode(Location opening_loc, Node[] parts, Location closing_loc, int startOffset, int length) { + public InterpolatedXStringNode(Node[] parts, int startOffset, int length) { super(startOffset, length); - this.opening_loc = opening_loc; this.parts = parts; - this.closing_loc = closing_loc; } @Override @@ -2993,6 +4638,25 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitInterpolatedXStringNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + String nextNextIndent = nextIndent + " "; + builder.append(nextIndent); + builder.append("parts: "); + builder.append('\n'); + for (Node child : this.parts) { + builder.append(nextNextIndent).append(child.toString(nextNextIndent)); + } + return builder.toString(); + } } // Represents a hash literal without opening and closing braces. @@ -3020,6 +4684,25 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitKeywordHashNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + String nextNextIndent = nextIndent + " "; + builder.append(nextIndent); + builder.append("elements: "); + builder.append('\n'); + for (Node child : this.elements) { + builder.append(nextNextIndent).append(child.toString(nextNextIndent)); + } + return builder.toString(); + } } // Represents a keyword parameter to a method, block, or lambda definition. @@ -3032,13 +4715,13 @@ public T accept(AbstractNodeVisitor visitor) { // ^^^^ // end public static final class KeywordParameterNode extends Node { - public final Location name_loc; + public final String name; /** optional (can be null) */ public final Node value; - public KeywordParameterNode(Location name_loc, Node value, int startOffset, int length) { + public KeywordParameterNode(String name, Node value, int startOffset, int length) { super(startOffset, length); - this.name_loc = name_loc; + this.name = name; this.value = value; } @@ -3055,6 +4738,25 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitKeywordParameterNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value == null ? "null\n" : this.value.toString(nextIndent)); + return builder.toString(); + } } // Represents a keyword rest parameter to a method, block, or lambda definition. @@ -3063,14 +4765,12 @@ public T accept(AbstractNodeVisitor visitor) { // ^^^ // end public static final class KeywordRestParameterNode extends Node { - public final Location operator_loc; /** optional (can be null) */ - public final Location name_loc; + public final String name; - public KeywordRestParameterNode(Location operator_loc, Location name_loc, int startOffset, int length) { + public KeywordRestParameterNode(String name, int startOffset, int length) { super(startOffset, length); - this.operator_loc = operator_loc; - this.name_loc = name_loc; + this.name = name; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -3083,6 +4783,22 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitKeywordRestParameterNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append(this.name == null ? "null" : "\"" + this.name + "\""); + builder.append('\n'); + return builder.toString(); + } } // Represents using a lambda literal (not the lambda method call). @@ -3090,21 +4806,15 @@ public T accept(AbstractNodeVisitor visitor) { // ->(value) { value * 2 } // ^^^^^^^^^^^^^^^^^^^^^^^ public static final class LambdaNode extends Node { - public final byte[][] locals; - public final Location operator_loc; - public final Location opening_loc; - public final Location closing_loc; + public final String[] locals; /** optional (can be null) */ public final BlockParametersNode parameters; /** optional (can be null) */ public final Node body; - public LambdaNode(byte[][] locals, Location operator_loc, Location opening_loc, Location closing_loc, BlockParametersNode parameters, Node body, int startOffset, int length) { + public LambdaNode(String[] locals, BlockParametersNode parameters, Node body, int startOffset, int length) { super(startOffset, length); this.locals = locals; - this.operator_loc = operator_loc; - this.opening_loc = opening_loc; - this.closing_loc = closing_loc; this.parameters = parameters; this.body = body; } @@ -3125,6 +4835,31 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitLambdaNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + String nextNextIndent = nextIndent + " "; + builder.append(nextIndent); + builder.append("locals: "); + builder.append('\n'); + for (String constant : this.locals) { + builder.append(nextNextIndent).append('"').append(constant).append('"').append('\n'); + } + builder.append(nextIndent); + builder.append("parameters: "); + builder.append(this.parameters == null ? "null\n" : this.parameters.toString(nextIndent)); + builder.append(nextIndent); + builder.append("body: "); + builder.append(this.body == null ? "null\n" : this.body.toString(nextIndent)); + return builder.toString(); + } } // Represents the use of the `&&=` operator for assignment to a local variable. @@ -3132,16 +4867,12 @@ public T accept(AbstractNodeVisitor visitor) { // target &&= value // ^^^^^^^^^^^^^^^^ public static final class LocalVariableAndWriteNode extends Node { - public final Location name_loc; - public final Location operator_loc; public final Node value; - public final byte[] name; + public final String name; public final int depth; - public LocalVariableAndWriteNode(Location name_loc, Location operator_loc, Node value, byte[] name, int depth, int startOffset, int length) { + public LocalVariableAndWriteNode(Node value, String name, int depth, int startOffset, int length) { super(startOffset, length); - this.name_loc = name_loc; - this.operator_loc = operator_loc; this.value = value; this.name = name; this.depth = depth; @@ -3158,6 +4889,29 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitLocalVariableAndWriteNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("depth: "); + builder.append(this.depth); + builder.append('\n'); + return builder.toString(); + } } // Represents assigning to a local variable using an operator that isn't `=`. @@ -3165,17 +4919,13 @@ public T accept(AbstractNodeVisitor visitor) { // target += value // ^^^^^^^^^^^^^^^ public static final class LocalVariableOperatorWriteNode extends Node { - public final Location name_loc; - public final Location operator_loc; public final Node value; - public final byte[] name; - public final byte[] operator; + public final String name; + public final String operator; public final int depth; - public LocalVariableOperatorWriteNode(Location name_loc, Location operator_loc, Node value, byte[] name, byte[] operator, int depth, int startOffset, int length) { + public LocalVariableOperatorWriteNode(Node value, String name, String operator, int depth, int startOffset, int length) { super(startOffset, length); - this.name_loc = name_loc; - this.operator_loc = operator_loc; this.value = value; this.name = name; this.operator = operator; @@ -3193,6 +4943,33 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitLocalVariableOperatorWriteNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("operator: "); + builder.append('"').append(this.operator).append('"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("depth: "); + builder.append(this.depth); + builder.append('\n'); + return builder.toString(); + } } // Represents the use of the `||=` operator for assignment to a local variable. @@ -3200,16 +4977,12 @@ public T accept(AbstractNodeVisitor visitor) { // target ||= value // ^^^^^^^^^^^^^^^^ public static final class LocalVariableOrWriteNode extends Node { - public final Location name_loc; - public final Location operator_loc; public final Node value; - public final byte[] name; + public final String name; public final int depth; - public LocalVariableOrWriteNode(Location name_loc, Location operator_loc, Node value, byte[] name, int depth, int startOffset, int length) { + public LocalVariableOrWriteNode(Node value, String name, int depth, int startOffset, int length) { super(startOffset, length); - this.name_loc = name_loc; - this.operator_loc = operator_loc; this.value = value; this.name = name; this.depth = depth; @@ -3226,6 +4999,29 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitLocalVariableOrWriteNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("depth: "); + builder.append(this.depth); + builder.append('\n'); + return builder.toString(); + } } // Represents reading a local variable. Note that this requires that a local @@ -3235,10 +5031,10 @@ public T accept(AbstractNodeVisitor visitor) { // foo // ^^^ public static final class LocalVariableReadNode extends Node { - public final byte[] name; + public final String name; public final int depth; - public LocalVariableReadNode(byte[] name, int depth, int startOffset, int length) { + public LocalVariableReadNode(String name, int depth, int startOffset, int length) { super(startOffset, length); this.name = name; this.depth = depth; @@ -3254,6 +5050,26 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitLocalVariableReadNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("depth: "); + builder.append(this.depth); + builder.append('\n'); + return builder.toString(); + } } // Represents writing to a local variable in a context that doesn't have an explicit value. @@ -3261,10 +5077,10 @@ public T accept(AbstractNodeVisitor visitor) { // foo, bar = baz // ^^^ ^^^ public static final class LocalVariableTargetNode extends Node { - public final byte[] name; + public final String name; public final int depth; - public LocalVariableTargetNode(byte[] name, int depth, int startOffset, int length) { + public LocalVariableTargetNode(String name, int depth, int startOffset, int length) { super(startOffset, length); this.name = name; this.depth = depth; @@ -3280,6 +5096,26 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitLocalVariableTargetNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("depth: "); + builder.append(this.depth); + builder.append('\n'); + return builder.toString(); + } } // Represents writing to a local variable. @@ -3287,19 +5123,15 @@ public T accept(AbstractNodeVisitor visitor) { // foo = 1 // ^^^^^^^ public static final class LocalVariableWriteNode extends Node { - public final byte[] name; + public final String name; public final int depth; - public final Location name_loc; public final Node value; - public final Location operator_loc; - public LocalVariableWriteNode(byte[] name, int depth, Location name_loc, Node value, Location operator_loc, int startOffset, int length) { + public LocalVariableWriteNode(String name, int depth, Node value, int startOffset, int length) { super(startOffset, length); this.name = name; this.depth = depth; - this.name_loc = name_loc; this.value = value; - this.operator_loc = operator_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -3313,6 +5145,111 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitLocalVariableWriteNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("depth: "); + builder.append(this.depth); + builder.append('\n'); + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + return builder.toString(); + } + } + + // Represents a regular expression literal used in the predicate of a + // conditional to implicitly match against the last line read by an IO + // object. + // + // if /foo/i then end + // ^^^^^^ + public static final class MatchLastLineNode extends Node { + public final Location content_loc; + public final byte[] unescaped; + public final short flags; + + public MatchLastLineNode(Location content_loc, byte[] unescaped, short flags, int startOffset, int length) { + super(startOffset, length); + this.content_loc = content_loc; + this.unescaped = unescaped; + this.flags = flags; + } + + public boolean isIgnoreCase() { + return RegularExpressionFlags.isIgnoreCase(this.flags); + } + + public boolean isExtended() { + return RegularExpressionFlags.isExtended(this.flags); + } + + public boolean isMultiLine() { + return RegularExpressionFlags.isMultiLine(this.flags); + } + + public boolean isEucJp() { + return RegularExpressionFlags.isEucJp(this.flags); + } + + public boolean isAscii8bit() { + return RegularExpressionFlags.isAscii8bit(this.flags); + } + + public boolean isWindows31j() { + return RegularExpressionFlags.isWindows31j(this.flags); + } + + public boolean isUtf8() { + return RegularExpressionFlags.isUtf8(this.flags); + } + + public boolean isOnce() { + return RegularExpressionFlags.isOnce(this.flags); + } + + public void visitChildNodes(AbstractNodeVisitor visitor) { + } + + public Node[] childNodes() { + return EMPTY_ARRAY; + } + + public T accept(AbstractNodeVisitor visitor) { + return visitor.visitMatchLastLineNode(this); + } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("unescaped: "); + builder.append('"' + new String(this.unescaped, StandardCharsets.UTF_8) + '"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + return builder.toString(); + } } // Represents the use of the modifier `in` operator. @@ -3322,13 +5259,11 @@ public T accept(AbstractNodeVisitor visitor) { public static final class MatchPredicateNode extends Node { public final Node value; public final Node pattern; - public final Location operator_loc; - public MatchPredicateNode(Node value, Node pattern, Location operator_loc, int startOffset, int length) { + public MatchPredicateNode(Node value, Node pattern, int startOffset, int length) { super(startOffset, length); this.value = value; this.pattern = pattern; - this.operator_loc = operator_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -3343,6 +5278,24 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitMatchPredicateNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + builder.append(nextIndent); + builder.append("pattern: "); + builder.append(this.pattern.toString(nextIndent)); + return builder.toString(); + } } // Represents the use of the `=>` operator. @@ -3352,13 +5305,11 @@ public T accept(AbstractNodeVisitor visitor) { public static final class MatchRequiredNode extends Node { public final Node value; public final Node pattern; - public final Location operator_loc; - public MatchRequiredNode(Node value, Node pattern, Location operator_loc, int startOffset, int length) { + public MatchRequiredNode(Node value, Node pattern, int startOffset, int length) { super(startOffset, length); this.value = value; this.pattern = pattern; - this.operator_loc = operator_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -3373,6 +5324,74 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitMatchRequiredNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + builder.append(nextIndent); + builder.append("pattern: "); + builder.append(this.pattern.toString(nextIndent)); + return builder.toString(); + } + } + + // Represents writing local variables using a regular expression match with + // named capture groups. + // + // /(?bar)/ =~ baz + // ^^^^^^^^^^^^^^^^^^^^ + public static final class MatchWriteNode extends Node { + public final CallNode call; + public final String[] locals; + + public MatchWriteNode(CallNode call, String[] locals, int startOffset, int length) { + super(startOffset, length); + this.call = call; + this.locals = locals; + } + + public void visitChildNodes(AbstractNodeVisitor visitor) { + this.call.accept(visitor); + } + + public Node[] childNodes() { + return new Node[] { this.call }; + } + + public T accept(AbstractNodeVisitor visitor) { + return visitor.visitMatchWriteNode(this); + } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + String nextNextIndent = nextIndent + " "; + builder.append(nextIndent); + builder.append("call: "); + builder.append(this.call.toString(nextIndent)); + builder.append(nextIndent); + builder.append("locals: "); + builder.append('\n'); + for (String constant : this.locals) { + builder.append(nextNextIndent).append('"').append(constant).append('"').append('\n'); + } + return builder.toString(); + } } // Represents a node that is missing from the source and results in a syntax @@ -3393,6 +5412,18 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitMissingNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + return builder.toString(); + } } // Represents a module declaration involving the `module` keyword. @@ -3400,21 +5431,17 @@ public T accept(AbstractNodeVisitor visitor) { // module Foo end // ^^^^^^^^^^^^^^ public static final class ModuleNode extends Node { - public final byte[][] locals; - public final Location module_keyword_loc; + public final String[] locals; public final Node constant_path; /** optional (can be null) */ public final Node body; - public final Location end_keyword_loc; - public final byte[] name; + public final String name; - public ModuleNode(byte[][] locals, Location module_keyword_loc, Node constant_path, Node body, Location end_keyword_loc, byte[] name, int startOffset, int length) { + public ModuleNode(String[] locals, Node constant_path, Node body, String name, int startOffset, int length) { super(startOffset, length); this.locals = locals; - this.module_keyword_loc = module_keyword_loc; this.constant_path = constant_path; this.body = body; - this.end_keyword_loc = end_keyword_loc; this.name = name; } @@ -3429,42 +5456,105 @@ public Node[] childNodes() { return new Node[] { this.constant_path, this.body }; } - public T accept(AbstractNodeVisitor visitor) { - return visitor.visitModuleNode(this); + public T accept(AbstractNodeVisitor visitor) { + return visitor.visitModuleNode(this); + } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + String nextNextIndent = nextIndent + " "; + builder.append(nextIndent); + builder.append("locals: "); + builder.append('\n'); + for (String constant : this.locals) { + builder.append(nextNextIndent).append('"').append(constant).append('"').append('\n'); + } + builder.append(nextIndent); + builder.append("constant_path: "); + builder.append(this.constant_path.toString(nextIndent)); + builder.append(nextIndent); + builder.append("body: "); + builder.append(this.body == null ? "null\n" : this.body.toString(nextIndent)); + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + return builder.toString(); + } + } + + // Represents a multi-target expression. + // + // a, b, c = 1, 2, 3 + // ^^^^^^^ + public static final class MultiTargetNode extends Node { + public final Node[] targets; + + public MultiTargetNode(Node[] targets, int startOffset, int length) { + super(startOffset, length); + this.targets = targets; + } + + public void visitChildNodes(AbstractNodeVisitor visitor) { + for (Nodes.Node child : this.targets) { + child.accept(visitor); + } + } + + public Node[] childNodes() { + return this.targets; + } + + public T accept(AbstractNodeVisitor visitor) { + return visitor.visitMultiTargetNode(this); + } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + String nextNextIndent = nextIndent + " "; + builder.append(nextIndent); + builder.append("targets: "); + builder.append('\n'); + for (Node child : this.targets) { + builder.append(nextNextIndent).append(child.toString(nextNextIndent)); + } + return builder.toString(); } } - // Represents a multi-target expression. + // Represents a write to a multi-target expression. // // a, b, c = 1, 2, 3 // ^^^^^^^^^^^^^^^^^ public static final class MultiWriteNode extends Node { public final Node[] targets; - /** optional (can be null) */ - public final Location operator_loc; - /** optional (can be null) */ public final Node value; - /** optional (can be null) */ - public final Location lparen_loc; - /** optional (can be null) */ - public final Location rparen_loc; - public MultiWriteNode(Node[] targets, Location operator_loc, Node value, Location lparen_loc, Location rparen_loc, int startOffset, int length) { + public MultiWriteNode(Node[] targets, Node value, int startOffset, int length) { super(startOffset, length); this.targets = targets; - this.operator_loc = operator_loc; this.value = value; - this.lparen_loc = lparen_loc; - this.rparen_loc = rparen_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { for (Nodes.Node child : this.targets) { child.accept(visitor); } - if (this.value != null) { - this.value.accept(visitor); - } + this.value.accept(visitor); } public Node[] childNodes() { @@ -3477,6 +5567,28 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitMultiWriteNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + String nextNextIndent = nextIndent + " "; + builder.append(nextIndent); + builder.append("targets: "); + builder.append('\n'); + for (Node child : this.targets) { + builder.append(nextNextIndent).append(child.toString(nextNextIndent)); + } + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + return builder.toString(); + } } // Represents the use of the `next` keyword. @@ -3486,12 +5598,10 @@ public T accept(AbstractNodeVisitor visitor) { public static final class NextNode extends Node { /** optional (can be null) */ public final ArgumentsNode arguments; - public final Location keyword_loc; - public NextNode(ArgumentsNode arguments, Location keyword_loc, int startOffset, int length) { + public NextNode(ArgumentsNode arguments, int startOffset, int length) { super(startOffset, length); this.arguments = arguments; - this.keyword_loc = keyword_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -3507,6 +5617,21 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitNextNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("arguments: "); + builder.append(this.arguments == null ? "null\n" : this.arguments.toString(nextIndent)); + return builder.toString(); + } } // Represents the use of the `nil` keyword. @@ -3529,6 +5654,18 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitNilNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + return builder.toString(); + } } // Represents the use of `**nil` inside method arguments. @@ -3537,13 +5674,9 @@ public T accept(AbstractNodeVisitor visitor) { // ^^^^^ // end public static final class NoKeywordsParameterNode extends Node { - public final Location operator_loc; - public final Location keyword_loc; - public NoKeywordsParameterNode(Location operator_loc, Location keyword_loc, int startOffset, int length) { + public NoKeywordsParameterNode(int startOffset, int length) { super(startOffset, length); - this.operator_loc = operator_loc; - this.keyword_loc = keyword_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -3556,6 +5689,18 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitNoKeywordsParameterNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + return builder.toString(); + } } // Represents reading a numbered reference to a capture in the previous match. @@ -3580,6 +5725,22 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitNumberedReferenceReadNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("number: "); + builder.append(this.number); + builder.append('\n'); + return builder.toString(); + } } // Represents an optional parameter to a method, block, or lambda definition. @@ -3588,16 +5749,12 @@ public T accept(AbstractNodeVisitor visitor) { // ^^^^^ // end public static final class OptionalParameterNode extends Node { - public final byte[] name; - public final Location name_loc; - public final Location operator_loc; + public final String name; public final Node value; - public OptionalParameterNode(byte[] name, Location name_loc, Location operator_loc, Node value, int startOffset, int length) { + public OptionalParameterNode(String name, Node value, int startOffset, int length) { super(startOffset, length); this.name = name; - this.name_loc = name_loc; - this.operator_loc = operator_loc; this.value = value; } @@ -3612,6 +5769,25 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitOptionalParameterNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("value: "); + builder.append(this.value.toString(nextIndent)); + return builder.toString(); + } } // Represents the use of the `||` operator or the `or` keyword. @@ -3621,13 +5797,11 @@ public T accept(AbstractNodeVisitor visitor) { public static final class OrNode extends Node { public final Node left; public final Node right; - public final Location operator_loc; - public OrNode(Node left, Node right, Location operator_loc, int startOffset, int length) { + public OrNode(Node left, Node right, int startOffset, int length) { super(startOffset, length); this.left = left; this.right = right; - this.operator_loc = operator_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -3642,6 +5816,24 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitOrNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("left: "); + builder.append(this.left.toString(nextIndent)); + builder.append(nextIndent); + builder.append("right: "); + builder.append(this.right.toString(nextIndent)); + return builder.toString(); + } } // Represents the list of parameters on a method, block, or lambda definition. @@ -3652,21 +5844,21 @@ public T accept(AbstractNodeVisitor visitor) { public static final class ParametersNode extends Node { public final Node[] requireds; public final Node[] optionals; - public final Node[] posts; /** optional (can be null) */ public final RestParameterNode rest; + public final Node[] posts; public final Node[] keywords; /** optional (can be null) */ public final Node keyword_rest; /** optional (can be null) */ public final BlockParameterNode block; - public ParametersNode(Node[] requireds, Node[] optionals, Node[] posts, RestParameterNode rest, Node[] keywords, Node keyword_rest, BlockParameterNode block, int startOffset, int length) { + public ParametersNode(Node[] requireds, Node[] optionals, RestParameterNode rest, Node[] posts, Node[] keywords, Node keyword_rest, BlockParameterNode block, int startOffset, int length) { super(startOffset, length); this.requireds = requireds; this.optionals = optionals; - this.posts = posts; this.rest = rest; + this.posts = posts; this.keywords = keywords; this.keyword_rest = keyword_rest; this.block = block; @@ -3679,12 +5871,12 @@ public void visitChildNodes(AbstractNodeVisitor visitor) { for (Nodes.Node child : this.optionals) { child.accept(visitor); } - for (Nodes.Node child : this.posts) { - child.accept(visitor); - } if (this.rest != null) { this.rest.accept(visitor); } + for (Nodes.Node child : this.posts) { + child.accept(visitor); + } for (Nodes.Node child : this.keywords) { child.accept(visitor); } @@ -3700,8 +5892,8 @@ public Node[] childNodes() { ArrayList childNodes = new ArrayList<>(); childNodes.addAll(Arrays.asList(this.requireds)); childNodes.addAll(Arrays.asList(this.optionals)); - childNodes.addAll(Arrays.asList(this.posts)); childNodes.add(this.rest); + childNodes.addAll(Arrays.asList(this.posts)); childNodes.addAll(Arrays.asList(this.keywords)); childNodes.add(this.keyword_rest); childNodes.add(this.block); @@ -3711,6 +5903,52 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitParametersNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + String nextNextIndent = nextIndent + " "; + builder.append(nextIndent); + builder.append("requireds: "); + builder.append('\n'); + for (Node child : this.requireds) { + builder.append(nextNextIndent).append(child.toString(nextNextIndent)); + } + builder.append(nextIndent); + builder.append("optionals: "); + builder.append('\n'); + for (Node child : this.optionals) { + builder.append(nextNextIndent).append(child.toString(nextNextIndent)); + } + builder.append(nextIndent); + builder.append("rest: "); + builder.append(this.rest == null ? "null\n" : this.rest.toString(nextIndent)); + builder.append(nextIndent); + builder.append("posts: "); + builder.append('\n'); + for (Node child : this.posts) { + builder.append(nextNextIndent).append(child.toString(nextNextIndent)); + } + builder.append(nextIndent); + builder.append("keywords: "); + builder.append('\n'); + for (Node child : this.keywords) { + builder.append(nextNextIndent).append(child.toString(nextNextIndent)); + } + builder.append(nextIndent); + builder.append("keyword_rest: "); + builder.append(this.keyword_rest == null ? "null\n" : this.keyword_rest.toString(nextIndent)); + builder.append(nextIndent); + builder.append("block: "); + builder.append(this.block == null ? "null\n" : this.block.toString(nextIndent)); + return builder.toString(); + } } // Represents a parenthesized expression @@ -3720,14 +5958,10 @@ public T accept(AbstractNodeVisitor visitor) { public static final class ParenthesesNode extends Node { /** optional (can be null) */ public final Node body; - public final Location opening_loc; - public final Location closing_loc; - public ParenthesesNode(Node body, Location opening_loc, Location closing_loc, int startOffset, int length) { + public ParenthesesNode(Node body, int startOffset, int length) { super(startOffset, length); this.body = body; - this.opening_loc = opening_loc; - this.closing_loc = closing_loc; } @Override @@ -3748,6 +5982,21 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitParenthesesNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("body: "); + builder.append(this.body == null ? "null\n" : this.body.toString(nextIndent)); + return builder.toString(); + } } // Represents the use of the `^` operator for pinning an expression in a @@ -3757,16 +6006,10 @@ public T accept(AbstractNodeVisitor visitor) { // ^^^^^^ public static final class PinnedExpressionNode extends Node { public final Node expression; - public final Location operator_loc; - public final Location lparen_loc; - public final Location rparen_loc; - public PinnedExpressionNode(Node expression, Location operator_loc, Location lparen_loc, Location rparen_loc, int startOffset, int length) { + public PinnedExpressionNode(Node expression, int startOffset, int length) { super(startOffset, length); this.expression = expression; - this.operator_loc = operator_loc; - this.lparen_loc = lparen_loc; - this.rparen_loc = rparen_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -3780,6 +6023,21 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitPinnedExpressionNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("expression: "); + builder.append(this.expression.toString(nextIndent)); + return builder.toString(); + } } // Represents the use of the `^` operator for pinning a variable in a pattern @@ -3789,12 +6047,10 @@ public T accept(AbstractNodeVisitor visitor) { // ^^^^ public static final class PinnedVariableNode extends Node { public final Node variable; - public final Location operator_loc; - public PinnedVariableNode(Node variable, Location operator_loc, int startOffset, int length) { + public PinnedVariableNode(Node variable, int startOffset, int length) { super(startOffset, length); this.variable = variable; - this.operator_loc = operator_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -3808,6 +6064,21 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitPinnedVariableNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("variable: "); + builder.append(this.variable.toString(nextIndent)); + return builder.toString(); + } } // Represents the use of the `END` keyword. @@ -3817,16 +6088,10 @@ public T accept(AbstractNodeVisitor visitor) { public static final class PostExecutionNode extends Node { /** optional (can be null) */ public final StatementsNode statements; - public final Location keyword_loc; - public final Location opening_loc; - public final Location closing_loc; - public PostExecutionNode(StatementsNode statements, Location keyword_loc, Location opening_loc, Location closing_loc, int startOffset, int length) { + public PostExecutionNode(StatementsNode statements, int startOffset, int length) { super(startOffset, length); this.statements = statements; - this.keyword_loc = keyword_loc; - this.opening_loc = opening_loc; - this.closing_loc = closing_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -3842,6 +6107,21 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitPostExecutionNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("statements: "); + builder.append(this.statements == null ? "null\n" : this.statements.toString(nextIndent)); + return builder.toString(); + } } // Represents the use of the `BEGIN` keyword. @@ -3851,16 +6131,10 @@ public T accept(AbstractNodeVisitor visitor) { public static final class PreExecutionNode extends Node { /** optional (can be null) */ public final StatementsNode statements; - public final Location keyword_loc; - public final Location opening_loc; - public final Location closing_loc; - public PreExecutionNode(StatementsNode statements, Location keyword_loc, Location opening_loc, Location closing_loc, int startOffset, int length) { + public PreExecutionNode(StatementsNode statements, int startOffset, int length) { super(startOffset, length); this.statements = statements; - this.keyword_loc = keyword_loc; - this.opening_loc = opening_loc; - this.closing_loc = closing_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -3876,14 +6150,29 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitPreExecutionNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("statements: "); + builder.append(this.statements == null ? "null\n" : this.statements.toString(nextIndent)); + return builder.toString(); + } } // The top level node of any parse tree. public static final class ProgramNode extends Node { - public final byte[][] locals; + public final String[] locals; public final StatementsNode statements; - public ProgramNode(byte[][] locals, StatementsNode statements, int startOffset, int length) { + public ProgramNode(String[] locals, StatementsNode statements, int startOffset, int length) { super(startOffset, length); this.locals = locals; this.statements = statements; @@ -3900,6 +6189,28 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitProgramNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + String nextNextIndent = nextIndent + " "; + builder.append(nextIndent); + builder.append("locals: "); + builder.append('\n'); + for (String constant : this.locals) { + builder.append(nextNextIndent).append('"').append(constant).append('"').append('\n'); + } + builder.append(nextIndent); + builder.append("statements: "); + builder.append(this.statements.toString(nextIndent)); + return builder.toString(); + } } // Represents the use of the `..` or `...` operators. @@ -3914,14 +6225,12 @@ public static final class RangeNode extends Node { public final Node left; /** optional (can be null) */ public final Node right; - public final Location operator_loc; public final short flags; - public RangeNode(Node left, Node right, Location operator_loc, short flags, int startOffset, int length) { + public RangeNode(Node left, Node right, short flags, int startOffset, int length) { super(startOffset, length); this.left = left; this.right = right; - this.operator_loc = operator_loc; this.flags = flags; } @@ -3945,6 +6254,28 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitRangeNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("left: "); + builder.append(this.left == null ? "null\n" : this.left.toString(nextIndent)); + builder.append(nextIndent); + builder.append("right: "); + builder.append(this.right == null ? "null\n" : this.right.toString(nextIndent)); + builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + return builder.toString(); + } } // Represents a rational number literal. @@ -3970,6 +6301,21 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitRationalNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("numeric: "); + builder.append(this.numeric.toString(nextIndent)); + return builder.toString(); + } } // Represents the use of the `redo` keyword. @@ -3992,6 +6338,18 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitRedoNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + return builder.toString(); + } } // Represents a regular expression literal with no interpolation. @@ -3999,17 +6357,13 @@ public T accept(AbstractNodeVisitor visitor) { // /foo/i // ^^^^^^ public static final class RegularExpressionNode extends Node { - public final Location opening_loc; public final Location content_loc; - public final Location closing_loc; public final byte[] unescaped; public final short flags; - public RegularExpressionNode(Location opening_loc, Location content_loc, Location closing_loc, byte[] unescaped, short flags, int startOffset, int length) { + public RegularExpressionNode(Location content_loc, byte[] unescaped, short flags, int startOffset, int length) { super(startOffset, length); - this.opening_loc = opening_loc; this.content_loc = content_loc; - this.closing_loc = closing_loc; this.unescaped = unescaped; this.flags = flags; } @@ -4018,14 +6372,14 @@ public boolean isIgnoreCase() { return RegularExpressionFlags.isIgnoreCase(this.flags); } - public boolean isMultiLine() { - return RegularExpressionFlags.isMultiLine(this.flags); - } - public boolean isExtended() { return RegularExpressionFlags.isExtended(this.flags); } + public boolean isMultiLine() { + return RegularExpressionFlags.isMultiLine(this.flags); + } + public boolean isEucJp() { return RegularExpressionFlags.isEucJp(this.flags); } @@ -4056,6 +6410,26 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitRegularExpressionNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("unescaped: "); + builder.append('"' + new String(this.unescaped, StandardCharsets.UTF_8) + '"'); + builder.append('\n'); + builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + return builder.toString(); + } } // Represents a destructured required parameter node. @@ -4065,14 +6439,10 @@ public T accept(AbstractNodeVisitor visitor) { // end public static final class RequiredDestructuredParameterNode extends Node { public final Node[] parameters; - public final Location opening_loc; - public final Location closing_loc; - public RequiredDestructuredParameterNode(Node[] parameters, Location opening_loc, Location closing_loc, int startOffset, int length) { + public RequiredDestructuredParameterNode(Node[] parameters, int startOffset, int length) { super(startOffset, length); this.parameters = parameters; - this.opening_loc = opening_loc; - this.closing_loc = closing_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -4088,6 +6458,25 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitRequiredDestructuredParameterNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + String nextNextIndent = nextIndent + " "; + builder.append(nextIndent); + builder.append("parameters: "); + builder.append('\n'); + for (Node child : this.parameters) { + builder.append(nextNextIndent).append(child.toString(nextNextIndent)); + } + return builder.toString(); + } } // Represents a required parameter to a method, block, or lambda definition. @@ -4096,9 +6485,9 @@ public T accept(AbstractNodeVisitor visitor) { // ^ // end public static final class RequiredParameterNode extends Node { - public final byte[] name; + public final String name; - public RequiredParameterNode(byte[] name, int startOffset, int length) { + public RequiredParameterNode(String name, int startOffset, int length) { super(startOffset, length); this.name = name; } @@ -4113,6 +6502,22 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitRequiredParameterNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append('"').append(this.name).append('"'); + builder.append('\n'); + return builder.toString(); + } } // Represents an expression modified with a rescue. @@ -4121,13 +6526,11 @@ public T accept(AbstractNodeVisitor visitor) { // ^^^^^^^^^^^^^^ public static final class RescueModifierNode extends Node { public final Node expression; - public final Location keyword_loc; public final Node rescue_expression; - public RescueModifierNode(Node expression, Location keyword_loc, Node rescue_expression, int startOffset, int length) { + public RescueModifierNode(Node expression, Node rescue_expression, int startOffset, int length) { super(startOffset, length); this.expression = expression; - this.keyword_loc = keyword_loc; this.rescue_expression = rescue_expression; } @@ -4148,6 +6551,24 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitRescueModifierNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("expression: "); + builder.append(this.expression.toString(nextIndent)); + builder.append(nextIndent); + builder.append("rescue_expression: "); + builder.append(this.rescue_expression.toString(nextIndent)); + return builder.toString(); + } } // Represents a rescue statement. @@ -4161,22 +6582,17 @@ public T accept(AbstractNodeVisitor visitor) { // `Foo, *splat, Bar` are in the `exceptions` field. // `ex` is in the `exception` field. public static final class RescueNode extends Node { - public final Location keyword_loc; public final Node[] exceptions; /** optional (can be null) */ - public final Location operator_loc; - /** optional (can be null) */ public final Node reference; /** optional (can be null) */ public final StatementsNode statements; /** optional (can be null) */ public final RescueNode consequent; - public RescueNode(Location keyword_loc, Node[] exceptions, Location operator_loc, Node reference, StatementsNode statements, RescueNode consequent, int startOffset, int length) { + public RescueNode(Node[] exceptions, Node reference, StatementsNode statements, RescueNode consequent, int startOffset, int length) { super(startOffset, length); - this.keyword_loc = keyword_loc; this.exceptions = exceptions; - this.operator_loc = operator_loc; this.reference = reference; this.statements = statements; this.consequent = consequent; @@ -4209,6 +6625,34 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitRescueNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + String nextNextIndent = nextIndent + " "; + builder.append(nextIndent); + builder.append("exceptions: "); + builder.append('\n'); + for (Node child : this.exceptions) { + builder.append(nextNextIndent).append(child.toString(nextNextIndent)); + } + builder.append(nextIndent); + builder.append("reference: "); + builder.append(this.reference == null ? "null\n" : this.reference.toString(nextIndent)); + builder.append(nextIndent); + builder.append("statements: "); + builder.append(this.statements == null ? "null\n" : this.statements.toString(nextIndent)); + builder.append(nextIndent); + builder.append("consequent: "); + builder.append(this.consequent == null ? "null\n" : this.consequent.toString(nextIndent)); + return builder.toString(); + } } // Represents a rest parameter to a method, block, or lambda definition. @@ -4217,14 +6661,12 @@ public T accept(AbstractNodeVisitor visitor) { // ^^ // end public static final class RestParameterNode extends Node { - public final Location operator_loc; /** optional (can be null) */ - public final Location name_loc; + public final String name; - public RestParameterNode(Location operator_loc, Location name_loc, int startOffset, int length) { + public RestParameterNode(String name, int startOffset, int length) { super(startOffset, length); - this.operator_loc = operator_loc; - this.name_loc = name_loc; + this.name = name; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -4237,6 +6679,22 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitRestParameterNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("name: "); + builder.append(this.name == null ? "null" : "\"" + this.name + "\""); + builder.append('\n'); + return builder.toString(); + } } // Represents the use of the `retry` keyword. @@ -4259,6 +6717,18 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitRetryNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + return builder.toString(); + } } // Represents the use of the `return` keyword. @@ -4266,13 +6736,11 @@ public T accept(AbstractNodeVisitor visitor) { // return 1 // ^^^^^^^^ public static final class ReturnNode extends Node { - public final Location keyword_loc; /** optional (can be null) */ public final ArgumentsNode arguments; - public ReturnNode(Location keyword_loc, ArgumentsNode arguments, int startOffset, int length) { + public ReturnNode(ArgumentsNode arguments, int startOffset, int length) { super(startOffset, length); - this.keyword_loc = keyword_loc; this.arguments = arguments; } @@ -4289,6 +6757,21 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitReturnNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("arguments: "); + builder.append(this.arguments == null ? "null\n" : this.arguments.toString(nextIndent)); + return builder.toString(); + } } // Represents the `self` keyword. @@ -4311,6 +6794,18 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitSelfNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + return builder.toString(); + } } // Represents a singleton class declaration involving the `class` keyword. @@ -4318,22 +6813,16 @@ public T accept(AbstractNodeVisitor visitor) { // class << self end // ^^^^^^^^^^^^^^^^^ public static final class SingletonClassNode extends Node { - public final byte[][] locals; - public final Location class_keyword_loc; - public final Location operator_loc; + public final String[] locals; public final Node expression; /** optional (can be null) */ public final Node body; - public final Location end_keyword_loc; - public SingletonClassNode(byte[][] locals, Location class_keyword_loc, Location operator_loc, Node expression, Node body, Location end_keyword_loc, int startOffset, int length) { + public SingletonClassNode(String[] locals, Node expression, Node body, int startOffset, int length) { super(startOffset, length); this.locals = locals; - this.class_keyword_loc = class_keyword_loc; - this.operator_loc = operator_loc; this.expression = expression; this.body = body; - this.end_keyword_loc = end_keyword_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -4350,6 +6839,31 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitSingletonClassNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + String nextNextIndent = nextIndent + " "; + builder.append(nextIndent); + builder.append("locals: "); + builder.append('\n'); + for (String constant : this.locals) { + builder.append(nextNextIndent).append('"').append(constant).append('"').append('\n'); + } + builder.append(nextIndent); + builder.append("expression: "); + builder.append(this.expression.toString(nextIndent)); + builder.append(nextIndent); + builder.append("body: "); + builder.append(this.body == null ? "null\n" : this.body.toString(nextIndent)); + return builder.toString(); + } } // Represents the use of the `__ENCODING__` keyword. @@ -4372,6 +6886,18 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitSourceEncodingNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + return builder.toString(); + } } // Represents the use of the `__FILE__` keyword. @@ -4396,6 +6922,22 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitSourceFileNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("filepath: "); + builder.append('"' + new String(this.filepath, StandardCharsets.UTF_8) + '"'); + builder.append('\n'); + return builder.toString(); + } } // Represents the use of the `__LINE__` keyword. @@ -4418,6 +6960,18 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitSourceLineNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + return builder.toString(); + } } // Represents the use of the splat operator. @@ -4425,13 +6979,11 @@ public T accept(AbstractNodeVisitor visitor) { // [*a] // ^^ public static final class SplatNode extends Node { - public final Location operator_loc; /** optional (can be null) */ public final Node expression; - public SplatNode(Location operator_loc, Node expression, int startOffset, int length) { + public SplatNode(Node expression, int startOffset, int length) { super(startOffset, length); - this.operator_loc = operator_loc; this.expression = expression; } @@ -4448,6 +7000,21 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitSplatNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("expression: "); + builder.append(this.expression == null ? "null\n" : this.expression.toString(nextIndent)); + return builder.toString(); + } } // Represents a set of statements contained within some scope. @@ -4475,6 +7042,25 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitStatementsNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + String nextNextIndent = nextIndent + " "; + builder.append(nextIndent); + builder.append("body: "); + builder.append('\n'); + for (Node child : this.body) { + builder.append(nextNextIndent).append(child.toString(nextNextIndent)); + } + return builder.toString(); + } } // Represents the use of compile-time string concatenation. @@ -4503,6 +7089,24 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitStringConcatNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("left: "); + builder.append(this.left.toString(nextIndent)); + builder.append(nextIndent); + builder.append("right: "); + builder.append(this.right.toString(nextIndent)); + return builder.toString(); + } } // Represents a string literal, a string contained within a `%w` list, or @@ -4517,21 +7121,24 @@ public T accept(AbstractNodeVisitor visitor) { // "foo #{bar} baz" // ^^^^ ^^^^ public static final class StringNode extends Node { + public final short flags; /** optional (can be null) */ public final Location opening_loc; public final Location content_loc; - /** optional (can be null) */ - public final Location closing_loc; public final byte[] unescaped; - public StringNode(Location opening_loc, Location content_loc, Location closing_loc, byte[] unescaped, int startOffset, int length) { + public StringNode(short flags, Location opening_loc, Location content_loc, byte[] unescaped, int startOffset, int length) { super(startOffset, length); + this.flags = flags; this.opening_loc = opening_loc; this.content_loc = content_loc; - this.closing_loc = closing_loc; this.unescaped = unescaped; } - + + public boolean isFrozen() { + return StringFlags.isFrozen(this.flags); + } + public void visitChildNodes(AbstractNodeVisitor visitor) { } @@ -4542,6 +7149,26 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitStringNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + builder.append(nextIndent); + builder.append("unescaped: "); + builder.append('"' + new String(this.unescaped, StandardCharsets.UTF_8) + '"'); + builder.append('\n'); + return builder.toString(); + } } // Represents the use of the `super` keyword with parentheses or arguments. @@ -4552,22 +7179,14 @@ public T accept(AbstractNodeVisitor visitor) { // super foo, bar // ^^^^^^^^^^^^^^ public static final class SuperNode extends Node { - public final Location keyword_loc; - /** optional (can be null) */ - public final Location lparen_loc; /** optional (can be null) */ public final ArgumentsNode arguments; /** optional (can be null) */ - public final Location rparen_loc; - /** optional (can be null) */ - public final BlockNode block; + public final Node block; - public SuperNode(Location keyword_loc, Location lparen_loc, ArgumentsNode arguments, Location rparen_loc, BlockNode block, int startOffset, int length) { + public SuperNode(ArgumentsNode arguments, Node block, int startOffset, int length) { super(startOffset, length); - this.keyword_loc = keyword_loc; - this.lparen_loc = lparen_loc; this.arguments = arguments; - this.rparen_loc = rparen_loc; this.block = block; } @@ -4587,6 +7206,24 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitSuperNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("arguments: "); + builder.append(this.arguments == null ? "null\n" : this.arguments.toString(nextIndent)); + builder.append(nextIndent); + builder.append("block: "); + builder.append(this.block == null ? "null\n" : this.block.toString(nextIndent)); + return builder.toString(); + } } // Represents a symbol literal or a symbol contained within a `%i` list. @@ -4597,19 +7234,10 @@ public T accept(AbstractNodeVisitor visitor) { // %i[foo] // ^^^ public static final class SymbolNode extends Node { - /** optional (can be null) */ - public final Location opening_loc; - /** optional (can be null) */ - public final Location value_loc; - /** optional (can be null) */ - public final Location closing_loc; public final byte[] unescaped; - public SymbolNode(Location opening_loc, Location value_loc, Location closing_loc, byte[] unescaped, int startOffset, int length) { + public SymbolNode(byte[] unescaped, int startOffset, int length) { super(startOffset, length); - this.opening_loc = opening_loc; - this.value_loc = value_loc; - this.closing_loc = closing_loc; this.unescaped = unescaped; } @@ -4623,6 +7251,22 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitSymbolNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("unescaped: "); + builder.append('"' + new String(this.unescaped, StandardCharsets.UTF_8) + '"'); + builder.append('\n'); + return builder.toString(); + } } // Represents the use of the literal `true` keyword. @@ -4645,6 +7289,18 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitTrueNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + return builder.toString(); + } } // Represents the use of the `undef` keyword. @@ -4653,12 +7309,10 @@ public T accept(AbstractNodeVisitor visitor) { // ^^^^^^^^^^^^^^^^^^^^^^ public static final class UndefNode extends Node { public final Node[] names; - public final Location keyword_loc; - public UndefNode(Node[] names, Location keyword_loc, int startOffset, int length) { + public UndefNode(Node[] names, int startOffset, int length) { super(startOffset, length); this.names = names; - this.keyword_loc = keyword_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -4674,6 +7328,25 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitUndefNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + String nextNextIndent = nextIndent + " "; + builder.append(nextIndent); + builder.append("names: "); + builder.append('\n'); + for (Node child : this.names) { + builder.append(nextNextIndent).append(child.toString(nextNextIndent)); + } + return builder.toString(); + } } // Represents the use of the `unless` keyword, either in the block form or the modifier form. @@ -4684,22 +7357,17 @@ public T accept(AbstractNodeVisitor visitor) { // unless foo then bar end // ^^^^^^^^^^^^^^^^^^^^^^^ public static final class UnlessNode extends Node { - public final Location keyword_loc; public final Node predicate; /** optional (can be null) */ public final StatementsNode statements; /** optional (can be null) */ public final ElseNode consequent; - /** optional (can be null) */ - public final Location end_keyword_loc; - public UnlessNode(Location keyword_loc, Node predicate, StatementsNode statements, ElseNode consequent, Location end_keyword_loc, int startOffset, int length) { + public UnlessNode(Node predicate, StatementsNode statements, ElseNode consequent, int startOffset, int length) { super(startOffset, length); - this.keyword_loc = keyword_loc; this.predicate = predicate; this.statements = statements; this.consequent = consequent; - this.end_keyword_loc = end_keyword_loc; } @Override @@ -4724,6 +7392,27 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitUnlessNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("predicate: "); + builder.append(this.predicate.toString(nextIndent)); + builder.append(nextIndent); + builder.append("statements: "); + builder.append(this.statements == null ? "null\n" : this.statements.toString(nextIndent)); + builder.append(nextIndent); + builder.append("consequent: "); + builder.append(this.consequent == null ? "null\n" : this.consequent.toString(nextIndent)); + return builder.toString(); + } } // Represents the use of the `until` keyword, either in the block form or the modifier form. @@ -4734,18 +7423,13 @@ public T accept(AbstractNodeVisitor visitor) { // until foo do bar end // ^^^^^^^^^^^^^^^^^^^^ public static final class UntilNode extends Node { - public final Location keyword_loc; - /** optional (can be null) */ - public final Location closing_loc; public final Node predicate; /** optional (can be null) */ public final StatementsNode statements; public final short flags; - public UntilNode(Location keyword_loc, Location closing_loc, Node predicate, StatementsNode statements, short flags, int startOffset, int length) { + public UntilNode(Node predicate, StatementsNode statements, short flags, int startOffset, int length) { super(startOffset, length); - this.keyword_loc = keyword_loc; - this.closing_loc = closing_loc; this.predicate = predicate; this.statements = statements; this.flags = flags; @@ -4774,6 +7458,28 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitUntilNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("predicate: "); + builder.append(this.predicate.toString(nextIndent)); + builder.append(nextIndent); + builder.append("statements: "); + builder.append(this.statements == null ? "null\n" : this.statements.toString(nextIndent)); + builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + return builder.toString(); + } } // Represents the use of the `when` keyword within a case statement. @@ -4783,14 +7489,12 @@ public T accept(AbstractNodeVisitor visitor) { // ^^^^^^^^^ // end public static final class WhenNode extends Node { - public final Location keyword_loc; public final Node[] conditions; /** optional (can be null) */ public final StatementsNode statements; - public WhenNode(Location keyword_loc, Node[] conditions, StatementsNode statements, int startOffset, int length) { + public WhenNode(Node[] conditions, StatementsNode statements, int startOffset, int length) { super(startOffset, length); - this.keyword_loc = keyword_loc; this.conditions = conditions; this.statements = statements; } @@ -4814,6 +7518,28 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitWhenNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + String nextNextIndent = nextIndent + " "; + builder.append(nextIndent); + builder.append("conditions: "); + builder.append('\n'); + for (Node child : this.conditions) { + builder.append(nextNextIndent).append(child.toString(nextNextIndent)); + } + builder.append(nextIndent); + builder.append("statements: "); + builder.append(this.statements == null ? "null\n" : this.statements.toString(nextIndent)); + return builder.toString(); + } } // Represents the use of the `while` keyword, either in the block form or the modifier form. @@ -4824,18 +7550,13 @@ public T accept(AbstractNodeVisitor visitor) { // while foo do bar end // ^^^^^^^^^^^^^^^^^^^^ public static final class WhileNode extends Node { - public final Location keyword_loc; - /** optional (can be null) */ - public final Location closing_loc; public final Node predicate; /** optional (can be null) */ public final StatementsNode statements; public final short flags; - public WhileNode(Location keyword_loc, Location closing_loc, Node predicate, StatementsNode statements, short flags, int startOffset, int length) { + public WhileNode(Node predicate, StatementsNode statements, short flags, int startOffset, int length) { super(startOffset, length); - this.keyword_loc = keyword_loc; - this.closing_loc = closing_loc; this.predicate = predicate; this.statements = statements; this.flags = flags; @@ -4864,6 +7585,28 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitWhileNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("predicate: "); + builder.append(this.predicate.toString(nextIndent)); + builder.append(nextIndent); + builder.append("statements: "); + builder.append(this.statements == null ? "null\n" : this.statements.toString(nextIndent)); + builder.append(nextIndent); + builder.append("flags: "); + builder.append(this.flags); + builder.append('\n'); + return builder.toString(); + } } // Represents an xstring literal with no interpolation. @@ -4871,16 +7614,10 @@ public T accept(AbstractNodeVisitor visitor) { // `foo` // ^^^^^ public static final class XStringNode extends Node { - public final Location opening_loc; - public final Location content_loc; - public final Location closing_loc; public final byte[] unescaped; - public XStringNode(Location opening_loc, Location content_loc, Location closing_loc, byte[] unescaped, int startOffset, int length) { + public XStringNode(byte[] unescaped, int startOffset, int length) { super(startOffset, length); - this.opening_loc = opening_loc; - this.content_loc = content_loc; - this.closing_loc = closing_loc; this.unescaped = unescaped; } @@ -4894,6 +7631,22 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitXStringNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("unescaped: "); + builder.append('"' + new String(this.unescaped, StandardCharsets.UTF_8) + '"'); + builder.append('\n'); + return builder.toString(); + } } // Represents the use of the `yield` keyword. @@ -4901,20 +7654,12 @@ public T accept(AbstractNodeVisitor visitor) { // yield 1 // ^^^^^^^ public static final class YieldNode extends Node { - public final Location keyword_loc; - /** optional (can be null) */ - public final Location lparen_loc; /** optional (can be null) */ public final ArgumentsNode arguments; - /** optional (can be null) */ - public final Location rparen_loc; - public YieldNode(Location keyword_loc, Location lparen_loc, ArgumentsNode arguments, Location rparen_loc, int startOffset, int length) { + public YieldNode(ArgumentsNode arguments, int startOffset, int length) { super(startOffset, length); - this.keyword_loc = keyword_loc; - this.lparen_loc = lparen_loc; this.arguments = arguments; - this.rparen_loc = rparen_loc; } public void visitChildNodes(AbstractNodeVisitor visitor) { @@ -4930,6 +7675,21 @@ public Node[] childNodes() { public T accept(AbstractNodeVisitor visitor) { return visitor.visitYieldNode(this); } + + @Override + protected String toString(String indent) { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getSimpleName()); + if (hasNewLineFlag()) { + builder.append("[Li]"); + } + builder.append('\n'); + String nextIndent = indent + " "; + builder.append(nextIndent); + builder.append("arguments: "); + builder.append(this.arguments == null ? "null\n" : this.arguments.toString(nextIndent)); + return builder.toString(); + } } } From 3bb3466af575b37f005b3ae922d7aece0336e338 Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Thu, 14 Sep 2023 20:08:30 +0200 Subject: [PATCH 2/2] Adapt to YARP changes --- .../truffleruby/parser/YARPTranslator.java | 126 ++++++------------ tool/import-yarp.sh | 2 + 2 files changed, 42 insertions(+), 86 deletions(-) diff --git a/src/main/java/org/truffleruby/parser/YARPTranslator.java b/src/main/java/org/truffleruby/parser/YARPTranslator.java index b7bcc1b830ac..0973133561c6 100644 --- a/src/main/java/org/truffleruby/parser/YARPTranslator.java +++ b/src/main/java/org/truffleruby/parser/YARPTranslator.java @@ -174,21 +174,21 @@ public RubyRootNode translate(Nodes.Node node) { Split.HEURISTIC, null, Arity.NO_ARGUMENTS); } - public RubyNode visitAliasNode(Nodes.AliasNode node) { - RubyNode rubyNode; + @Override + public RubyNode visitAliasGlobalVariableNode(Nodes.AliasGlobalVariableNode node) { + RubyNode rubyNode = new AliasGlobalVarNode(toString(node.old_name), toString(node.new_name)); - if (node.new_name instanceof Nodes.GlobalVariableReadNode && - node.old_name instanceof Nodes.GlobalVariableReadNode) { - rubyNode = new AliasGlobalVarNode( - toString(node.old_name), - toString(node.new_name)); - } else { - // expected InterpolatedSymbolNode (that should be evaluated in runtime) - // or SymbolNode - rubyNode = new ModuleNodes.AliasKeywordNode( - node.new_name.accept(this), - node.old_name.accept(this)); - } + assignNodePositionInSource(node, rubyNode); + return rubyNode; + } + + @Override + public RubyNode visitAliasMethodNode(Nodes.AliasMethodNode node) { + // expected InterpolatedSymbolNode (that should be evaluated in runtime) + // or SymbolNode + RubyNode rubyNode = new ModuleNodes.AliasKeywordNode( + node.new_name.accept(this), + node.old_name.accept(this)); assignNodePositionInSource(node, rubyNode); return rubyNode; @@ -452,14 +452,6 @@ public RubyNode visitCallNode(Nodes.CallNode node) { return rubyCallNode; } - public RubyNode visitCallOperatorAndWriteNode(Nodes.CallOperatorAndWriteNode node) { - return defaultVisit(node); - } - - public RubyNode visitCallOperatorOrWriteNode(Nodes.CallOperatorOrWriteNode node) { - return defaultVisit(node); - } - public RubyNode visitCallOperatorWriteNode(Nodes.CallOperatorWriteNode node) { return defaultVisit(node); } @@ -473,30 +465,21 @@ public RubyNode visitCaseNode(Nodes.CaseNode node) { } public RubyNode visitClassNode(Nodes.ClassNode node) { - final String name; final RubyNode lexicalParent = translateCPath(node.constant_path); final RubyNode superClass; - if (node.constant_path instanceof Nodes.ConstantReadNode constantNode) { - name = toString(constantNode); - } else if (node.constant_path instanceof Nodes.ConstantPathNode pathNode) { - name = toString(pathNode.child); - } else { - throw CompilerDirectives.shouldNotReachHere(); - } - if (node.superclass != null) { superClass = node.superclass.accept(this); } else { superClass = null; } - final DefineClassNode defineOrGetClass = new DefineClassNode(name, lexicalParent, superClass); + final DefineClassNode defineOrGetClass = new DefineClassNode(node.name, lexicalParent, superClass); final RubyNode rubyNode = openModule( node, defineOrGetClass, - name, + node.name, node.body, OpenModule.CLASS, shouldUseDynamicConstantLookupForModuleBody(node)); @@ -508,7 +491,7 @@ public RubyNode visitClassNode(Nodes.ClassNode node) { public RubyNode visitClassVariableReadNode(Nodes.ClassVariableReadNode node) { final RubyNode rubyNode = new ReadClassVariableNode( getLexicalScopeNode("class variable lookup", node), - toString(node)); + node.name); assignNodePositionInSource(node, rubyNode); return rubyNode; @@ -518,7 +501,7 @@ public RubyNode visitClassVariableWriteNode(Nodes.ClassVariableWriteNode node) { final RubyNode rhs = node.value.accept(this); final RubyNode rubyNode = new WriteClassVariableNode( getLexicalScopeNode("set dynamic class variable", node), - toString(node.name), + node.name, rhs); assignNodePositionInSource(node, rubyNode); @@ -528,7 +511,7 @@ public RubyNode visitClassVariableWriteNode(Nodes.ClassVariableWriteNode node) { public RubyNode visitClassVariableTargetNode(Nodes.ClassVariableTargetNode node) { final RubyNode rubyNode = new WriteClassVariableNode( getLexicalScopeNode("set dynamic class variable", node), - toString(node.name), + node.name, null); assignNodePositionInSource(node, rubyNode); @@ -538,7 +521,7 @@ public RubyNode visitClassVariableTargetNode(Nodes.ClassVariableTargetNode node) public RubyNode visitConstantPathNode(Nodes.ConstantPathNode node) { assert node.child instanceof Nodes.ConstantReadNode; - final String name = toString(node.child); + final String name = ((Nodes.ConstantReadNode) node.child).name; final RubyNode moduleNode; if (node.parent != null) { @@ -567,7 +550,7 @@ public RubyNode visitConstantPathWriteNode(Nodes.ConstantPathWriteNode node) { moduleNode = new ObjectClassLiteralNode(); } - final String name = toString(constantPathNode.child); + final String name = ((Nodes.ConstantReadNode) constantPathNode.child).name; final RubyNode value = node.value.accept(this); final RubyNode rubyNode = new WriteConstantNode(name, moduleNode, value); @@ -585,7 +568,7 @@ public RubyNode visitConstantPathTargetNode(Nodes.ConstantPathTargetNode node) { moduleNode = new ObjectClassLiteralNode(); } - final String name = toString(node.child); + final String name = ((Nodes.ConstantReadNode) node.child).name; final RubyNode rubyNode = new WriteConstantNode(name, moduleNode, null); assignNodePositionInSource(node, rubyNode); @@ -594,7 +577,6 @@ public RubyNode visitConstantPathTargetNode(Nodes.ConstantPathTargetNode node) { public RubyNode visitConstantReadNode(Nodes.ConstantReadNode node) { final RubyNode rubyNode; - final String name = toString(node); if (environment.isDynamicConstantLookup()) { if (language.options.LOG_DYNAMIC_CONSTANT_LOOKUP) { @@ -602,10 +584,10 @@ public RubyNode visitConstantReadNode(Nodes.ConstantReadNode node) { RubyLanguage.getCurrentContext().fileLine(getSourceSection(node))); } - rubyNode = new ReadConstantWithDynamicScopeNode(name); + rubyNode = new ReadConstantWithDynamicScopeNode(node.name); } else { final LexicalScope lexicalScope = environment.getStaticLexicalScope(); - rubyNode = new ReadConstantWithLexicalScopeNode(lexicalScope, name); + rubyNode = new ReadConstantWithLexicalScopeNode(lexicalScope, node.name); } assignNodePositionInSource(node, rubyNode); @@ -613,19 +595,17 @@ public RubyNode visitConstantReadNode(Nodes.ConstantReadNode node) { } public RubyNode visitConstantWriteNode(Nodes.ConstantWriteNode node) { - final String name = toString(node.name_loc); final RubyNode value = node.value.accept(this); final RubyNode moduleNode = getLexicalScopeModuleNode("set dynamic constant", node); - final RubyNode rubyNode = new WriteConstantNode(name, moduleNode, value); + final RubyNode rubyNode = new WriteConstantNode(node.name, moduleNode, value); assignNodePositionInSource(node, rubyNode); return rubyNode; } public RubyNode visitConstantTargetNode(Nodes.ConstantTargetNode node) { - final String name = toString(node); final RubyNode moduleNode = getLexicalScopeModuleNode("set dynamic constant", node); - final RubyNode rubyNode = new WriteConstantNode(name, moduleNode, null); + final RubyNode rubyNode = new WriteConstantNode(node.name, moduleNode, null); assignNodePositionInSource(node, rubyNode); return rubyNode; @@ -725,23 +705,21 @@ public RubyNode visitForwardingSuperNode(Nodes.ForwardingSuperNode node) { } public RubyNode visitGlobalVariableReadNode(Nodes.GlobalVariableReadNode node) { - final RubyNode rubyNode = ReadGlobalVariableNodeGen.create(toString(node)); + final RubyNode rubyNode = ReadGlobalVariableNodeGen.create(node.name); assignNodePositionInSource(node, rubyNode); return rubyNode; } public RubyNode visitGlobalVariableWriteNode(Nodes.GlobalVariableWriteNode node) { - final String name = toString(node.name); final RubyNode value = node.value.accept(this); - final RubyNode rubyNode = WriteGlobalVariableNodeGen.create(name, value); + final RubyNode rubyNode = WriteGlobalVariableNodeGen.create(node.name, value); assignNodePositionInSource(node, rubyNode); return rubyNode; } public RubyNode visitGlobalVariableTargetNode(Nodes.GlobalVariableTargetNode node) { - final String name = toString(node.name); - final RubyNode rubyNode = WriteGlobalVariableNodeGen.create(name, null); + final RubyNode rubyNode = WriteGlobalVariableNodeGen.create(node.name, null); assignNodePositionInSource(node, rubyNode); return rubyNode; @@ -848,25 +826,22 @@ public RubyNode visitInNode(Nodes.InNode node) { } public RubyNode visitInstanceVariableReadNode(Nodes.InstanceVariableReadNode node) { - final String name = toString(node); - final RubyNode rubyNode = new ReadInstanceVariableNode(name); + final RubyNode rubyNode = new ReadInstanceVariableNode(node.name); assignNodePositionInSource(node, rubyNode); return rubyNode; } public RubyNode visitInstanceVariableWriteNode(Nodes.InstanceVariableWriteNode node) { - final String name = toString(node.name); final RubyNode value = node.value.accept(this); - final RubyNode rubyNode = WriteInstanceVariableNodeGen.create(name, value); + final RubyNode rubyNode = WriteInstanceVariableNodeGen.create(node.name, value); assignNodePositionInSource(node, rubyNode); return rubyNode; } public RubyNode visitInstanceVariableTargetNode(Nodes.InstanceVariableTargetNode node) { - final String name = toString(node.name); - final RubyNode rubyNode = WriteInstanceVariableNodeGen.create(name, null); + final RubyNode rubyNode = WriteInstanceVariableNodeGen.create(node.name, null); assignNodePositionInSource(node, rubyNode); return rubyNode; @@ -954,8 +929,7 @@ public RubyNode visitInterpolatedSymbolNode(Nodes.InterpolatedSymbolNode node) { } public RubyNode visitInterpolatedXStringNode(Nodes.InterpolatedXStringNode node) { - final Nodes.InterpolatedStringNode stringNode = new Nodes.InterpolatedStringNode( - node.opening_loc, node.parts, node.closing_loc, node.startOffset, node.length); + var stringNode = new Nodes.InterpolatedStringNode(node.parts, node.startOffset, node.length); final RubyNode string = stringNode.accept(this); final RubyNode rubyNode = createCallNode(new SelfNode(), "`", string); @@ -972,7 +946,7 @@ public RubyNode visitLambdaNode(Nodes.LambdaNode node) { } public RubyNode visitLocalVariableReadNode(Nodes.LocalVariableReadNode node) { - final String name = toString(node); + final String name = node.name; final RubyNode rubyNode = environment.findLocalVarNode(name, null); assert rubyNode != null : name; @@ -982,7 +956,7 @@ public RubyNode visitLocalVariableReadNode(Nodes.LocalVariableReadNode node) { } public RubyNode visitLocalVariableWriteNode(Nodes.LocalVariableWriteNode node) { - final String name = toString(node.name); + final String name = node.name; if (environment.getNeverAssignInParentScope()) { environment.declareVar(name); @@ -1016,8 +990,7 @@ public RubyNode visitLocalVariableWriteNode(Nodes.LocalVariableWriteNode node) { public RubyNode visitLocalVariableTargetNode(Nodes.LocalVariableTargetNode node) { // TODO: this could be done more directly but the logic of visitLocalVariableWriteNode() needs to be simpler first return visitLocalVariableWriteNode( - new Nodes.LocalVariableWriteNode(node.name, node.depth, null, null, null, node.startOffset, - node.length)); + new Nodes.LocalVariableWriteNode(node.name, node.depth, null, node.startOffset, node.length)); } public RubyNode visitMatchPredicateNode(Nodes.MatchPredicateNode node) { @@ -1033,23 +1006,14 @@ public RubyNode visitMissingNode(Nodes.MissingNode node) { } public RubyNode visitModuleNode(Nodes.ModuleNode node) { - final String name; final RubyNode lexicalParent = translateCPath(node.constant_path); - if (node.constant_path instanceof Nodes.ConstantReadNode constantNode) { - name = toString(constantNode); - } else if (node.constant_path instanceof Nodes.ConstantPathNode pathNode) { - name = toString(pathNode.child); - } else { - throw CompilerDirectives.shouldNotReachHere(); - } - - final DefineModuleNode defineModuleNode = DefineModuleNodeGen.create(name, lexicalParent); + final DefineModuleNode defineModuleNode = DefineModuleNodeGen.create(node.name, lexicalParent); final RubyNode rubyNode = openModule( node, defineModuleNode, - name, + node.name, node.body, OpenModule.MODULE, shouldUseDynamicConstantLookupForModuleBody(node)); @@ -1348,8 +1312,8 @@ public RubyNode visitWhileNode(Nodes.WhileNode node) { } public RubyNode visitXStringNode(Nodes.XStringNode node) { - final Nodes.StringNode stringNode = new Nodes.StringNode( - node.opening_loc, node.content_loc, node.closing_loc, node.unescaped, node.startOffset, node.length); + // TODO: pass flags, needs https://github.com/ruby/yarp/issues/1567 + var stringNode = new Nodes.StringNode((short) 0, null, null, node.unescaped, node.startOffset, node.length); final RubyNode string = stringNode.accept(this); final RubyNode rubyNode = createCallNode(new SelfNode(), "`", string); @@ -1694,16 +1658,6 @@ protected boolean isSideEffectFreeRescueExpression(Nodes.Node node) { node instanceof Nodes.NilNode; } - private String toString(byte[] bytes) { - return TStringUtils.toJavaStringOrThrow( - TruffleString.fromByteArrayUncached(bytes, sourceEncoding.tencoding, false), sourceEncoding); - } - - private String toString(Nodes.Location location) { - return TStringUtils.toJavaStringOrThrow(TruffleString.fromByteArrayUncached(sourceBytes, location.startOffset, - location.length, sourceEncoding.tencoding, false), sourceEncoding); - } - private String toString(Nodes.Node node) { return TStringUtils.toJavaStringOrThrow(TruffleString.fromByteArrayUncached(sourceBytes, node.startOffset, node.length, sourceEncoding.tencoding, false), sourceEncoding); diff --git a/tool/import-yarp.sh b/tool/import-yarp.sh index b39b6c6cc8d1..14e6345baf0f 100755 --- a/tool/import-yarp.sh +++ b/tool/import-yarp.sh @@ -5,6 +5,8 @@ set -e YARP=../../yarp +export YARP_SERIALIZE_ONLY_SEMANTICS_FIELDS=1 + # Create generated files pushd $YARP bundle