diff --git a/spec/truffle/parsing/fixtures/operators/||=/reference_assignment_with_splatted_argument.yaml b/spec/truffle/parsing/fixtures/operators/||=/reference_assignment_with_splatted_argument.yaml index f96da26e19c..a964e89cb2a 100644 --- a/spec/truffle/parsing/fixtures/operators/||=/reference_assignment_with_splatted_argument.yaml +++ b/spec/truffle/parsing/fixtures/operators/||=/reference_assignment_with_splatted_argument.yaml @@ -1,5 +1,5 @@ subject: "||=" -description: "Assign an element referenced with splatted argument (a[*b] &&= c)" +description: "Assign an element referenced with splatted argument (a[*b] ||= c)" notes: > Splatting should be specified explicitly for `[]` and `[]=` method calls. diff --git a/src/main/c/yarp/include/prism/ast.h b/src/main/c/yarp/include/prism/ast.h index cf55cfe79c8..148f574360e 100644 --- a/src/main/c/yarp/include/prism/ast.h +++ b/src/main/c/yarp/include/prism/ast.h @@ -1100,7 +1100,7 @@ typedef struct pm_node { * alias $foo $bar * ^^^^^^^^^^^^^^^ * - * Type: PM_ALIAS_GLOBAL_VARIABLE_NODE + * Type: ::PM_ALIAS_GLOBAL_VARIABLE_NODE * * @extends pm_node_t */ @@ -1108,6 +1108,7 @@ typedef struct pm_alias_global_variable_node { /** The embedded base node. */ pm_node_t base; + /** * AliasGlobalVariableNode#new_name * @@ -1147,7 +1148,7 @@ typedef struct pm_alias_global_variable_node { * alias foo bar * ^^^^^^^^^^^^^ * - * Type: PM_ALIAS_METHOD_NODE + * Type: ::PM_ALIAS_METHOD_NODE * * @extends pm_node_t */ @@ -1155,13 +1156,36 @@ typedef struct pm_alias_method_node { /** The embedded base node. */ pm_node_t base; + /** * AliasMethodNode#new_name + * + * Represents the new name of the method that will be aliased. + * + * alias foo bar + * ^^^ + * + * alias :foo :bar + * ^^^^ + * + * alias :"#{foo}" :"#{bar}" + * ^^^^^^^^^ */ struct pm_node *new_name; /** * AliasMethodNode#old_name + * + * Represents the old name of the method that will be aliased. + * + * alias foo bar + * ^^^ + * + * alias :foo :bar + * ^^^^ + * + * alias :"#{foo}" :"#{bar}" + * ^^^^^^^^^ */ struct pm_node *old_name; @@ -1179,7 +1203,7 @@ typedef struct pm_alias_method_node { * foo => bar | baz * ^^^^^^^^^ * - * Type: PM_ALTERNATION_PATTERN_NODE + * Type: ::PM_ALTERNATION_PATTERN_NODE * * @extends pm_node_t */ @@ -1187,18 +1211,34 @@ typedef struct pm_alternation_pattern_node { /** The embedded base node. */ pm_node_t base; + /** * AlternationPatternNode#left + * + * Represents the left side of the expression. + * + * foo => bar | baz + * ^^^ */ struct pm_node *left; /** * AlternationPatternNode#right + * + * Represents the right side of the expression. + * + * foo => bar | baz + * ^^^ */ struct pm_node *right; /** * AlternationPatternNode#operator_loc + * + * Represents the alternation operator location. + * + * foo => bar | baz + * ^ */ pm_location_t operator_loc; } pm_alternation_pattern_node_t; @@ -1211,7 +1251,7 @@ typedef struct pm_alternation_pattern_node { * left and right * ^^^^^^^^^^^^^^ * - * Type: PM_AND_NODE + * Type: ::PM_AND_NODE * * @extends pm_node_t */ @@ -1219,6 +1259,7 @@ typedef struct pm_and_node { /** The embedded base node. */ pm_node_t base; + /** * AndNode#left * @@ -1235,7 +1276,7 @@ typedef struct pm_and_node { /** * AndNode#right * - * Represents the right side of the expression. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). + * Represents the right side of the expression. * * left && right * ^^^^^ @@ -1264,11 +1305,14 @@ typedef struct pm_and_node { * return foo, bar, baz * ^^^^^^^^^^^^^ * - * Type: PM_ARGUMENTS_NODE - * Flags: - * PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS - * PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT - * PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT + * Type: ::PM_ARGUMENTS_NODE + + * Flags (#pm_arguments_node_flags): + * * ::PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING + * * ::PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS + * * ::PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT + * * ::PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT + * * ::PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS * * @extends pm_node_t */ @@ -1276,6 +1320,7 @@ typedef struct pm_arguments_node { /** The embedded base node. */ pm_node_t base; + /** * ArgumentsNode#arguments */ @@ -1290,9 +1335,10 @@ typedef struct pm_arguments_node { * [1, 2, 3] * ^^^^^^^^^ * - * Type: PM_ARRAY_NODE - * Flags: - * PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT + * Type: ::PM_ARRAY_NODE + + * Flags (#pm_array_node_flags): + * * ::PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT * * @extends pm_node_t */ @@ -1300,6 +1346,7 @@ typedef struct pm_array_node { /** The embedded base node. */ pm_node_t base; + /** * ArrayNode#elements * @@ -1352,7 +1399,7 @@ typedef struct pm_array_node { * foo in Bar[1, 2, 3] * ^^^^^^^^^^^^^^^^^^^ * - * Type: PM_ARRAY_PATTERN_NODE + * Type: ::PM_ARRAY_PATTERN_NODE * * @extends pm_node_t */ @@ -1360,6 +1407,7 @@ typedef struct pm_array_pattern_node { /** The embedded base node. */ pm_node_t base; + /** * ArrayPatternNode#constant */ @@ -1399,7 +1447,7 @@ typedef struct pm_array_pattern_node { * { a => b } * ^^^^^^ * - * Type: PM_ASSOC_NODE + * Type: ::PM_ASSOC_NODE * * @extends pm_node_t */ @@ -1407,6 +1455,7 @@ typedef struct pm_assoc_node { /** The embedded base node. */ pm_node_t base; + /** * AssocNode#key * @@ -1455,7 +1504,7 @@ typedef struct pm_assoc_node { * { **foo } * ^^^^^ * - * Type: PM_ASSOC_SPLAT_NODE + * Type: ::PM_ASSOC_SPLAT_NODE * * @extends pm_node_t */ @@ -1463,6 +1512,7 @@ typedef struct pm_assoc_splat_node { /** The embedded base node. */ pm_node_t base; + /** * AssocSplatNode#value * @@ -1492,7 +1542,7 @@ typedef struct pm_assoc_splat_node { * $' * ^^ * - * Type: PM_BACK_REFERENCE_READ_NODE + * Type: ::PM_BACK_REFERENCE_READ_NODE * * @extends pm_node_t */ @@ -1500,6 +1550,7 @@ typedef struct pm_back_reference_read_node { /** The embedded base node. */ pm_node_t base; + /** * BackReferenceReadNode#name * @@ -1522,7 +1573,7 @@ typedef struct pm_back_reference_read_node { * end * ^^^^^ * - * Type: PM_BEGIN_NODE + * Type: ::PM_BEGIN_NODE * * @extends pm_node_t */ @@ -1530,6 +1581,7 @@ typedef struct pm_begin_node { /** The embedded base node. */ pm_node_t base; + /** * BeginNode#begin_keyword_loc */ @@ -1569,7 +1621,7 @@ typedef struct pm_begin_node { * bar(&args) * ^^^^^^^^^^ * - * Type: PM_BLOCK_ARGUMENT_NODE + * Type: ::PM_BLOCK_ARGUMENT_NODE * * @extends pm_node_t */ @@ -1577,6 +1629,7 @@ typedef struct pm_block_argument_node { /** The embedded base node. */ pm_node_t base; + /** * BlockArgumentNode#expression */ @@ -1596,9 +1649,10 @@ typedef struct pm_block_argument_node { * a { |; b| } * ^ * - * Type: PM_BLOCK_LOCAL_VARIABLE_NODE - * Flags: - * PM_PARAMETER_FLAGS_REPEATED_PARAMETER + * Type: ::PM_BLOCK_LOCAL_VARIABLE_NODE + + * Flags (#pm_parameter_flags): + * * ::PM_PARAMETER_FLAGS_REPEATED_PARAMETER * * @extends pm_node_t */ @@ -1606,6 +1660,7 @@ typedef struct pm_block_local_variable_node { /** The embedded base node. */ pm_node_t base; + /** * BlockLocalVariableNode#name */ @@ -1620,7 +1675,7 @@ typedef struct pm_block_local_variable_node { * [1, 2, 3].each { |i| puts x } * ^^^^^^^^^^^^^^ * - * Type: PM_BLOCK_NODE + * Type: ::PM_BLOCK_NODE * * @extends pm_node_t */ @@ -1628,6 +1683,7 @@ typedef struct pm_block_node { /** The embedded base node. */ pm_node_t base; + /** * BlockNode#locals */ @@ -1663,9 +1719,10 @@ typedef struct pm_block_node { * ^^ * end * - * Type: PM_BLOCK_PARAMETER_NODE - * Flags: - * PM_PARAMETER_FLAGS_REPEATED_PARAMETER + * Type: ::PM_BLOCK_PARAMETER_NODE + + * Flags (#pm_parameter_flags): + * * ::PM_PARAMETER_FLAGS_REPEATED_PARAMETER * * @extends pm_node_t */ @@ -1673,6 +1730,7 @@ typedef struct pm_block_parameter_node { /** The embedded base node. */ pm_node_t base; + /** * BlockParameterNode#name */ @@ -1701,7 +1759,7 @@ typedef struct pm_block_parameter_node { * ^^^^^^^^^^^^^^^^^ * end * - * Type: PM_BLOCK_PARAMETERS_NODE + * Type: ::PM_BLOCK_PARAMETERS_NODE * * @extends pm_node_t */ @@ -1709,6 +1767,7 @@ typedef struct pm_block_parameters_node { /** The embedded base node. */ pm_node_t base; + /** * BlockParametersNode#parameters */ @@ -1738,7 +1797,7 @@ typedef struct pm_block_parameters_node { * break foo * ^^^^^^^^^ * - * Type: PM_BREAK_NODE + * Type: ::PM_BREAK_NODE * * @extends pm_node_t */ @@ -1746,6 +1805,7 @@ typedef struct pm_break_node { /** The embedded base node. */ pm_node_t base; + /** * BreakNode#arguments * @@ -1775,12 +1835,13 @@ typedef struct pm_break_node { * foo.bar &&= value * ^^^^^^^^^^^^^^^^^ * - * Type: PM_CALL_AND_WRITE_NODE - * Flags: - * PM_CALL_NODE_FLAGS_SAFE_NAVIGATION - * PM_CALL_NODE_FLAGS_VARIABLE_CALL - * PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE - * PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY + * Type: ::PM_CALL_AND_WRITE_NODE + + * Flags (#pm_call_node_flags): + * * ::PM_CALL_NODE_FLAGS_SAFE_NAVIGATION + * * ::PM_CALL_NODE_FLAGS_VARIABLE_CALL + * * ::PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE + * * ::PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY * * @extends pm_node_t */ @@ -1788,6 +1849,7 @@ typedef struct pm_call_and_write_node { /** The embedded base node. */ pm_node_t base; + /** * CallAndWriteNode#receiver */ @@ -1847,12 +1909,13 @@ typedef struct pm_call_and_write_node { * foo&.bar * ^^^^^^^^ * - * Type: PM_CALL_NODE - * Flags: - * PM_CALL_NODE_FLAGS_SAFE_NAVIGATION - * PM_CALL_NODE_FLAGS_VARIABLE_CALL - * PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE - * PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY + * Type: ::PM_CALL_NODE + + * Flags (#pm_call_node_flags): + * * ::PM_CALL_NODE_FLAGS_SAFE_NAVIGATION + * * ::PM_CALL_NODE_FLAGS_VARIABLE_CALL + * * ::PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE + * * ::PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY * * @extends pm_node_t */ @@ -1860,6 +1923,7 @@ typedef struct pm_call_node { /** The embedded base node. */ pm_node_t base; + /** * CallNode#receiver * @@ -1920,12 +1984,13 @@ typedef struct pm_call_node { * foo.bar += baz * ^^^^^^^^^^^^^^ * - * Type: PM_CALL_OPERATOR_WRITE_NODE - * Flags: - * PM_CALL_NODE_FLAGS_SAFE_NAVIGATION - * PM_CALL_NODE_FLAGS_VARIABLE_CALL - * PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE - * PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY + * Type: ::PM_CALL_OPERATOR_WRITE_NODE + + * Flags (#pm_call_node_flags): + * * ::PM_CALL_NODE_FLAGS_SAFE_NAVIGATION + * * ::PM_CALL_NODE_FLAGS_VARIABLE_CALL + * * ::PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE + * * ::PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY * * @extends pm_node_t */ @@ -1933,6 +1998,7 @@ typedef struct pm_call_operator_write_node { /** The embedded base node. */ pm_node_t base; + /** * CallOperatorWriteNode#receiver */ @@ -1982,12 +2048,13 @@ typedef struct pm_call_operator_write_node { * foo.bar ||= value * ^^^^^^^^^^^^^^^^^ * - * Type: PM_CALL_OR_WRITE_NODE - * Flags: - * PM_CALL_NODE_FLAGS_SAFE_NAVIGATION - * PM_CALL_NODE_FLAGS_VARIABLE_CALL - * PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE - * PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY + * Type: ::PM_CALL_OR_WRITE_NODE + + * Flags (#pm_call_node_flags): + * * ::PM_CALL_NODE_FLAGS_SAFE_NAVIGATION + * * ::PM_CALL_NODE_FLAGS_VARIABLE_CALL + * * ::PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE + * * ::PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY * * @extends pm_node_t */ @@ -1995,6 +2062,7 @@ typedef struct pm_call_or_write_node { /** The embedded base node. */ pm_node_t base; + /** * CallOrWriteNode#receiver */ @@ -2047,12 +2115,13 @@ typedef struct pm_call_or_write_node { * for foo.bar in baz do end * ^^^^^^^ * - * Type: PM_CALL_TARGET_NODE - * Flags: - * PM_CALL_NODE_FLAGS_SAFE_NAVIGATION - * PM_CALL_NODE_FLAGS_VARIABLE_CALL - * PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE - * PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY + * Type: ::PM_CALL_TARGET_NODE + + * Flags (#pm_call_node_flags): + * * ::PM_CALL_NODE_FLAGS_SAFE_NAVIGATION + * * ::PM_CALL_NODE_FLAGS_VARIABLE_CALL + * * ::PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE + * * ::PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY * * @extends pm_node_t */ @@ -2060,6 +2129,7 @@ typedef struct pm_call_target_node { /** The embedded base node. */ pm_node_t base; + /** * CallTargetNode#receiver */ @@ -2089,7 +2159,7 @@ typedef struct pm_call_target_node { * foo => [bar => baz] * ^^^^^^^^^^^^ * - * Type: PM_CAPTURE_PATTERN_NODE + * Type: ::PM_CAPTURE_PATTERN_NODE * * @extends pm_node_t */ @@ -2097,6 +2167,7 @@ typedef struct pm_capture_pattern_node { /** The embedded base node. */ pm_node_t base; + /** * CapturePatternNode#value */ @@ -2105,7 +2176,7 @@ typedef struct pm_capture_pattern_node { /** * CapturePatternNode#target */ - struct pm_node *target; + struct pm_local_variable_target_node *target; /** * CapturePatternNode#operator_loc @@ -2123,7 +2194,7 @@ typedef struct pm_capture_pattern_node { * end * ^^^^^^^^^ * - * Type: PM_CASE_MATCH_NODE + * Type: ::PM_CASE_MATCH_NODE * * @extends pm_node_t */ @@ -2131,6 +2202,7 @@ typedef struct pm_case_match_node { /** The embedded base node. */ pm_node_t base; + /** * CaseMatchNode#predicate */ @@ -2167,7 +2239,7 @@ typedef struct pm_case_match_node { * end * ^^^^^^^^^^ * - * Type: PM_CASE_NODE + * Type: ::PM_CASE_NODE * * @extends pm_node_t */ @@ -2175,6 +2247,7 @@ typedef struct pm_case_node { /** The embedded base node. */ pm_node_t base; + /** * CaseNode#predicate */ @@ -2209,7 +2282,7 @@ typedef struct pm_case_node { * class Foo end * ^^^^^^^^^^^^^ * - * Type: PM_CLASS_NODE + * Type: ::PM_CLASS_NODE * * @extends pm_node_t */ @@ -2217,6 +2290,7 @@ typedef struct pm_class_node { /** The embedded base node. */ pm_node_t base; + /** * ClassNode#locals */ @@ -2266,7 +2340,7 @@ typedef struct pm_class_node { * @@target &&= value * ^^^^^^^^^^^^^^^^^^ * - * Type: PM_CLASS_VARIABLE_AND_WRITE_NODE + * Type: ::PM_CLASS_VARIABLE_AND_WRITE_NODE * * @extends pm_node_t */ @@ -2274,6 +2348,7 @@ typedef struct pm_class_variable_and_write_node { /** The embedded base node. */ pm_node_t base; + /** * ClassVariableAndWriteNode#name */ @@ -2303,7 +2378,7 @@ typedef struct pm_class_variable_and_write_node { * @@target += value * ^^^^^^^^^^^^^^^^^ * - * Type: PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE + * Type: ::PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE * * @extends pm_node_t */ @@ -2311,6 +2386,7 @@ typedef struct pm_class_variable_operator_write_node { /** The embedded base node. */ pm_node_t base; + /** * ClassVariableOperatorWriteNode#name */ @@ -2345,7 +2421,7 @@ typedef struct pm_class_variable_operator_write_node { * @@target ||= value * ^^^^^^^^^^^^^^^^^^ * - * Type: PM_CLASS_VARIABLE_OR_WRITE_NODE + * Type: ::PM_CLASS_VARIABLE_OR_WRITE_NODE * * @extends pm_node_t */ @@ -2353,6 +2429,7 @@ typedef struct pm_class_variable_or_write_node { /** The embedded base node. */ pm_node_t base; + /** * ClassVariableOrWriteNode#name */ @@ -2382,7 +2459,7 @@ typedef struct pm_class_variable_or_write_node { * @@foo * ^^^^^ * - * Type: PM_CLASS_VARIABLE_READ_NODE + * Type: ::PM_CLASS_VARIABLE_READ_NODE * * @extends pm_node_t */ @@ -2390,6 +2467,7 @@ typedef struct pm_class_variable_read_node { /** The embedded base node. */ pm_node_t base; + /** * ClassVariableReadNode#name * @@ -2410,7 +2488,7 @@ typedef struct pm_class_variable_read_node { * @@foo, @@bar = baz * ^^^^^ ^^^^^ * - * Type: PM_CLASS_VARIABLE_TARGET_NODE + * Type: ::PM_CLASS_VARIABLE_TARGET_NODE * * @extends pm_node_t */ @@ -2418,6 +2496,7 @@ typedef struct pm_class_variable_target_node { /** The embedded base node. */ pm_node_t base; + /** * ClassVariableTargetNode#name */ @@ -2432,7 +2511,7 @@ typedef struct pm_class_variable_target_node { * @@foo = 1 * ^^^^^^^^^ * - * Type: PM_CLASS_VARIABLE_WRITE_NODE + * Type: ::PM_CLASS_VARIABLE_WRITE_NODE * * @extends pm_node_t */ @@ -2440,6 +2519,7 @@ typedef struct pm_class_variable_write_node { /** The embedded base node. */ pm_node_t base; + /** * ClassVariableWriteNode#name * @@ -2493,7 +2573,7 @@ typedef struct pm_class_variable_write_node { * Target &&= value * ^^^^^^^^^^^^^^^^ * - * Type: PM_CONSTANT_AND_WRITE_NODE + * Type: ::PM_CONSTANT_AND_WRITE_NODE * * @extends pm_node_t */ @@ -2501,6 +2581,7 @@ typedef struct pm_constant_and_write_node { /** The embedded base node. */ pm_node_t base; + /** * ConstantAndWriteNode#name */ @@ -2530,7 +2611,7 @@ typedef struct pm_constant_and_write_node { * Target += value * ^^^^^^^^^^^^^^^ * - * Type: PM_CONSTANT_OPERATOR_WRITE_NODE + * Type: ::PM_CONSTANT_OPERATOR_WRITE_NODE * * @extends pm_node_t */ @@ -2538,6 +2619,7 @@ typedef struct pm_constant_operator_write_node { /** The embedded base node. */ pm_node_t base; + /** * ConstantOperatorWriteNode#name */ @@ -2572,7 +2654,7 @@ typedef struct pm_constant_operator_write_node { * Target ||= value * ^^^^^^^^^^^^^^^^ * - * Type: PM_CONSTANT_OR_WRITE_NODE + * Type: ::PM_CONSTANT_OR_WRITE_NODE * * @extends pm_node_t */ @@ -2580,6 +2662,7 @@ typedef struct pm_constant_or_write_node { /** The embedded base node. */ pm_node_t base; + /** * ConstantOrWriteNode#name */ @@ -2609,7 +2692,7 @@ typedef struct pm_constant_or_write_node { * Parent::Child &&= value * ^^^^^^^^^^^^^^^^^^^^^^^ * - * Type: PM_CONSTANT_PATH_AND_WRITE_NODE + * Type: ::PM_CONSTANT_PATH_AND_WRITE_NODE * * @extends pm_node_t */ @@ -2617,6 +2700,7 @@ typedef struct pm_constant_path_and_write_node { /** The embedded base node. */ pm_node_t base; + /** * ConstantPathAndWriteNode#target */ @@ -2641,7 +2725,7 @@ typedef struct pm_constant_path_and_write_node { * Foo::Bar * ^^^^^^^^ * - * Type: PM_CONSTANT_PATH_NODE + * Type: ::PM_CONSTANT_PATH_NODE * * @extends pm_node_t */ @@ -2649,6 +2733,7 @@ typedef struct pm_constant_path_node { /** The embedded base node. */ pm_node_t base; + /** * ConstantPathNode#parent * @@ -2707,7 +2792,7 @@ typedef struct pm_constant_path_node { * Parent::Child += value * ^^^^^^^^^^^^^^^^^^^^^^ * - * Type: PM_CONSTANT_PATH_OPERATOR_WRITE_NODE + * Type: ::PM_CONSTANT_PATH_OPERATOR_WRITE_NODE * * @extends pm_node_t */ @@ -2715,6 +2800,7 @@ typedef struct pm_constant_path_operator_write_node { /** The embedded base node. */ pm_node_t base; + /** * ConstantPathOperatorWriteNode#target */ @@ -2744,7 +2830,7 @@ typedef struct pm_constant_path_operator_write_node { * Parent::Child ||= value * ^^^^^^^^^^^^^^^^^^^^^^^ * - * Type: PM_CONSTANT_PATH_OR_WRITE_NODE + * Type: ::PM_CONSTANT_PATH_OR_WRITE_NODE * * @extends pm_node_t */ @@ -2752,6 +2838,7 @@ typedef struct pm_constant_path_or_write_node { /** The embedded base node. */ pm_node_t base; + /** * ConstantPathOrWriteNode#target */ @@ -2776,7 +2863,7 @@ typedef struct pm_constant_path_or_write_node { * Foo::Foo, Bar::Bar = baz * ^^^^^^^^ ^^^^^^^^ * - * Type: PM_CONSTANT_PATH_TARGET_NODE + * Type: ::PM_CONSTANT_PATH_TARGET_NODE * * @extends pm_node_t */ @@ -2784,6 +2871,7 @@ typedef struct pm_constant_path_target_node { /** The embedded base node. */ pm_node_t base; + /** * ConstantPathTargetNode#parent */ @@ -2819,7 +2907,7 @@ typedef struct pm_constant_path_target_node { * ::Foo::Bar = 1 * ^^^^^^^^^^^^^^ * - * Type: PM_CONSTANT_PATH_WRITE_NODE + * Type: ::PM_CONSTANT_PATH_WRITE_NODE * * @extends pm_node_t */ @@ -2827,6 +2915,7 @@ typedef struct pm_constant_path_write_node { /** The embedded base node. */ pm_node_t base; + /** * ConstantPathWriteNode#target * @@ -2869,7 +2958,7 @@ typedef struct pm_constant_path_write_node { * Foo * ^^^ * - * Type: PM_CONSTANT_READ_NODE + * Type: ::PM_CONSTANT_READ_NODE * * @extends pm_node_t */ @@ -2877,6 +2966,7 @@ typedef struct pm_constant_read_node { /** The embedded base node. */ pm_node_t base; + /** * ConstantReadNode#name * @@ -2897,7 +2987,7 @@ typedef struct pm_constant_read_node { * Foo, Bar = baz * ^^^ ^^^ * - * Type: PM_CONSTANT_TARGET_NODE + * Type: ::PM_CONSTANT_TARGET_NODE * * @extends pm_node_t */ @@ -2905,6 +2995,7 @@ typedef struct pm_constant_target_node { /** The embedded base node. */ pm_node_t base; + /** * ConstantTargetNode#name */ @@ -2919,7 +3010,7 @@ typedef struct pm_constant_target_node { * Foo = 1 * ^^^^^^^ * - * Type: PM_CONSTANT_WRITE_NODE + * Type: ::PM_CONSTANT_WRITE_NODE * * @extends pm_node_t */ @@ -2927,6 +3018,7 @@ typedef struct pm_constant_write_node { /** The embedded base node. */ pm_node_t base; + /** * ConstantWriteNode#name * @@ -2981,7 +3073,7 @@ typedef struct pm_constant_write_node { * end * ^^^^^^^^^^ * - * Type: PM_DEF_NODE + * Type: ::PM_DEF_NODE * * @extends pm_node_t */ @@ -2989,6 +3081,7 @@ typedef struct pm_def_node { /** The embedded base node. */ pm_node_t base; + /** * DefNode#name */ @@ -3058,7 +3151,7 @@ typedef struct pm_def_node { * defined?(a) * ^^^^^^^^^^^ * - * Type: PM_DEFINED_NODE + * Type: ::PM_DEFINED_NODE * * @extends pm_node_t */ @@ -3066,6 +3159,7 @@ typedef struct pm_defined_node { /** The embedded base node. */ pm_node_t base; + /** * DefinedNode#lparen_loc */ @@ -3095,7 +3189,7 @@ typedef struct pm_defined_node { * if a then b else c end * ^^^^^^^^^^ * - * Type: PM_ELSE_NODE + * Type: ::PM_ELSE_NODE * * @extends pm_node_t */ @@ -3103,6 +3197,7 @@ typedef struct pm_else_node { /** The embedded base node. */ pm_node_t base; + /** * ElseNode#else_keyword_loc */ @@ -3127,7 +3222,7 @@ typedef struct pm_else_node { * "foo #{bar}" * ^^^^^^ * - * Type: PM_EMBEDDED_STATEMENTS_NODE + * Type: ::PM_EMBEDDED_STATEMENTS_NODE * * @extends pm_node_t */ @@ -3135,6 +3230,7 @@ typedef struct pm_embedded_statements_node { /** The embedded base node. */ pm_node_t base; + /** * EmbeddedStatementsNode#opening_loc */ @@ -3159,7 +3255,7 @@ typedef struct pm_embedded_statements_node { * "foo #@bar" * ^^^^^ * - * Type: PM_EMBEDDED_VARIABLE_NODE + * Type: ::PM_EMBEDDED_VARIABLE_NODE * * @extends pm_node_t */ @@ -3167,6 +3263,7 @@ typedef struct pm_embedded_variable_node { /** The embedded base node. */ pm_node_t base; + /** * EmbeddedVariableNode#operator_loc */ @@ -3190,7 +3287,7 @@ typedef struct pm_embedded_variable_node { * bar * end * - * Type: PM_ENSURE_NODE + * Type: ::PM_ENSURE_NODE * * @extends pm_node_t */ @@ -3198,6 +3295,7 @@ typedef struct pm_ensure_node { /** The embedded base node. */ pm_node_t base; + /** * EnsureNode#ensure_keyword_loc */ @@ -3222,13 +3320,14 @@ typedef struct pm_ensure_node { * false * ^^^^^ * - * Type: PM_FALSE_NODE + * Type: ::PM_FALSE_NODE * * @extends pm_node_t */ typedef struct pm_false_node { /** The embedded base node. */ pm_node_t base; + } pm_false_node_t; /** @@ -3245,7 +3344,7 @@ typedef struct pm_false_node { * foo in Foo(*bar, baz, *qux) * ^^^^^^^^^^^^^^^^^^^^ * - * Type: PM_FIND_PATTERN_NODE + * Type: ::PM_FIND_PATTERN_NODE * * @extends pm_node_t */ @@ -3253,6 +3352,7 @@ typedef struct pm_find_pattern_node { /** The embedded base node. */ pm_node_t base; + /** * FindPatternNode#constant */ @@ -3261,7 +3361,7 @@ typedef struct pm_find_pattern_node { /** * FindPatternNode#left */ - struct pm_node *left; + struct pm_splat_node *left; /** * FindPatternNode#requireds @@ -3271,7 +3371,7 @@ typedef struct pm_find_pattern_node { /** * FindPatternNode#right */ - struct pm_node *right; + struct pm_splat_node *right; /** * FindPatternNode#opening_loc @@ -3292,9 +3392,10 @@ typedef struct pm_find_pattern_node { * baz if foo .. bar * ^^^^^^^^^^ * - * Type: PM_FLIP_FLOP_NODE - * Flags: - * PM_RANGE_FLAGS_EXCLUDE_END + * Type: ::PM_FLIP_FLOP_NODE + + * Flags (#pm_range_flags): + * * ::PM_RANGE_FLAGS_EXCLUDE_END * * @extends pm_node_t */ @@ -3302,6 +3403,7 @@ typedef struct pm_flip_flop_node { /** The embedded base node. */ pm_node_t base; + /** * FlipFlopNode#left */ @@ -3326,7 +3428,7 @@ typedef struct pm_flip_flop_node { * 1.0 * ^^^ * - * Type: PM_FLOAT_NODE + * Type: ::PM_FLOAT_NODE * * @extends pm_node_t */ @@ -3334,6 +3436,7 @@ typedef struct pm_float_node { /** The embedded base node. */ pm_node_t base; + /** * FloatNode#value * @@ -3350,7 +3453,7 @@ typedef struct pm_float_node { * for i in a end * ^^^^^^^^^^^^^^ * - * Type: PM_FOR_NODE + * Type: ::PM_FOR_NODE * * @extends pm_node_t */ @@ -3358,6 +3461,7 @@ typedef struct pm_for_node { /** The embedded base node. */ pm_node_t base; + /** * ForNode#index * @@ -3441,13 +3545,14 @@ typedef struct pm_for_node { * ^^^ * end * - * Type: PM_FORWARDING_ARGUMENTS_NODE + * Type: ::PM_FORWARDING_ARGUMENTS_NODE * * @extends pm_node_t */ typedef struct pm_forwarding_arguments_node { /** The embedded base node. */ pm_node_t base; + } pm_forwarding_arguments_node_t; /** @@ -3459,13 +3564,14 @@ typedef struct pm_forwarding_arguments_node { * ^^^ * end * - * Type: PM_FORWARDING_PARAMETER_NODE + * Type: ::PM_FORWARDING_PARAMETER_NODE * * @extends pm_node_t */ typedef struct pm_forwarding_parameter_node { /** The embedded base node. */ pm_node_t base; + } pm_forwarding_parameter_node_t; /** @@ -3476,7 +3582,7 @@ typedef struct pm_forwarding_parameter_node { * super * ^^^^^ * - * Type: PM_FORWARDING_SUPER_NODE + * Type: ::PM_FORWARDING_SUPER_NODE * * @extends pm_node_t */ @@ -3484,6 +3590,7 @@ typedef struct pm_forwarding_super_node { /** The embedded base node. */ pm_node_t base; + /** * ForwardingSuperNode#block */ @@ -3498,7 +3605,7 @@ typedef struct pm_forwarding_super_node { * $target &&= value * ^^^^^^^^^^^^^^^^^ * - * Type: PM_GLOBAL_VARIABLE_AND_WRITE_NODE + * Type: ::PM_GLOBAL_VARIABLE_AND_WRITE_NODE * * @extends pm_node_t */ @@ -3506,6 +3613,7 @@ typedef struct pm_global_variable_and_write_node { /** The embedded base node. */ pm_node_t base; + /** * GlobalVariableAndWriteNode#name */ @@ -3535,7 +3643,7 @@ typedef struct pm_global_variable_and_write_node { * $target += value * ^^^^^^^^^^^^^^^^ * - * Type: PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE + * Type: ::PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE * * @extends pm_node_t */ @@ -3543,6 +3651,7 @@ typedef struct pm_global_variable_operator_write_node { /** The embedded base node. */ pm_node_t base; + /** * GlobalVariableOperatorWriteNode#name */ @@ -3577,7 +3686,7 @@ typedef struct pm_global_variable_operator_write_node { * $target ||= value * ^^^^^^^^^^^^^^^^^ * - * Type: PM_GLOBAL_VARIABLE_OR_WRITE_NODE + * Type: ::PM_GLOBAL_VARIABLE_OR_WRITE_NODE * * @extends pm_node_t */ @@ -3585,6 +3694,7 @@ typedef struct pm_global_variable_or_write_node { /** The embedded base node. */ pm_node_t base; + /** * GlobalVariableOrWriteNode#name */ @@ -3614,7 +3724,7 @@ typedef struct pm_global_variable_or_write_node { * $foo * ^^^^ * - * Type: PM_GLOBAL_VARIABLE_READ_NODE + * Type: ::PM_GLOBAL_VARIABLE_READ_NODE * * @extends pm_node_t */ @@ -3622,6 +3732,7 @@ typedef struct pm_global_variable_read_node { /** The embedded base node. */ pm_node_t base; + /** * GlobalVariableReadNode#name * @@ -3642,7 +3753,7 @@ typedef struct pm_global_variable_read_node { * $foo, $bar = baz * ^^^^ ^^^^ * - * Type: PM_GLOBAL_VARIABLE_TARGET_NODE + * Type: ::PM_GLOBAL_VARIABLE_TARGET_NODE * * @extends pm_node_t */ @@ -3650,6 +3761,7 @@ typedef struct pm_global_variable_target_node { /** The embedded base node. */ pm_node_t base; + /** * GlobalVariableTargetNode#name */ @@ -3664,7 +3776,7 @@ typedef struct pm_global_variable_target_node { * $foo = 1 * ^^^^^^^^ * - * Type: PM_GLOBAL_VARIABLE_WRITE_NODE + * Type: ::PM_GLOBAL_VARIABLE_WRITE_NODE * * @extends pm_node_t */ @@ -3672,6 +3784,7 @@ typedef struct pm_global_variable_write_node { /** The embedded base node. */ pm_node_t base; + /** * GlobalVariableWriteNode#name * @@ -3725,7 +3838,7 @@ typedef struct pm_global_variable_write_node { * { a => b } * ^^^^^^^^^^ * - * Type: PM_HASH_NODE + * Type: ::PM_HASH_NODE * * @extends pm_node_t */ @@ -3733,6 +3846,7 @@ typedef struct pm_hash_node { /** The embedded base node. */ pm_node_t base; + /** * HashNode#opening_loc * @@ -3778,7 +3892,7 @@ typedef struct pm_hash_node { * foo => { a: 1, b: 2, **c } * ^^^^^^^^^^^^^^^^^^^ * - * Type: PM_HASH_PATTERN_NODE + * Type: ::PM_HASH_PATTERN_NODE * * @extends pm_node_t */ @@ -3786,6 +3900,7 @@ typedef struct pm_hash_pattern_node { /** The embedded base node. */ pm_node_t base; + /** * HashPatternNode#constant */ @@ -3826,7 +3941,7 @@ typedef struct pm_hash_pattern_node { * foo ? bar : baz * ^^^^^^^^^^^^^^^ * - * Type: PM_IF_NODE + * Type: ::PM_IF_NODE * * @extends pm_node_t */ @@ -3834,6 +3949,7 @@ typedef struct pm_if_node { /** The embedded base node. */ pm_node_t base; + /** * IfNode#if_keyword_loc * @@ -3931,7 +4047,7 @@ typedef struct pm_if_node { * 1.0i * ^^^^ * - * Type: PM_IMAGINARY_NODE + * Type: ::PM_IMAGINARY_NODE * * @extends pm_node_t */ @@ -3939,6 +4055,7 @@ typedef struct pm_imaginary_node { /** The embedded base node. */ pm_node_t base; + /** * ImaginaryNode#numeric */ @@ -3959,7 +4076,7 @@ typedef struct pm_imaginary_node { * foo in { bar: } * ^^^^ * - * Type: PM_IMPLICIT_NODE + * Type: ::PM_IMPLICIT_NODE * * @extends pm_node_t */ @@ -3967,6 +4084,7 @@ typedef struct pm_implicit_node { /** The embedded base node. */ pm_node_t base; + /** * ImplicitNode#value */ @@ -3990,13 +4108,14 @@ typedef struct pm_implicit_node { * foo, = bar * ^ * - * Type: PM_IMPLICIT_REST_NODE + * Type: ::PM_IMPLICIT_REST_NODE * * @extends pm_node_t */ typedef struct pm_implicit_rest_node { /** The embedded base node. */ pm_node_t base; + } pm_implicit_rest_node_t; /** @@ -4007,7 +4126,7 @@ typedef struct pm_implicit_rest_node { * case a; in b then c end * ^^^^^^^^^^^ * - * Type: PM_IN_NODE + * Type: ::PM_IN_NODE * * @extends pm_node_t */ @@ -4015,6 +4134,7 @@ typedef struct pm_in_node { /** The embedded base node. */ pm_node_t base; + /** * InNode#pattern */ @@ -4044,12 +4164,13 @@ typedef struct pm_in_node { * foo.bar[baz] &&= value * ^^^^^^^^^^^^^^^^^^^^^^ * - * Type: PM_INDEX_AND_WRITE_NODE - * Flags: - * PM_CALL_NODE_FLAGS_SAFE_NAVIGATION - * PM_CALL_NODE_FLAGS_VARIABLE_CALL - * PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE - * PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY + * Type: ::PM_INDEX_AND_WRITE_NODE + + * Flags (#pm_call_node_flags): + * * ::PM_CALL_NODE_FLAGS_SAFE_NAVIGATION + * * ::PM_CALL_NODE_FLAGS_VARIABLE_CALL + * * ::PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE + * * ::PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY * * @extends pm_node_t */ @@ -4057,6 +4178,7 @@ typedef struct pm_index_and_write_node { /** The embedded base node. */ pm_node_t base; + /** * IndexAndWriteNode#receiver */ @@ -4085,7 +4207,7 @@ typedef struct pm_index_and_write_node { /** * IndexAndWriteNode#block */ - struct pm_node *block; + struct pm_block_argument_node *block; /** * IndexAndWriteNode#operator_loc @@ -4106,12 +4228,13 @@ typedef struct pm_index_and_write_node { * foo.bar[baz] += value * ^^^^^^^^^^^^^^^^^^^^^ * - * Type: PM_INDEX_OPERATOR_WRITE_NODE - * Flags: - * PM_CALL_NODE_FLAGS_SAFE_NAVIGATION - * PM_CALL_NODE_FLAGS_VARIABLE_CALL - * PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE - * PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY + * Type: ::PM_INDEX_OPERATOR_WRITE_NODE + + * Flags (#pm_call_node_flags): + * * ::PM_CALL_NODE_FLAGS_SAFE_NAVIGATION + * * ::PM_CALL_NODE_FLAGS_VARIABLE_CALL + * * ::PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE + * * ::PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY * * @extends pm_node_t */ @@ -4119,6 +4242,7 @@ typedef struct pm_index_operator_write_node { /** The embedded base node. */ pm_node_t base; + /** * IndexOperatorWriteNode#receiver */ @@ -4147,7 +4271,7 @@ typedef struct pm_index_operator_write_node { /** * IndexOperatorWriteNode#block */ - struct pm_node *block; + struct pm_block_argument_node *block; /** * IndexOperatorWriteNode#binary_operator @@ -4173,12 +4297,13 @@ typedef struct pm_index_operator_write_node { * foo.bar[baz] ||= value * ^^^^^^^^^^^^^^^^^^^^^^ * - * Type: PM_INDEX_OR_WRITE_NODE - * Flags: - * PM_CALL_NODE_FLAGS_SAFE_NAVIGATION - * PM_CALL_NODE_FLAGS_VARIABLE_CALL - * PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE - * PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY + * Type: ::PM_INDEX_OR_WRITE_NODE + + * Flags (#pm_call_node_flags): + * * ::PM_CALL_NODE_FLAGS_SAFE_NAVIGATION + * * ::PM_CALL_NODE_FLAGS_VARIABLE_CALL + * * ::PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE + * * ::PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY * * @extends pm_node_t */ @@ -4186,6 +4311,7 @@ typedef struct pm_index_or_write_node { /** The embedded base node. */ pm_node_t base; + /** * IndexOrWriteNode#receiver */ @@ -4214,7 +4340,7 @@ typedef struct pm_index_or_write_node { /** * IndexOrWriteNode#block */ - struct pm_node *block; + struct pm_block_argument_node *block; /** * IndexOrWriteNode#operator_loc @@ -4243,12 +4369,13 @@ typedef struct pm_index_or_write_node { * for foo[bar] in baz do end * ^^^^^^^^ * - * Type: PM_INDEX_TARGET_NODE - * Flags: - * PM_CALL_NODE_FLAGS_SAFE_NAVIGATION - * PM_CALL_NODE_FLAGS_VARIABLE_CALL - * PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE - * PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY + * Type: ::PM_INDEX_TARGET_NODE + + * Flags (#pm_call_node_flags): + * * ::PM_CALL_NODE_FLAGS_SAFE_NAVIGATION + * * ::PM_CALL_NODE_FLAGS_VARIABLE_CALL + * * ::PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE + * * ::PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY * * @extends pm_node_t */ @@ -4256,6 +4383,7 @@ typedef struct pm_index_target_node { /** The embedded base node. */ pm_node_t base; + /** * IndexTargetNode#receiver */ @@ -4279,7 +4407,7 @@ typedef struct pm_index_target_node { /** * IndexTargetNode#block */ - struct pm_node *block; + struct pm_block_argument_node *block; } pm_index_target_node_t; /** @@ -4290,7 +4418,7 @@ typedef struct pm_index_target_node { * @target &&= value * ^^^^^^^^^^^^^^^^^ * - * Type: PM_INSTANCE_VARIABLE_AND_WRITE_NODE + * Type: ::PM_INSTANCE_VARIABLE_AND_WRITE_NODE * * @extends pm_node_t */ @@ -4298,6 +4426,7 @@ typedef struct pm_instance_variable_and_write_node { /** The embedded base node. */ pm_node_t base; + /** * InstanceVariableAndWriteNode#name */ @@ -4327,7 +4456,7 @@ typedef struct pm_instance_variable_and_write_node { * @target += value * ^^^^^^^^^^^^^^^^ * - * Type: PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE + * Type: ::PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE * * @extends pm_node_t */ @@ -4335,6 +4464,7 @@ typedef struct pm_instance_variable_operator_write_node { /** The embedded base node. */ pm_node_t base; + /** * InstanceVariableOperatorWriteNode#name */ @@ -4369,7 +4499,7 @@ typedef struct pm_instance_variable_operator_write_node { * @target ||= value * ^^^^^^^^^^^^^^^^^ * - * Type: PM_INSTANCE_VARIABLE_OR_WRITE_NODE + * Type: ::PM_INSTANCE_VARIABLE_OR_WRITE_NODE * * @extends pm_node_t */ @@ -4377,6 +4507,7 @@ typedef struct pm_instance_variable_or_write_node { /** The embedded base node. */ pm_node_t base; + /** * InstanceVariableOrWriteNode#name */ @@ -4406,7 +4537,7 @@ typedef struct pm_instance_variable_or_write_node { * @foo * ^^^^ * - * Type: PM_INSTANCE_VARIABLE_READ_NODE + * Type: ::PM_INSTANCE_VARIABLE_READ_NODE * * @extends pm_node_t */ @@ -4414,6 +4545,7 @@ typedef struct pm_instance_variable_read_node { /** The embedded base node. */ pm_node_t base; + /** * InstanceVariableReadNode#name * @@ -4434,7 +4566,7 @@ typedef struct pm_instance_variable_read_node { * @foo, @bar = baz * ^^^^ ^^^^ * - * Type: PM_INSTANCE_VARIABLE_TARGET_NODE + * Type: ::PM_INSTANCE_VARIABLE_TARGET_NODE * * @extends pm_node_t */ @@ -4442,6 +4574,7 @@ typedef struct pm_instance_variable_target_node { /** The embedded base node. */ pm_node_t base; + /** * InstanceVariableTargetNode#name */ @@ -4456,7 +4589,7 @@ typedef struct pm_instance_variable_target_node { * @foo = 1 * ^^^^^^^^ * - * Type: PM_INSTANCE_VARIABLE_WRITE_NODE + * Type: ::PM_INSTANCE_VARIABLE_WRITE_NODE * * @extends pm_node_t */ @@ -4464,6 +4597,7 @@ typedef struct pm_instance_variable_write_node { /** The embedded base node. */ pm_node_t base; + /** * InstanceVariableWriteNode#name * @@ -4517,12 +4651,13 @@ typedef struct pm_instance_variable_write_node { * 1 * ^ * - * Type: PM_INTEGER_NODE - * Flags: - * PM_INTEGER_BASE_FLAGS_BINARY - * PM_INTEGER_BASE_FLAGS_DECIMAL - * PM_INTEGER_BASE_FLAGS_OCTAL - * PM_INTEGER_BASE_FLAGS_HEXADECIMAL + * Type: ::PM_INTEGER_NODE + + * Flags (#pm_integer_base_flags): + * * ::PM_INTEGER_BASE_FLAGS_BINARY + * * ::PM_INTEGER_BASE_FLAGS_DECIMAL + * * ::PM_INTEGER_BASE_FLAGS_OCTAL + * * ::PM_INTEGER_BASE_FLAGS_HEXADECIMAL * * @extends pm_node_t */ @@ -4530,6 +4665,7 @@ typedef struct pm_integer_node { /** The embedded base node. */ pm_node_t base; + /** * IntegerNode#value * @@ -4546,19 +4682,20 @@ typedef struct pm_integer_node { * if /foo #{bar} baz/ then end * ^^^^^^^^^^^^^^^^ * - * Type: PM_INTERPOLATED_MATCH_LAST_LINE_NODE - * Flags: - * PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE - * PM_REGULAR_EXPRESSION_FLAGS_EXTENDED - * PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE - * PM_REGULAR_EXPRESSION_FLAGS_ONCE - * PM_REGULAR_EXPRESSION_FLAGS_EUC_JP - * PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT - * PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J - * PM_REGULAR_EXPRESSION_FLAGS_UTF_8 - * PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING - * PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING - * PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING + * Type: ::PM_INTERPOLATED_MATCH_LAST_LINE_NODE + + * Flags (#pm_regular_expression_flags): + * * ::PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE + * * ::PM_REGULAR_EXPRESSION_FLAGS_EXTENDED + * * ::PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE + * * ::PM_REGULAR_EXPRESSION_FLAGS_ONCE + * * ::PM_REGULAR_EXPRESSION_FLAGS_EUC_JP + * * ::PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT + * * ::PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J + * * ::PM_REGULAR_EXPRESSION_FLAGS_UTF_8 + * * ::PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING + * * ::PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING + * * ::PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING * * @extends pm_node_t */ @@ -4566,6 +4703,7 @@ typedef struct pm_interpolated_match_last_line_node { /** The embedded base node. */ pm_node_t base; + /** * InterpolatedMatchLastLineNode#opening_loc */ @@ -4590,19 +4728,20 @@ typedef struct pm_interpolated_match_last_line_node { * /foo #{bar} baz/ * ^^^^^^^^^^^^^^^^ * - * Type: PM_INTERPOLATED_REGULAR_EXPRESSION_NODE - * Flags: - * PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE - * PM_REGULAR_EXPRESSION_FLAGS_EXTENDED - * PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE - * PM_REGULAR_EXPRESSION_FLAGS_ONCE - * PM_REGULAR_EXPRESSION_FLAGS_EUC_JP - * PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT - * PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J - * PM_REGULAR_EXPRESSION_FLAGS_UTF_8 - * PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING - * PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING - * PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING + * Type: ::PM_INTERPOLATED_REGULAR_EXPRESSION_NODE + + * Flags (#pm_regular_expression_flags): + * * ::PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE + * * ::PM_REGULAR_EXPRESSION_FLAGS_EXTENDED + * * ::PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE + * * ::PM_REGULAR_EXPRESSION_FLAGS_ONCE + * * ::PM_REGULAR_EXPRESSION_FLAGS_EUC_JP + * * ::PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT + * * ::PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J + * * ::PM_REGULAR_EXPRESSION_FLAGS_UTF_8 + * * ::PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING + * * ::PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING + * * ::PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING * * @extends pm_node_t */ @@ -4610,6 +4749,7 @@ typedef struct pm_interpolated_regular_expression_node { /** The embedded base node. */ pm_node_t base; + /** * InterpolatedRegularExpressionNode#opening_loc */ @@ -4634,10 +4774,11 @@ typedef struct pm_interpolated_regular_expression_node { * "foo #{bar} baz" * ^^^^^^^^^^^^^^^^ * - * Type: PM_INTERPOLATED_STRING_NODE - * Flags: - * PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN - * PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE + * Type: ::PM_INTERPOLATED_STRING_NODE + + * Flags (#pm_interpolated_string_node_flags): + * * ::PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN + * * ::PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE * * @extends pm_node_t */ @@ -4645,6 +4786,7 @@ typedef struct pm_interpolated_string_node { /** The embedded base node. */ pm_node_t base; + /** * InterpolatedStringNode#opening_loc */ @@ -4669,7 +4811,7 @@ typedef struct pm_interpolated_string_node { * :"foo #{bar} baz" * ^^^^^^^^^^^^^^^^^ * - * Type: PM_INTERPOLATED_SYMBOL_NODE + * Type: ::PM_INTERPOLATED_SYMBOL_NODE * * @extends pm_node_t */ @@ -4677,6 +4819,7 @@ typedef struct pm_interpolated_symbol_node { /** The embedded base node. */ pm_node_t base; + /** * InterpolatedSymbolNode#opening_loc */ @@ -4701,7 +4844,7 @@ typedef struct pm_interpolated_symbol_node { * `foo #{bar} baz` * ^^^^^^^^^^^^^^^^ * - * Type: PM_INTERPOLATED_X_STRING_NODE + * Type: ::PM_INTERPOLATED_X_STRING_NODE * * @extends pm_node_t */ @@ -4709,6 +4852,7 @@ typedef struct pm_interpolated_x_string_node { /** The embedded base node. */ pm_node_t base; + /** * InterpolatedXStringNode#opening_loc */ @@ -4733,13 +4877,14 @@ typedef struct pm_interpolated_x_string_node { * -> { it } * ^^ * - * Type: PM_IT_LOCAL_VARIABLE_READ_NODE + * Type: ::PM_IT_LOCAL_VARIABLE_READ_NODE * * @extends pm_node_t */ typedef struct pm_it_local_variable_read_node { /** The embedded base node. */ pm_node_t base; + } pm_it_local_variable_read_node_t; /** @@ -4750,13 +4895,14 @@ typedef struct pm_it_local_variable_read_node { * -> { it + it } * ^^^^^^^^^^^^^^ * - * Type: PM_IT_PARAMETERS_NODE + * Type: ::PM_IT_PARAMETERS_NODE * * @extends pm_node_t */ typedef struct pm_it_parameters_node { /** The embedded base node. */ pm_node_t base; + } pm_it_parameters_node_t; /** @@ -4767,9 +4913,10 @@ typedef struct pm_it_parameters_node { * foo(a: b) * ^^^^ * - * Type: PM_KEYWORD_HASH_NODE - * Flags: - * PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS + * Type: ::PM_KEYWORD_HASH_NODE + + * Flags (#pm_keyword_hash_node_flags): + * * ::PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS * * @extends pm_node_t */ @@ -4777,6 +4924,7 @@ typedef struct pm_keyword_hash_node { /** The embedded base node. */ pm_node_t base; + /** * KeywordHashNode#elements */ @@ -4792,9 +4940,10 @@ typedef struct pm_keyword_hash_node { * ^^^ * end * - * Type: PM_KEYWORD_REST_PARAMETER_NODE - * Flags: - * PM_PARAMETER_FLAGS_REPEATED_PARAMETER + * Type: ::PM_KEYWORD_REST_PARAMETER_NODE + + * Flags (#pm_parameter_flags): + * * ::PM_PARAMETER_FLAGS_REPEATED_PARAMETER * * @extends pm_node_t */ @@ -4802,6 +4951,7 @@ typedef struct pm_keyword_rest_parameter_node { /** The embedded base node. */ pm_node_t base; + /** * KeywordRestParameterNode#name */ @@ -4826,7 +4976,7 @@ typedef struct pm_keyword_rest_parameter_node { * ->(value) { value * 2 } * ^^^^^^^^^^^^^^^^^^^^^^^ * - * Type: PM_LAMBDA_NODE + * Type: ::PM_LAMBDA_NODE * * @extends pm_node_t */ @@ -4834,6 +4984,7 @@ typedef struct pm_lambda_node { /** The embedded base node. */ pm_node_t base; + /** * LambdaNode#locals */ @@ -4873,7 +5024,7 @@ typedef struct pm_lambda_node { * target &&= value * ^^^^^^^^^^^^^^^^ * - * Type: PM_LOCAL_VARIABLE_AND_WRITE_NODE + * Type: ::PM_LOCAL_VARIABLE_AND_WRITE_NODE * * @extends pm_node_t */ @@ -4881,6 +5032,7 @@ typedef struct pm_local_variable_and_write_node { /** The embedded base node. */ pm_node_t base; + /** * LocalVariableAndWriteNode#name_loc */ @@ -4915,7 +5067,7 @@ typedef struct pm_local_variable_and_write_node { * target += value * ^^^^^^^^^^^^^^^ * - * Type: PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE + * Type: ::PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE * * @extends pm_node_t */ @@ -4923,6 +5075,7 @@ typedef struct pm_local_variable_operator_write_node { /** The embedded base node. */ pm_node_t base; + /** * LocalVariableOperatorWriteNode#name_loc */ @@ -4962,7 +5115,7 @@ typedef struct pm_local_variable_operator_write_node { * target ||= value * ^^^^^^^^^^^^^^^^ * - * Type: PM_LOCAL_VARIABLE_OR_WRITE_NODE + * Type: ::PM_LOCAL_VARIABLE_OR_WRITE_NODE * * @extends pm_node_t */ @@ -4970,6 +5123,7 @@ typedef struct pm_local_variable_or_write_node { /** The embedded base node. */ pm_node_t base; + /** * LocalVariableOrWriteNode#name_loc */ @@ -5004,7 +5158,7 @@ typedef struct pm_local_variable_or_write_node { * foo * ^^^ * - * Type: PM_LOCAL_VARIABLE_READ_NODE + * Type: ::PM_LOCAL_VARIABLE_READ_NODE * * @extends pm_node_t */ @@ -5012,6 +5166,7 @@ typedef struct pm_local_variable_read_node { /** The embedded base node. */ pm_node_t base; + /** * LocalVariableReadNode#name * @@ -5049,7 +5204,7 @@ typedef struct pm_local_variable_read_node { * foo, bar = baz * ^^^ ^^^ * - * Type: PM_LOCAL_VARIABLE_TARGET_NODE + * Type: ::PM_LOCAL_VARIABLE_TARGET_NODE * * @extends pm_node_t */ @@ -5057,6 +5212,7 @@ typedef struct pm_local_variable_target_node { /** The embedded base node. */ pm_node_t base; + /** * LocalVariableTargetNode#name */ @@ -5076,7 +5232,7 @@ typedef struct pm_local_variable_target_node { * foo = 1 * ^^^^^^^ * - * Type: PM_LOCAL_VARIABLE_WRITE_NODE + * Type: ::PM_LOCAL_VARIABLE_WRITE_NODE * * @extends pm_node_t */ @@ -5084,6 +5240,7 @@ typedef struct pm_local_variable_write_node { /** The embedded base node. */ pm_node_t base; + /** * LocalVariableWriteNode#name * @@ -5154,19 +5311,20 @@ typedef struct pm_local_variable_write_node { * if /foo/i then end * ^^^^^^ * - * Type: PM_MATCH_LAST_LINE_NODE - * Flags: - * PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE - * PM_REGULAR_EXPRESSION_FLAGS_EXTENDED - * PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE - * PM_REGULAR_EXPRESSION_FLAGS_ONCE - * PM_REGULAR_EXPRESSION_FLAGS_EUC_JP - * PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT - * PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J - * PM_REGULAR_EXPRESSION_FLAGS_UTF_8 - * PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING - * PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING - * PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING + * Type: ::PM_MATCH_LAST_LINE_NODE + + * Flags (#pm_regular_expression_flags): + * * ::PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE + * * ::PM_REGULAR_EXPRESSION_FLAGS_EXTENDED + * * ::PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE + * * ::PM_REGULAR_EXPRESSION_FLAGS_ONCE + * * ::PM_REGULAR_EXPRESSION_FLAGS_EUC_JP + * * ::PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT + * * ::PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J + * * ::PM_REGULAR_EXPRESSION_FLAGS_UTF_8 + * * ::PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING + * * ::PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING + * * ::PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING * * @extends pm_node_t */ @@ -5174,6 +5332,7 @@ typedef struct pm_match_last_line_node { /** The embedded base node. */ pm_node_t base; + /** * MatchLastLineNode#opening_loc */ @@ -5203,7 +5362,7 @@ typedef struct pm_match_last_line_node { * foo in bar * ^^^^^^^^^^ * - * Type: PM_MATCH_PREDICATE_NODE + * Type: ::PM_MATCH_PREDICATE_NODE * * @extends pm_node_t */ @@ -5211,6 +5370,7 @@ typedef struct pm_match_predicate_node { /** The embedded base node. */ pm_node_t base; + /** * MatchPredicateNode#value */ @@ -5235,7 +5395,7 @@ typedef struct pm_match_predicate_node { * foo => bar * ^^^^^^^^^^ * - * Type: PM_MATCH_REQUIRED_NODE + * Type: ::PM_MATCH_REQUIRED_NODE * * @extends pm_node_t */ @@ -5243,6 +5403,7 @@ typedef struct pm_match_required_node { /** The embedded base node. */ pm_node_t base; + /** * MatchRequiredNode#value */ @@ -5267,7 +5428,7 @@ typedef struct pm_match_required_node { * /(?bar)/ =~ baz * ^^^^^^^^^^^^^^^^^^^^ * - * Type: PM_MATCH_WRITE_NODE + * Type: ::PM_MATCH_WRITE_NODE * * @extends pm_node_t */ @@ -5275,6 +5436,7 @@ typedef struct pm_match_write_node { /** The embedded base node. */ pm_node_t base; + /** * MatchWriteNode#call */ @@ -5291,13 +5453,14 @@ typedef struct pm_match_write_node { * * Represents a node that is missing from the source and results in a syntax error. * - * Type: PM_MISSING_NODE + * Type: ::PM_MISSING_NODE * * @extends pm_node_t */ typedef struct pm_missing_node { /** The embedded base node. */ pm_node_t base; + } pm_missing_node_t; /** @@ -5308,7 +5471,7 @@ typedef struct pm_missing_node { * module Foo end * ^^^^^^^^^^^^^^ * - * Type: PM_MODULE_NODE + * Type: ::PM_MODULE_NODE * * @extends pm_node_t */ @@ -5316,6 +5479,7 @@ typedef struct pm_module_node { /** The embedded base node. */ pm_node_t base; + /** * ModuleNode#locals */ @@ -5360,7 +5524,7 @@ typedef struct pm_module_node { * for a, b in [[1, 2], [3, 4]] * ^^^^ * - * Type: PM_MULTI_TARGET_NODE + * Type: ::PM_MULTI_TARGET_NODE * * @extends pm_node_t */ @@ -5368,6 +5532,7 @@ typedef struct pm_multi_target_node { /** The embedded base node. */ pm_node_t base; + /** * MultiTargetNode#lefts * @@ -5396,7 +5561,7 @@ typedef struct pm_multi_target_node { * a, (b, *) = 1, 2, 3, 4 * ^ * - * If the `*` is omitted, the field will containt an `ImplicitRestNode` + * If the `*` is omitted, this field will contain an `ImplicitRestNode` * * a, (b,) = 1, 2, 3, 4 * ^ @@ -5442,7 +5607,7 @@ typedef struct pm_multi_target_node { * a, b, c = 1, 2, 3 * ^^^^^^^^^^^^^^^^^ * - * Type: PM_MULTI_WRITE_NODE + * Type: ::PM_MULTI_WRITE_NODE * * @extends pm_node_t */ @@ -5450,6 +5615,7 @@ typedef struct pm_multi_write_node { /** The embedded base node. */ pm_node_t base; + /** * MultiWriteNode#lefts * @@ -5478,7 +5644,7 @@ typedef struct pm_multi_write_node { * a, b, * = 1, 2, 3, 4 * ^ * - * If the `*` is omitted, the field will containt an `ImplicitRestNode` + * If the `*` is omitted, this field will contain an `ImplicitRestNode` * * a, b, = 1, 2, 3, 4 * ^ @@ -5544,7 +5710,7 @@ typedef struct pm_multi_write_node { * next 1 * ^^^^^^ * - * Type: PM_NEXT_NODE + * Type: ::PM_NEXT_NODE * * @extends pm_node_t */ @@ -5552,6 +5718,7 @@ typedef struct pm_next_node { /** The embedded base node. */ pm_node_t base; + /** * NextNode#arguments */ @@ -5571,13 +5738,14 @@ typedef struct pm_next_node { * nil * ^^^ * - * Type: PM_NIL_NODE + * Type: ::PM_NIL_NODE * * @extends pm_node_t */ typedef struct pm_nil_node { /** The embedded base node. */ pm_node_t base; + } pm_nil_node_t; /** @@ -5589,7 +5757,7 @@ typedef struct pm_nil_node { * ^^^^^ * end * - * Type: PM_NO_KEYWORDS_PARAMETER_NODE + * Type: ::PM_NO_KEYWORDS_PARAMETER_NODE * * @extends pm_node_t */ @@ -5597,6 +5765,7 @@ typedef struct pm_no_keywords_parameter_node { /** The embedded base node. */ pm_node_t base; + /** * NoKeywordsParameterNode#operator_loc */ @@ -5616,7 +5785,7 @@ typedef struct pm_no_keywords_parameter_node { * -> { _1 + _2 } * ^^^^^^^^^^^^^^ * - * Type: PM_NUMBERED_PARAMETERS_NODE + * Type: ::PM_NUMBERED_PARAMETERS_NODE * * @extends pm_node_t */ @@ -5624,6 +5793,7 @@ typedef struct pm_numbered_parameters_node { /** The embedded base node. */ pm_node_t base; + /** * NumberedParametersNode#maximum */ @@ -5638,7 +5808,7 @@ typedef struct pm_numbered_parameters_node { * $1 * ^^ * - * Type: PM_NUMBERED_REFERENCE_READ_NODE + * Type: ::PM_NUMBERED_REFERENCE_READ_NODE * * @extends pm_node_t */ @@ -5646,6 +5816,7 @@ typedef struct pm_numbered_reference_read_node { /** The embedded base node. */ pm_node_t base; + /** * NumberedReferenceReadNode#number * @@ -5669,9 +5840,10 @@ typedef struct pm_numbered_reference_read_node { * ^^^^ * end * - * Type: PM_OPTIONAL_KEYWORD_PARAMETER_NODE - * Flags: - * PM_PARAMETER_FLAGS_REPEATED_PARAMETER + * Type: ::PM_OPTIONAL_KEYWORD_PARAMETER_NODE + + * Flags (#pm_parameter_flags): + * * ::PM_PARAMETER_FLAGS_REPEATED_PARAMETER * * @extends pm_node_t */ @@ -5679,6 +5851,7 @@ typedef struct pm_optional_keyword_parameter_node { /** The embedded base node. */ pm_node_t base; + /** * OptionalKeywordParameterNode#name */ @@ -5704,9 +5877,10 @@ typedef struct pm_optional_keyword_parameter_node { * ^^^^^ * end * - * Type: PM_OPTIONAL_PARAMETER_NODE - * Flags: - * PM_PARAMETER_FLAGS_REPEATED_PARAMETER + * Type: ::PM_OPTIONAL_PARAMETER_NODE + + * Flags (#pm_parameter_flags): + * * ::PM_PARAMETER_FLAGS_REPEATED_PARAMETER * * @extends pm_node_t */ @@ -5714,6 +5888,7 @@ typedef struct pm_optional_parameter_node { /** The embedded base node. */ pm_node_t base; + /** * OptionalParameterNode#name */ @@ -5743,7 +5918,7 @@ typedef struct pm_optional_parameter_node { * left or right * ^^^^^^^^^^^^^ * - * Type: PM_OR_NODE + * Type: ::PM_OR_NODE * * @extends pm_node_t */ @@ -5751,6 +5926,7 @@ typedef struct pm_or_node { /** The embedded base node. */ pm_node_t base; + /** * OrNode#left * @@ -5767,7 +5943,7 @@ typedef struct pm_or_node { /** * OrNode#right * - * Represents the right side of the expression. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). + * Represents the right side of the expression. * * left || right * ^^^^^ @@ -5797,7 +5973,7 @@ typedef struct pm_or_node { * ^^^^^^^ * end * - * Type: PM_PARAMETERS_NODE + * Type: ::PM_PARAMETERS_NODE * * @extends pm_node_t */ @@ -5805,6 +5981,7 @@ typedef struct pm_parameters_node { /** The embedded base node. */ pm_node_t base; + /** * ParametersNode#requireds */ @@ -5849,7 +6026,7 @@ typedef struct pm_parameters_node { * (10 + 34) * ^^^^^^^^^ * - * Type: PM_PARENTHESES_NODE + * Type: ::PM_PARENTHESES_NODE * * @extends pm_node_t */ @@ -5857,6 +6034,7 @@ typedef struct pm_parentheses_node { /** The embedded base node. */ pm_node_t base; + /** * ParenthesesNode#body */ @@ -5881,7 +6059,7 @@ typedef struct pm_parentheses_node { * foo in ^(bar) * ^^^^^^ * - * Type: PM_PINNED_EXPRESSION_NODE + * Type: ::PM_PINNED_EXPRESSION_NODE * * @extends pm_node_t */ @@ -5889,6 +6067,7 @@ typedef struct pm_pinned_expression_node { /** The embedded base node. */ pm_node_t base; + /** * PinnedExpressionNode#expression */ @@ -5918,7 +6097,7 @@ typedef struct pm_pinned_expression_node { * foo in ^bar * ^^^^ * - * Type: PM_PINNED_VARIABLE_NODE + * Type: ::PM_PINNED_VARIABLE_NODE * * @extends pm_node_t */ @@ -5926,6 +6105,7 @@ typedef struct pm_pinned_variable_node { /** The embedded base node. */ pm_node_t base; + /** * PinnedVariableNode#variable */ @@ -5945,7 +6125,7 @@ typedef struct pm_pinned_variable_node { * END { foo } * ^^^^^^^^^^^ * - * Type: PM_POST_EXECUTION_NODE + * Type: ::PM_POST_EXECUTION_NODE * * @extends pm_node_t */ @@ -5953,6 +6133,7 @@ typedef struct pm_post_execution_node { /** The embedded base node. */ pm_node_t base; + /** * PostExecutionNode#statements */ @@ -5982,7 +6163,7 @@ typedef struct pm_post_execution_node { * BEGIN { foo } * ^^^^^^^^^^^^^ * - * Type: PM_PRE_EXECUTION_NODE + * Type: ::PM_PRE_EXECUTION_NODE * * @extends pm_node_t */ @@ -5990,6 +6171,7 @@ typedef struct pm_pre_execution_node { /** The embedded base node. */ pm_node_t base; + /** * PreExecutionNode#statements */ @@ -6016,7 +6198,7 @@ typedef struct pm_pre_execution_node { * * The top level node of any parse tree. * - * Type: PM_PROGRAM_NODE + * Type: ::PM_PROGRAM_NODE * * @extends pm_node_t */ @@ -6024,6 +6206,7 @@ typedef struct pm_program_node { /** The embedded base node. */ pm_node_t base; + /** * ProgramNode#locals */ @@ -6046,9 +6229,10 @@ typedef struct pm_program_node { * c if a =~ /left/ ... b =~ /right/ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * - * Type: PM_RANGE_NODE - * Flags: - * PM_RANGE_FLAGS_EXCLUDE_END + * Type: ::PM_RANGE_NODE + + * Flags (#pm_range_flags): + * * ::PM_RANGE_FLAGS_EXCLUDE_END * * @extends pm_node_t */ @@ -6056,6 +6240,7 @@ typedef struct pm_range_node { /** The embedded base node. */ pm_node_t base; + /** * RangeNode#left * @@ -6099,12 +6284,13 @@ typedef struct pm_range_node { * 1.0r * ^^^^ * - * Type: PM_RATIONAL_NODE - * Flags: - * PM_INTEGER_BASE_FLAGS_BINARY - * PM_INTEGER_BASE_FLAGS_DECIMAL - * PM_INTEGER_BASE_FLAGS_OCTAL - * PM_INTEGER_BASE_FLAGS_HEXADECIMAL + * Type: ::PM_RATIONAL_NODE + + * Flags (#pm_integer_base_flags): + * * ::PM_INTEGER_BASE_FLAGS_BINARY + * * ::PM_INTEGER_BASE_FLAGS_DECIMAL + * * ::PM_INTEGER_BASE_FLAGS_OCTAL + * * ::PM_INTEGER_BASE_FLAGS_HEXADECIMAL * * @extends pm_node_t */ @@ -6112,6 +6298,7 @@ typedef struct pm_rational_node { /** The embedded base node. */ pm_node_t base; + /** * RationalNode#numerator * @@ -6139,13 +6326,14 @@ typedef struct pm_rational_node { * redo * ^^^^ * - * Type: PM_REDO_NODE + * Type: ::PM_REDO_NODE * * @extends pm_node_t */ typedef struct pm_redo_node { /** The embedded base node. */ pm_node_t base; + } pm_redo_node_t; /** @@ -6156,19 +6344,20 @@ typedef struct pm_redo_node { * /foo/i * ^^^^^^ * - * Type: PM_REGULAR_EXPRESSION_NODE - * Flags: - * PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE - * PM_REGULAR_EXPRESSION_FLAGS_EXTENDED - * PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE - * PM_REGULAR_EXPRESSION_FLAGS_ONCE - * PM_REGULAR_EXPRESSION_FLAGS_EUC_JP - * PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT - * PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J - * PM_REGULAR_EXPRESSION_FLAGS_UTF_8 - * PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING - * PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING - * PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING + * Type: ::PM_REGULAR_EXPRESSION_NODE + + * Flags (#pm_regular_expression_flags): + * * ::PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE + * * ::PM_REGULAR_EXPRESSION_FLAGS_EXTENDED + * * ::PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE + * * ::PM_REGULAR_EXPRESSION_FLAGS_ONCE + * * ::PM_REGULAR_EXPRESSION_FLAGS_EUC_JP + * * ::PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT + * * ::PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J + * * ::PM_REGULAR_EXPRESSION_FLAGS_UTF_8 + * * ::PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING + * * ::PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING + * * ::PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING * * @extends pm_node_t */ @@ -6176,6 +6365,7 @@ typedef struct pm_regular_expression_node { /** The embedded base node. */ pm_node_t base; + /** * RegularExpressionNode#opening_loc */ @@ -6206,9 +6396,10 @@ typedef struct pm_regular_expression_node { * ^^ * end * - * Type: PM_REQUIRED_KEYWORD_PARAMETER_NODE - * Flags: - * PM_PARAMETER_FLAGS_REPEATED_PARAMETER + * Type: ::PM_REQUIRED_KEYWORD_PARAMETER_NODE + + * Flags (#pm_parameter_flags): + * * ::PM_PARAMETER_FLAGS_REPEATED_PARAMETER * * @extends pm_node_t */ @@ -6216,6 +6407,7 @@ typedef struct pm_required_keyword_parameter_node { /** The embedded base node. */ pm_node_t base; + /** * RequiredKeywordParameterNode#name */ @@ -6236,9 +6428,10 @@ typedef struct pm_required_keyword_parameter_node { * ^ * end * - * Type: PM_REQUIRED_PARAMETER_NODE - * Flags: - * PM_PARAMETER_FLAGS_REPEATED_PARAMETER + * Type: ::PM_REQUIRED_PARAMETER_NODE + + * Flags (#pm_parameter_flags): + * * ::PM_PARAMETER_FLAGS_REPEATED_PARAMETER * * @extends pm_node_t */ @@ -6246,6 +6439,7 @@ typedef struct pm_required_parameter_node { /** The embedded base node. */ pm_node_t base; + /** * RequiredParameterNode#name */ @@ -6260,7 +6454,7 @@ typedef struct pm_required_parameter_node { * foo rescue nil * ^^^^^^^^^^^^^^ * - * Type: PM_RESCUE_MODIFIER_NODE + * Type: ::PM_RESCUE_MODIFIER_NODE * * @extends pm_node_t */ @@ -6268,6 +6462,7 @@ typedef struct pm_rescue_modifier_node { /** The embedded base node. */ pm_node_t base; + /** * RescueModifierNode#expression */ @@ -6297,7 +6492,7 @@ typedef struct pm_rescue_modifier_node { * * `Foo, *splat, Bar` are in the `exceptions` field. `ex` is in the `exception` field. * - * Type: PM_RESCUE_NODE + * Type: ::PM_RESCUE_NODE * * @extends pm_node_t */ @@ -6305,6 +6500,7 @@ typedef struct pm_rescue_node { /** The embedded base node. */ pm_node_t base; + /** * RescueNode#keyword_loc */ @@ -6345,9 +6541,10 @@ typedef struct pm_rescue_node { * ^^ * end * - * Type: PM_REST_PARAMETER_NODE - * Flags: - * PM_PARAMETER_FLAGS_REPEATED_PARAMETER + * Type: ::PM_REST_PARAMETER_NODE + + * Flags (#pm_parameter_flags): + * * ::PM_PARAMETER_FLAGS_REPEATED_PARAMETER * * @extends pm_node_t */ @@ -6355,6 +6552,7 @@ typedef struct pm_rest_parameter_node { /** The embedded base node. */ pm_node_t base; + /** * RestParameterNode#name */ @@ -6379,13 +6577,14 @@ typedef struct pm_rest_parameter_node { * retry * ^^^^^ * - * Type: PM_RETRY_NODE + * Type: ::PM_RETRY_NODE * * @extends pm_node_t */ typedef struct pm_retry_node { /** The embedded base node. */ pm_node_t base; + } pm_retry_node_t; /** @@ -6396,7 +6595,7 @@ typedef struct pm_retry_node { * return 1 * ^^^^^^^^ * - * Type: PM_RETURN_NODE + * Type: ::PM_RETURN_NODE * * @extends pm_node_t */ @@ -6404,6 +6603,7 @@ typedef struct pm_return_node { /** The embedded base node. */ pm_node_t base; + /** * ReturnNode#keyword_loc */ @@ -6423,13 +6623,14 @@ typedef struct pm_return_node { * self * ^^^^ * - * Type: PM_SELF_NODE + * Type: ::PM_SELF_NODE * * @extends pm_node_t */ typedef struct pm_self_node { /** The embedded base node. */ pm_node_t base; + } pm_self_node_t; /** @@ -6441,11 +6642,12 @@ typedef struct pm_self_node { * C = { a: 1 } * ^^^^^^^^^^^^ * - * Type: PM_SHAREABLE_CONSTANT_NODE - * Flags: - * PM_SHAREABLE_CONSTANT_NODE_FLAGS_LITERAL - * PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_EVERYTHING - * PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_COPY + * Type: ::PM_SHAREABLE_CONSTANT_NODE + + * Flags (#pm_shareable_constant_node_flags): + * * ::PM_SHAREABLE_CONSTANT_NODE_FLAGS_LITERAL + * * ::PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_EVERYTHING + * * ::PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_COPY * * @extends pm_node_t */ @@ -6453,6 +6655,7 @@ typedef struct pm_shareable_constant_node { /** The embedded base node. */ pm_node_t base; + /** * ShareableConstantNode#write * @@ -6469,7 +6672,7 @@ typedef struct pm_shareable_constant_node { * class << self end * ^^^^^^^^^^^^^^^^^ * - * Type: PM_SINGLETON_CLASS_NODE + * Type: ::PM_SINGLETON_CLASS_NODE * * @extends pm_node_t */ @@ -6477,6 +6680,7 @@ typedef struct pm_singleton_class_node { /** The embedded base node. */ pm_node_t base; + /** * SingletonClassNode#locals */ @@ -6516,13 +6720,14 @@ typedef struct pm_singleton_class_node { * __ENCODING__ * ^^^^^^^^^^^^ * - * Type: PM_SOURCE_ENCODING_NODE + * Type: ::PM_SOURCE_ENCODING_NODE * * @extends pm_node_t */ typedef struct pm_source_encoding_node { /** The embedded base node. */ pm_node_t base; + } pm_source_encoding_node_t; /** @@ -6533,12 +6738,13 @@ typedef struct pm_source_encoding_node { * __FILE__ * ^^^^^^^^ * - * Type: PM_SOURCE_FILE_NODE - * Flags: - * PM_STRING_FLAGS_FORCED_UTF8_ENCODING - * PM_STRING_FLAGS_FORCED_BINARY_ENCODING - * PM_STRING_FLAGS_FROZEN - * PM_STRING_FLAGS_MUTABLE + * Type: ::PM_SOURCE_FILE_NODE + + * Flags (#pm_string_flags): + * * ::PM_STRING_FLAGS_FORCED_UTF8_ENCODING + * * ::PM_STRING_FLAGS_FORCED_BINARY_ENCODING + * * ::PM_STRING_FLAGS_FROZEN + * * ::PM_STRING_FLAGS_MUTABLE * * @extends pm_node_t */ @@ -6546,6 +6752,7 @@ typedef struct pm_source_file_node { /** The embedded base node. */ pm_node_t base; + /** * SourceFileNode#filepath * @@ -6562,13 +6769,14 @@ typedef struct pm_source_file_node { * __LINE__ * ^^^^^^^^ * - * Type: PM_SOURCE_LINE_NODE + * Type: ::PM_SOURCE_LINE_NODE * * @extends pm_node_t */ typedef struct pm_source_line_node { /** The embedded base node. */ pm_node_t base; + } pm_source_line_node_t; /** @@ -6579,7 +6787,7 @@ typedef struct pm_source_line_node { * [*a] * ^^ * - * Type: PM_SPLAT_NODE + * Type: ::PM_SPLAT_NODE * * @extends pm_node_t */ @@ -6587,6 +6795,7 @@ typedef struct pm_splat_node { /** The embedded base node. */ pm_node_t base; + /** * SplatNode#operator_loc */ @@ -6606,7 +6815,7 @@ typedef struct pm_splat_node { * foo; bar; baz * ^^^^^^^^^^^^^ * - * Type: PM_STATEMENTS_NODE + * Type: ::PM_STATEMENTS_NODE * * @extends pm_node_t */ @@ -6614,6 +6823,7 @@ typedef struct pm_statements_node { /** The embedded base node. */ pm_node_t base; + /** * StatementsNode#body */ @@ -6634,12 +6844,13 @@ typedef struct pm_statements_node { * "foo #{bar} baz" * ^^^^ ^^^^ * - * Type: PM_STRING_NODE - * Flags: - * PM_STRING_FLAGS_FORCED_UTF8_ENCODING - * PM_STRING_FLAGS_FORCED_BINARY_ENCODING - * PM_STRING_FLAGS_FROZEN - * PM_STRING_FLAGS_MUTABLE + * Type: ::PM_STRING_NODE + + * Flags (#pm_string_flags): + * * ::PM_STRING_FLAGS_FORCED_UTF8_ENCODING + * * ::PM_STRING_FLAGS_FORCED_BINARY_ENCODING + * * ::PM_STRING_FLAGS_FROZEN + * * ::PM_STRING_FLAGS_MUTABLE * * @extends pm_node_t */ @@ -6647,6 +6858,7 @@ typedef struct pm_string_node { /** The embedded base node. */ pm_node_t base; + /** * StringNode#opening_loc */ @@ -6679,7 +6891,7 @@ typedef struct pm_string_node { * super foo, bar * ^^^^^^^^^^^^^^ * - * Type: PM_SUPER_NODE + * Type: ::PM_SUPER_NODE * * @extends pm_node_t */ @@ -6687,6 +6899,7 @@ typedef struct pm_super_node { /** The embedded base node. */ pm_node_t base; + /** * SuperNode#keyword_loc */ @@ -6724,11 +6937,12 @@ typedef struct pm_super_node { * %i[foo] * ^^^ * - * Type: PM_SYMBOL_NODE - * Flags: - * PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING - * PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING - * PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING + * Type: ::PM_SYMBOL_NODE + + * Flags (#pm_symbol_flags): + * * ::PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING + * * ::PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING + * * ::PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING * * @extends pm_node_t */ @@ -6736,6 +6950,7 @@ typedef struct pm_symbol_node { /** The embedded base node. */ pm_node_t base; + /** * SymbolNode#opening_loc */ @@ -6765,13 +6980,14 @@ typedef struct pm_symbol_node { * true * ^^^^ * - * Type: PM_TRUE_NODE + * Type: ::PM_TRUE_NODE * * @extends pm_node_t */ typedef struct pm_true_node { /** The embedded base node. */ pm_node_t base; + } pm_true_node_t; /** @@ -6782,7 +6998,7 @@ typedef struct pm_true_node { * undef :foo, :bar, :baz * ^^^^^^^^^^^^^^^^^^^^^^ * - * Type: PM_UNDEF_NODE + * Type: ::PM_UNDEF_NODE * * @extends pm_node_t */ @@ -6790,6 +7006,7 @@ typedef struct pm_undef_node { /** The embedded base node. */ pm_node_t base; + /** * UndefNode#names */ @@ -6812,7 +7029,7 @@ typedef struct pm_undef_node { * unless foo then bar end * ^^^^^^^^^^^^^^^^^^^^^^^ * - * Type: PM_UNLESS_NODE + * Type: ::PM_UNLESS_NODE * * @extends pm_node_t */ @@ -6820,6 +7037,7 @@ typedef struct pm_unless_node { /** The embedded base node. */ pm_node_t base; + /** * UnlessNode#keyword_loc * @@ -6899,9 +7117,10 @@ typedef struct pm_unless_node { * until foo do bar end * ^^^^^^^^^^^^^^^^^^^^ * - * Type: PM_UNTIL_NODE - * Flags: - * PM_LOOP_FLAGS_BEGIN_MODIFIER + * Type: ::PM_UNTIL_NODE + + * Flags (#pm_loop_flags): + * * ::PM_LOOP_FLAGS_BEGIN_MODIFIER * * @extends pm_node_t */ @@ -6909,6 +7128,7 @@ typedef struct pm_until_node { /** The embedded base node. */ pm_node_t base; + /** * UntilNode#keyword_loc */ @@ -6940,7 +7160,7 @@ typedef struct pm_until_node { * ^^^^^^^^^ * end * - * Type: PM_WHEN_NODE + * Type: ::PM_WHEN_NODE * * @extends pm_node_t */ @@ -6948,6 +7168,7 @@ typedef struct pm_when_node { /** The embedded base node. */ pm_node_t base; + /** * WhenNode#keyword_loc */ @@ -6980,9 +7201,10 @@ typedef struct pm_when_node { * while foo do bar end * ^^^^^^^^^^^^^^^^^^^^ * - * Type: PM_WHILE_NODE - * Flags: - * PM_LOOP_FLAGS_BEGIN_MODIFIER + * Type: ::PM_WHILE_NODE + + * Flags (#pm_loop_flags): + * * ::PM_LOOP_FLAGS_BEGIN_MODIFIER * * @extends pm_node_t */ @@ -6990,6 +7212,7 @@ typedef struct pm_while_node { /** The embedded base node. */ pm_node_t base; + /** * WhileNode#keyword_loc */ @@ -7019,10 +7242,11 @@ typedef struct pm_while_node { * `foo` * ^^^^^ * - * Type: PM_X_STRING_NODE - * Flags: - * PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING - * PM_ENCODING_FLAGS_FORCED_BINARY_ENCODING + * Type: ::PM_X_STRING_NODE + + * Flags (#pm_encoding_flags): + * * ::PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING + * * ::PM_ENCODING_FLAGS_FORCED_BINARY_ENCODING * * @extends pm_node_t */ @@ -7030,6 +7254,7 @@ typedef struct pm_x_string_node { /** The embedded base node. */ pm_node_t base; + /** * XStringNode#opening_loc */ @@ -7059,7 +7284,7 @@ typedef struct pm_x_string_node { * yield 1 * ^^^^^^^ * - * Type: PM_YIELD_NODE + * Type: ::PM_YIELD_NODE * * @extends pm_node_t */ @@ -7067,6 +7292,7 @@ typedef struct pm_yield_node { /** The embedded base node. */ pm_node_t base; + /** * YieldNode#keyword_loc */ @@ -7092,14 +7318,20 @@ typedef struct pm_yield_node { * Flags for arguments nodes. */ typedef enum pm_arguments_node_flags { - /** if arguments contain keywords */ - PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS = 4, + /** if the arguments contain forwarding */ + PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING = 4, + + /** if the arguments contain keywords */ + PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS = 8, + + /** if the arguments contain a keyword splat */ + PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT = 16, - /** if arguments contain keyword splat */ - PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT = 8, + /** if the arguments contain a splat */ + PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT = 32, - /** if arguments contain splat */ - PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT = 16, + /** if the arguments contain multiple splats */ + PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS = 64, } pm_arguments_node_flags_t; /** diff --git a/src/main/c/yarp/include/prism/defines.h b/src/main/c/yarp/include/prism/defines.h index a4246e67c8a..e78c7dd75ce 100644 --- a/src/main/c/yarp/include/prism/defines.h +++ b/src/main/c/yarp/include/prism/defines.h @@ -25,6 +25,15 @@ #define __STDC_FORMAT_MACROS #include +/** + * When we are parsing using recursive descent, we want to protect against + * malicious payloads that could attempt to crash our parser. We do this by + * specifying a maximum depth to which we are allowed to recurse. + */ +#ifndef PRISM_DEPTH_MAXIMUM + #define PRISM_DEPTH_MAXIMUM 1000 +#endif + /** * By default, we compile with -fvisibility=hidden. When this is enabled, we * need to mark certain functions as being publically-visible. This macro does @@ -212,4 +221,22 @@ #define PRISM_ENCODING_EXCLUDE_FULL #endif +/** + * Support PRISM_LIKELY and PRISM_UNLIKELY to help the compiler optimize its + * branch predication. + */ +#if defined(__GNUC__) || defined(__clang__) + /** The compiler should predicate that this branch will be taken. */ + #define PRISM_LIKELY(x) __builtin_expect(!!(x), 1) + + /** The compiler should predicate that this branch will not be taken. */ + #define PRISM_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else + /** Void because this platform does not support branch prediction hints. */ + #define PRISM_LIKELY(x) (x) + + /** Void because this platform does not support branch prediction hints. */ + #define PRISM_UNLIKELY(x) (x) +#endif + #endif diff --git a/src/main/c/yarp/include/prism/diagnostic.h b/src/main/c/yarp/include/prism/diagnostic.h index 50c81c36f9d..5e11412c2a8 100644 --- a/src/main/c/yarp/include/prism/diagnostic.h +++ b/src/main/c/yarp/include/prism/diagnostic.h @@ -44,7 +44,6 @@ typedef enum { PM_ERR_ARGUMENT_FORMAL_GLOBAL, PM_ERR_ARGUMENT_FORMAL_IVAR, PM_ERR_ARGUMENT_FORWARDING_UNBOUND, - PM_ERR_ARGUMENT_IN, PM_ERR_ARGUMENT_NO_FORWARDING_AMPERSAND, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES, PM_ERR_ARGUMENT_NO_FORWARDING_STAR, @@ -128,6 +127,7 @@ typedef enum { PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, + PM_ERR_EXPECT_FOR_DELIMITER, PM_ERR_EXPECT_IDENT_REQ_PARAMETER, PM_ERR_EXPECT_IN_DELIMITER, PM_ERR_EXPECT_LPAREN_REQ_PARAMETER, @@ -136,6 +136,7 @@ typedef enum { PM_ERR_EXPECT_RPAREN, PM_ERR_EXPECT_RPAREN_AFTER_MULTI, PM_ERR_EXPECT_RPAREN_REQ_PARAMETER, + PM_ERR_EXPECT_SINGLETON_CLASS_DELIMITER, PM_ERR_EXPECT_STRING_CONTENT, PM_ERR_EXPECT_WHEN_DELIMITER, PM_ERR_EXPRESSION_BARE_HASH, @@ -214,7 +215,9 @@ typedef enum { PM_ERR_MODULE_TERM, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST, + PM_ERR_NESTING_TOO_DEEP, PM_ERR_NO_LOCAL_VARIABLE, + PM_ERR_NON_ASSOCIATIVE_OPERATOR, PM_ERR_NOT_EXPRESSION, PM_ERR_NUMBER_LITERAL_UNDERSCORE, PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK, @@ -300,6 +303,7 @@ typedef enum { PM_ERR_UNEXPECTED_BLOCK_ARGUMENT, PM_ERR_UNEXPECTED_INDEX_BLOCK, PM_ERR_UNEXPECTED_INDEX_KEYWORDS, + PM_ERR_UNEXPECTED_LABEL, PM_ERR_UNEXPECTED_MULTI_WRITE, PM_ERR_UNEXPECTED_RANGE_OPERATOR, PM_ERR_UNEXPECTED_SAFE_NAVIGATION, diff --git a/src/main/c/yarp/include/prism/options.h b/src/main/c/yarp/include/prism/options.h index 52b5380965a..c96fa684ac6 100644 --- a/src/main/c/yarp/include/prism/options.h +++ b/src/main/c/yarp/include/prism/options.h @@ -7,6 +7,7 @@ #define PRISM_OPTIONS_H #include "prism/defines.h" +#include "prism/util/pm_char.h" #include "prism/util/pm_string.h" #include @@ -139,6 +140,23 @@ typedef struct pm_options { * but ignore any encoding magic comments at the top of the file. */ bool encoding_locked; + + /** + * When the file being parsed is the main script, the shebang will be + * considered for command-line flags (or for implicit -x). The caller needs + * to pass this information to the parser so that it can behave correctly. + */ + bool main_script; + + /** + * When the file being parsed is considered a "partial" script, jumps will + * not be marked as errors if they are not contained within loops/blocks. + * This is used in the case that you're parsing a script that you know will + * be embedded inside another script later, but you do not have that context + * yet. For example, when parsing an ERB template that will be evaluated + * inside another script. + */ + bool partial_script; } pm_options_t; /** @@ -248,6 +266,22 @@ PRISM_EXPORTED_FUNCTION void pm_options_command_line_set(pm_options_t *options, */ PRISM_EXPORTED_FUNCTION bool pm_options_version_set(pm_options_t *options, const char *version, size_t length); +/** + * Set the main script option on the given options struct. + * + * @param options The options struct to set the main script value on. + * @param main_script The main script value to set. + */ +PRISM_EXPORTED_FUNCTION void pm_options_main_script_set(pm_options_t *options, bool main_script); + +/** + * Set the partial script option on the given options struct. + * + * @param options The options struct to set the partial script value on. + * @param partial_script The partial script value to set. + */ +PRISM_EXPORTED_FUNCTION void pm_options_partial_script_set(pm_options_t *options, bool partial_script); + /** * Allocate and zero out the scopes array on the given options struct. * @@ -315,6 +349,9 @@ PRISM_EXPORTED_FUNCTION void pm_options_free(pm_options_t *options); * | `1` | -l command line option | * | `1` | -a command line option | * | `1` | the version | + * | `1` | encoding locked | + * | `1` | main script | + * | `1` | partial script | * | `4` | the number of scopes | * | ... | the scopes | * @@ -347,8 +384,8 @@ PRISM_EXPORTED_FUNCTION void pm_options_free(pm_options_t *options); * * The encoding can have a length of 0, in which case we'll use the default * encoding (UTF-8). If it's not 0, it should correspond to a name of an * encoding that can be passed to `Encoding.find` in Ruby. - * * The frozen string literal and suppress warnings fields are booleans, so - * their values should be either 0 or 1. + * * The frozen string literal, encoding locked, main script, and partial script + * fields are booleans, so their values should be either 0 or 1. * * The number of scopes can be 0. * * @param options The options struct to deserialize into. diff --git a/src/main/c/yarp/include/prism/parser.h b/src/main/c/yarp/include/prism/parser.h index ea40fc910a2..bdff8ad2996 100644 --- a/src/main/c/yarp/include/prism/parser.h +++ b/src/main/c/yarp/include/prism/parser.h @@ -861,6 +861,13 @@ struct pm_parser { */ bool parsing_eval; + /** + * Whether or not we are parsing a "partial" script, which is a script that + * will be evaluated in the context of another script, so we should not + * check jumps (next/break/etc.) for validity. + */ + bool partial_script; + /** Whether or not we're at the beginning of a command. */ bool command_start; diff --git a/src/main/c/yarp/include/prism/util/pm_string.h b/src/main/c/yarp/include/prism/util/pm_string.h index e4a20558d36..f99f1abdf38 100644 --- a/src/main/c/yarp/include/prism/util/pm_string.h +++ b/src/main/c/yarp/include/prism/util/pm_string.h @@ -22,6 +22,9 @@ #include #include #include +#elif defined(PRISM_HAS_FILESYSTEM) +#include +#include #endif /** @@ -93,6 +96,26 @@ void pm_string_owned_init(pm_string_t *string, uint8_t *source, size_t length); */ void pm_string_constant_init(pm_string_t *string, const char *source, size_t length); +/** + * Represents the result of calling pm_string_mapped_init or + * pm_string_file_init. We need this additional information because there is + * not a platform-agnostic way to indicate that the file that was attempted to + * be opened was a directory. + */ +typedef enum { + /** Indicates that the string was successfully initialized. */ + PM_STRING_INIT_SUCCESS = 0, + /** + * Indicates a generic error from a string_*_init function, where the type + * of error should be read from `errno` or `GetLastError()`. + */ + PM_STRING_INIT_ERROR_GENERIC = 1, + /** + * Indicates that the file that was attempted to be opened was a directory. + */ + PM_STRING_INIT_ERROR_DIRECTORY = 2 +} pm_string_init_result_t; + /** * Read the file indicated by the filepath parameter into source and load its * contents and size into the given `pm_string_t`. The given `pm_string_t` @@ -106,9 +129,9 @@ void pm_string_constant_init(pm_string_t *string, const char *source, size_t len * * @param string The string to initialize. * @param filepath The filepath to read. - * @return Whether or not the file was successfully mapped. + * @return The success of the read, indicated by the value of the enum. */ -PRISM_EXPORTED_FUNCTION bool pm_string_mapped_init(pm_string_t *string, const char *filepath); +PRISM_EXPORTED_FUNCTION pm_string_init_result_t pm_string_mapped_init(pm_string_t *string, const char *filepath); /** * Read the file indicated by the filepath parameter into source and load its @@ -117,9 +140,9 @@ PRISM_EXPORTED_FUNCTION bool pm_string_mapped_init(pm_string_t *string, const ch * * @param string The string to initialize. * @param filepath The filepath to read. - * @return Whether or not the file was successfully read. + * @return The success of the read, indicated by the value of the enum. */ -PRISM_EXPORTED_FUNCTION bool pm_string_file_init(pm_string_t *string, const char *filepath); +PRISM_EXPORTED_FUNCTION pm_string_init_result_t pm_string_file_init(pm_string_t *string, const char *filepath); /** * Ensure the string is owned. If it is not, then reinitialize it as owned and diff --git a/src/main/c/yarp/include/prism/version.h b/src/main/c/yarp/include/prism/version.h index 3cca6489966..a75cb4646d6 100644 --- a/src/main/c/yarp/include/prism/version.h +++ b/src/main/c/yarp/include/prism/version.h @@ -14,7 +14,7 @@ /** * The minor version of the Prism library as an int. */ -#define PRISM_VERSION_MINOR 0 +#define PRISM_VERSION_MINOR 1 /** * The patch version of the Prism library as an int. @@ -24,6 +24,6 @@ /** * The version of the Prism library as a constant string. */ -#define PRISM_VERSION "1.0.0" +#define PRISM_VERSION "1.1.0" #endif diff --git a/src/main/c/yarp/src/diagnostic.c b/src/main/c/yarp/src/diagnostic.c index 1461a663f99..4fdb1f4060c 100644 --- a/src/main/c/yarp/src/diagnostic.c +++ b/src/main/c/yarp/src/diagnostic.c @@ -8,7 +8,7 @@ #include "prism/diagnostic.h" -#define PM_DIAGNOSTIC_ID_MAX 314 +#define PM_DIAGNOSTIC_ID_MAX 318 /** This struct holds the data for each diagnostic. */ typedef struct { @@ -108,7 +108,6 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = { [PM_ERR_ARGUMENT_FORMAL_GLOBAL] = { "invalid formal argument; formal argument cannot be a global variable", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_ARGUMENT_FORMAL_IVAR] = { "invalid formal argument; formal argument cannot be an instance variable", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_ARGUMENT_FORWARDING_UNBOUND] = { "unexpected `...` in an non-parenthesized call", PM_ERROR_LEVEL_SYNTAX }, - [PM_ERR_ARGUMENT_IN] = { "unexpected `in` keyword in arguments", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_ARGUMENT_NO_FORWARDING_AMPERSAND] = { "unexpected `&`; no anonymous block parameter", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES] = { "unexpected ... when the parent method is not forwarding", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_ARGUMENT_NO_FORWARDING_STAR] = { "unexpected `*`; no anonymous rest parameter", PM_ERROR_LEVEL_SYNTAX }, @@ -121,7 +120,7 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = { [PM_ERR_ARRAY_EXPRESSION] = { "expected an expression for the array element", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_ARRAY_EXPRESSION_AFTER_STAR] = { "expected an expression after `*` in the array", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_ARRAY_SEPARATOR] = { "unexpected %s; expected a `,` separator for the array elements", PM_ERROR_LEVEL_SYNTAX }, - [PM_ERR_ARRAY_TERM] = { "expected a `]` to close the array", PM_ERROR_LEVEL_SYNTAX }, + [PM_ERR_ARRAY_TERM] = { "unexpected %s; expected a `]` to close the array", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_BEGIN_LONELY_ELSE] = { "unexpected `else` in `begin` block; else without rescue is useless", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_BEGIN_TERM] = { "expected an `end` to close the `begin` statement", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_BEGIN_UPCASE_BRACE] = { "expected a `{` after `BEGIN`", PM_ERROR_LEVEL_SYNTAX }, @@ -178,7 +177,7 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = { [PM_ERR_ESCAPE_INVALID_UNICODE_LONG] = { "invalid Unicode escape sequence; maximum length is 6 digits", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_ESCAPE_INVALID_UNICODE_SHORT] = { "too short escape sequence: %.*s", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_ESCAPE_INVALID_UNICODE_TERM] = { "unterminated Unicode escape", PM_ERROR_LEVEL_SYNTAX }, - [PM_ERR_EXPECT_ARGUMENT] = { "expected an argument", PM_ERROR_LEVEL_SYNTAX }, + [PM_ERR_EXPECT_ARGUMENT] = { "unexpected %s; expected an argument", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_EXPECT_EOL_AFTER_STATEMENT] = { "unexpected %s, expecting end-of-input", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ] = { "expected an expression after `&&=`", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ] = { "expected an expression after `||=`", PM_ERROR_LEVEL_SYNTAX }, @@ -190,6 +189,7 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = { [PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT] = { "expected an expression after `*` splat in an argument", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH] = { "expected an expression after `**` in a hash", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_EXPECT_EXPRESSION_AFTER_STAR] = { "expected an expression after `*`", PM_ERROR_LEVEL_SYNTAX }, + [PM_ERR_EXPECT_FOR_DELIMITER] = { "unexpected %s; expected a 'do', newline, or ';' after the 'for' loop collection", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_EXPECT_IDENT_REQ_PARAMETER] = { "expected an identifier for the required parameter", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_EXPECT_IN_DELIMITER] = { "expected a delimiter after the patterns of an `in` clause", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_EXPECT_LPAREN_REQ_PARAMETER] = { "expected a `(` to start a required parameter", PM_ERROR_LEVEL_SYNTAX }, @@ -198,6 +198,7 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = { [PM_ERR_EXPECT_RPAREN] = { "expected a matching `)`", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_EXPECT_RPAREN_AFTER_MULTI] = { "expected a `)` after multiple assignment", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_EXPECT_RPAREN_REQ_PARAMETER] = { "expected a `)` to end a required parameter", PM_ERROR_LEVEL_SYNTAX }, + [PM_ERR_EXPECT_SINGLETON_CLASS_DELIMITER] = { "unexpected %s; expected a newline or a ';' after the singleton class", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_EXPECT_STRING_CONTENT] = { "expected string content after opening string delimiter", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_EXPECT_WHEN_DELIMITER] = { "expected a delimiter after the predicates of a `when` clause", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_EXPRESSION_BARE_HASH] = { "unexpected bare hash in expression", PM_ERROR_LEVEL_SYNTAX }, @@ -275,8 +276,10 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = { [PM_ERR_MODULE_TERM] = { "expected an `end` to close the `module` statement", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_MULTI_ASSIGN_MULTI_SPLATS] = { "multiple splats in multiple assignment", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST] = { "unexpected '%.*s' resulting in multiple splats in multiple assignment", PM_ERROR_LEVEL_SYNTAX }, - [PM_ERR_NOT_EXPRESSION] = { "expected an expression after `not`", PM_ERROR_LEVEL_SYNTAX }, + [PM_ERR_NESTING_TOO_DEEP] = { "nesting too deep", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_NO_LOCAL_VARIABLE] = { "%.*s: no such local variable", PM_ERROR_LEVEL_SYNTAX }, + [PM_ERR_NON_ASSOCIATIVE_OPERATOR] = { "unexpected %s; %s is a non-associative operator", PM_ERROR_LEVEL_SYNTAX }, + [PM_ERR_NOT_EXPRESSION] = { "expected an expression after `not`", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_NUMBER_LITERAL_UNDERSCORE] = { "number literal ending with a `_`", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK] = { "numbered parameter is already used in inner block", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_NUMBERED_PARAMETER_IT] = { "numbered parameters are not allowed when 'it' is already used", PM_ERROR_LEVEL_SYNTAX }, @@ -354,12 +357,13 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = { [PM_ERR_TERNARY_COLON] = { "expected a `:` after the true expression of a ternary operator", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_TERNARY_EXPRESSION_FALSE] = { "expected an expression after `:` in the ternary operator", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_TERNARY_EXPRESSION_TRUE] = { "expected an expression after `?` in the ternary operator", PM_ERROR_LEVEL_SYNTAX }, - [PM_ERR_UNDEF_ARGUMENT] = { "invalid argument being passed to `undef`; expected a bare word, constant, or symbol argument", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_UNARY_RECEIVER] = { "unexpected %s, expected a receiver for unary `%c`", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_UNARY_DISALLOWED] = { "unexpected %s; unary calls are not allowed in this context", PM_ERROR_LEVEL_SYNTAX }, + [PM_ERR_UNDEF_ARGUMENT] = { "invalid argument being passed to `undef`; expected a bare word, constant, or symbol argument", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_UNEXPECTED_BLOCK_ARGUMENT] = { "block argument should not be given", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_UNEXPECTED_INDEX_BLOCK] = { "unexpected block arg given in index assignment; blocks are not allowed in index assignment expressions", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_UNEXPECTED_INDEX_KEYWORDS] = { "unexpected keyword arg given in index assignment; keywords are not allowed in index assignment expressions", PM_ERROR_LEVEL_SYNTAX }, + [PM_ERR_UNEXPECTED_LABEL] = { "unexpected label", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_UNEXPECTED_MULTI_WRITE] = { "unexpected multiple assignment; multiple assignment is not allowed in this context", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_UNEXPECTED_RANGE_OPERATOR] = { "unexpected range operator; .. and ... are non-associative and cannot be chained", PM_ERROR_LEVEL_SYNTAX }, [PM_ERR_UNEXPECTED_SAFE_NAVIGATION] = { "&. inside multiple assignment destination", PM_ERROR_LEVEL_SYNTAX }, @@ -428,7 +432,6 @@ pm_diagnostic_id_human(pm_diagnostic_id_t diag_id) { case PM_ERR_ARGUMENT_FORMAL_GLOBAL: return "argument_formal_global"; case PM_ERR_ARGUMENT_FORMAL_IVAR: return "argument_formal_ivar"; case PM_ERR_ARGUMENT_FORWARDING_UNBOUND: return "argument_forwarding_unbound"; - case PM_ERR_ARGUMENT_IN: return "argument_in"; case PM_ERR_ARGUMENT_NO_FORWARDING_AMPERSAND: return "argument_no_forwarding_ampersand"; case PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES: return "argument_no_forwarding_ellipses"; case PM_ERR_ARGUMENT_NO_FORWARDING_STAR: return "argument_no_forwarding_star"; @@ -512,6 +515,7 @@ pm_diagnostic_id_human(pm_diagnostic_id_t diag_id) { case PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT: return "expect_expression_after_splat"; case PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH: return "expect_expression_after_splat_hash"; case PM_ERR_EXPECT_EXPRESSION_AFTER_STAR: return "expect_expression_after_star"; + case PM_ERR_EXPECT_FOR_DELIMITER: return "expect_for_delimiter"; case PM_ERR_EXPECT_IDENT_REQ_PARAMETER: return "expect_ident_req_parameter"; case PM_ERR_EXPECT_IN_DELIMITER: return "expect_in_delimiter"; case PM_ERR_EXPECT_LPAREN_REQ_PARAMETER: return "expect_lparen_req_parameter"; @@ -520,6 +524,7 @@ pm_diagnostic_id_human(pm_diagnostic_id_t diag_id) { case PM_ERR_EXPECT_RPAREN: return "expect_rparen"; case PM_ERR_EXPECT_RPAREN_AFTER_MULTI: return "expect_rparen_after_multi"; case PM_ERR_EXPECT_RPAREN_REQ_PARAMETER: return "expect_rparen_req_parameter"; + case PM_ERR_EXPECT_SINGLETON_CLASS_DELIMITER: return "expect_singleton_class_delimiter"; case PM_ERR_EXPECT_STRING_CONTENT: return "expect_string_content"; case PM_ERR_EXPECT_WHEN_DELIMITER: return "expect_when_delimiter"; case PM_ERR_EXPRESSION_BARE_HASH: return "expression_bare_hash"; @@ -598,7 +603,9 @@ pm_diagnostic_id_human(pm_diagnostic_id_t diag_id) { case PM_ERR_MODULE_TERM: return "module_term"; case PM_ERR_MULTI_ASSIGN_MULTI_SPLATS: return "multi_assign_multi_splats"; case PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST: return "multi_assign_unexpected_rest"; + case PM_ERR_NESTING_TOO_DEEP: return "nesting_too_deep"; case PM_ERR_NO_LOCAL_VARIABLE: return "no_local_variable"; + case PM_ERR_NON_ASSOCIATIVE_OPERATOR: return "non_associative_operator"; case PM_ERR_NOT_EXPRESSION: return "not_expression"; case PM_ERR_NUMBER_LITERAL_UNDERSCORE: return "number_literal_underscore"; case PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK: return "numbered_parameter_inner_block"; @@ -684,6 +691,7 @@ pm_diagnostic_id_human(pm_diagnostic_id_t diag_id) { case PM_ERR_UNEXPECTED_BLOCK_ARGUMENT: return "unexpected_block_argument"; case PM_ERR_UNEXPECTED_INDEX_BLOCK: return "unexpected_index_block"; case PM_ERR_UNEXPECTED_INDEX_KEYWORDS: return "unexpected_index_keywords"; + case PM_ERR_UNEXPECTED_LABEL: return "unexpected_label"; case PM_ERR_UNEXPECTED_MULTI_WRITE: return "unexpected_multi_write"; case PM_ERR_UNEXPECTED_RANGE_OPERATOR: return "unexpected_range_operator"; case PM_ERR_UNEXPECTED_SAFE_NAVIGATION: return "unexpected_safe_navigation"; diff --git a/src/main/c/yarp/src/node.c b/src/main/c/yarp/src/node.c index 2d6afa97cb3..2eecc0e0dbd 100644 --- a/src/main/c/yarp/src/node.c +++ b/src/main/c/yarp/src/node.c @@ -3125,6 +3125,11 @@ pm_dump_json(pm_buffer_t *buffer, const pm_parser_t *parser, const pm_node_t *no pm_buffer_append_string(buffer, "\"ArgumentsNodeFlags\":", 21); size_t flags = 0; pm_buffer_append_byte(buffer, '['); + if (PM_NODE_FLAG_P(cast, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"CONTAINS_FORWARDING\"", 21); + flags++; + } if (PM_NODE_FLAG_P(cast, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) { if (flags != 0) pm_buffer_append_byte(buffer, ','); pm_buffer_append_string(buffer, "\"CONTAINS_KEYWORDS\"", 19); @@ -3140,6 +3145,11 @@ pm_dump_json(pm_buffer_t *buffer, const pm_parser_t *parser, const pm_node_t *no pm_buffer_append_string(buffer, "\"CONTAINS_SPLAT\"", 16); flags++; } + if (PM_NODE_FLAG_P(cast, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS)) { + if (flags != 0) pm_buffer_append_byte(buffer, ','); + pm_buffer_append_string(buffer, "\"CONTAINS_MULTIPLE_SPLATS\"", 26); + flags++; + } pm_buffer_append_byte(buffer, ']'); // Dump the arguments field diff --git a/src/main/c/yarp/src/options.c b/src/main/c/yarp/src/options.c index 643de9d95a3..6b52b2f2960 100644 --- a/src/main/c/yarp/src/options.c +++ b/src/main/c/yarp/src/options.c @@ -57,6 +57,14 @@ pm_options_command_line_set(pm_options_t *options, uint8_t command_line) { options->command_line = command_line; } +/** + * Checks if the given slice represents a number. + */ +static inline bool +is_number(const char *string, size_t length) { + return pm_strspn_decimal_digit((const uint8_t *) string, (ptrdiff_t) length) == length; +} + /** * Set the version option on the given options struct by parsing the given * string. If the string contains an invalid option, this returns false. @@ -64,40 +72,61 @@ pm_options_command_line_set(pm_options_t *options, uint8_t command_line) { */ PRISM_EXPORTED_FUNCTION bool pm_options_version_set(pm_options_t *options, const char *version, size_t length) { - switch (length) { - case 0: - if (version == NULL) { - options->version = PM_OPTIONS_VERSION_LATEST; - return true; - } + if (version == NULL) { + options->version = PM_OPTIONS_VERSION_LATEST; + return true; + } - return false; - case 5: - assert(version != NULL); + if (length == 3) { + if (strncmp(version, "3.3", 3) == 0) { + options->version = PM_OPTIONS_VERSION_CRUBY_3_3; + return true; + } - if ((strncmp(version, "3.3.0", length) == 0) || (strncmp(version, "3.3.1", length) == 0)) { - options->version = PM_OPTIONS_VERSION_CRUBY_3_3; - return true; - } + if (strncmp(version, "3.4", 3) == 0) { + options->version = PM_OPTIONS_VERSION_LATEST; + return true; + } - if (strncmp(version, "3.4.0", length) == 0) { - options->version = PM_OPTIONS_VERSION_LATEST; - return true; - } + return false; + } - return false; - case 6: - assert(version != NULL); + if (length >= 4) { + if (strncmp(version, "3.3.", 4) == 0 && is_number(version + 4, length - 4)) { + options->version = PM_OPTIONS_VERSION_CRUBY_3_3; + return true; + } - if (strncmp(version, "latest", length) == 0) { - options->version = PM_OPTIONS_VERSION_LATEST; - return true; - } + if (strncmp(version, "3.4.", 4) == 0 && is_number(version + 4, length - 4)) { + options->version = PM_OPTIONS_VERSION_LATEST; + return true; + } + } - return false; - default: - return false; + if (length >= 6) { + if (strncmp(version, "latest", 7) == 0) { // 7 to compare the \0 as well + options->version = PM_OPTIONS_VERSION_LATEST; + return true; + } } + + return false; +} + +/** + * Set the main script option on the given options struct. + */ +PRISM_EXPORTED_FUNCTION void +pm_options_main_script_set(pm_options_t *options, bool main_script) { + options->main_script = main_script; +} + +/** + * Set the partial script option on the given options struct. + */ +PRISM_EXPORTED_FUNCTION void +pm_options_partial_script_set(pm_options_t *options, bool partial_script) { + options->partial_script = partial_script; } // For some reason, GCC analyzer thinks we're leaking allocated scopes and @@ -233,6 +262,8 @@ pm_options_read(pm_options_t *options, const char *data) { options->command_line = (uint8_t) *data++; options->version = (pm_options_version_t) *data++; options->encoding_locked = ((uint8_t) *data++) > 0; + options->main_script = ((uint8_t) *data++) > 0; + options->partial_script = ((uint8_t) *data++) > 0; uint32_t scopes_count = pm_options_read_u32(data); data += 4; diff --git a/src/main/c/yarp/src/prettyprint.c b/src/main/c/yarp/src/prettyprint.c index 68407c0a4a3..397cfbf4af0 100644 --- a/src/main/c/yarp/src/prettyprint.c +++ b/src/main/c/yarp/src/prettyprint.c @@ -231,6 +231,11 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm pm_buffer_concat(output_buffer, prefix_buffer); pm_buffer_append_string(output_buffer, "+-- ArgumentsNodeFlags:", 23); bool found = false; + if (cast->base.flags & PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " contains_forwarding", 20); + found = true; + } if (cast->base.flags & PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS) { if (found) pm_buffer_append_byte(output_buffer, ','); pm_buffer_append_string(output_buffer, " contains_keywords", 18); @@ -246,6 +251,11 @@ prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm pm_buffer_append_string(output_buffer, " contains_splat", 15); found = true; } + if (cast->base.flags & PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS) { + if (found) pm_buffer_append_byte(output_buffer, ','); + pm_buffer_append_string(output_buffer, " contains_multiple_splats", 25); + found = true; + } if (!found) pm_buffer_append_string(output_buffer, " nil", 4); pm_buffer_append_byte(output_buffer, '\n'); } diff --git a/src/main/c/yarp/src/prism.c b/src/main/c/yarp/src/prism.c index 28bd8d0d439..55f402a63c3 100644 --- a/src/main/c/yarp/src/prism.c +++ b/src/main/c/yarp/src/prism.c @@ -168,6 +168,7 @@ lex_mode_push_regexp(pm_parser_t *parser, uint8_t incrementor, uint8_t terminato breakpoints[index++] = incrementor; } + parser->explicit_encoding = NULL; return lex_mode_push(parser, lex_mode); } @@ -277,11 +278,6 @@ lex_state_beg_p(pm_parser_t *parser) { return lex_state_p(parser, PM_LEX_STATE_BEG_ANY) || ((parser->lex_state & (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)) == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)); } -static inline bool -lex_state_arg_labeled_p(pm_parser_t *parser) { - return (parser->lex_state & (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)) == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED); -} - static inline bool lex_state_arg_p(pm_parser_t *parser) { return lex_state_p(parser, PM_LEX_STATE_ARG_ANY); @@ -1038,7 +1034,7 @@ pm_parser_optional_constant_id_token(pm_parser_t *parser, const pm_token_t *toke */ static pm_node_t * pm_check_value_expression(pm_parser_t *parser, pm_node_t *node) { - pm_node_t* void_node = NULL; + pm_node_t *void_node = NULL; while (node != NULL) { switch (PM_NODE_TYPE(node)) { @@ -1054,24 +1050,43 @@ pm_check_value_expression(pm_parser_t *parser, pm_node_t *node) { case PM_BEGIN_NODE: { pm_begin_node_t *cast = (pm_begin_node_t *) node; - if (cast->statements == NULL && cast->ensure_clause != NULL) { - node = (pm_node_t *) cast->ensure_clause; - } - else { + if (cast->ensure_clause != NULL) { if (cast->rescue_clause != NULL) { - if (cast->rescue_clause->statements == NULL) { - return NULL; - } - else if (cast->else_clause != NULL) { - node = (pm_node_t *) cast->else_clause; + pm_node_t *vn = pm_check_value_expression(parser, (pm_node_t *) cast->rescue_clause); + if (vn != NULL) return vn; + } + + if (cast->statements != NULL) { + pm_node_t *vn = pm_check_value_expression(parser, (pm_node_t *) cast->statements); + if (vn != NULL) return vn; + } + + node = (pm_node_t *) cast->ensure_clause; + } else if (cast->rescue_clause != NULL) { + if (cast->statements == NULL) return NULL; + + pm_node_t *vn = pm_check_value_expression(parser, (pm_node_t *) cast->statements); + if (vn == NULL) return NULL; + if (void_node == NULL) void_node = vn; + + for (pm_rescue_node_t *rescue_clause = cast->rescue_clause; rescue_clause != NULL; rescue_clause = rescue_clause->subsequent) { + pm_node_t *vn = pm_check_value_expression(parser, (pm_node_t *) rescue_clause->statements); + if (vn == NULL) { + void_node = NULL; + break; } - else { - node = (pm_node_t *) cast->statements; + if (void_node == NULL) { + void_node = vn; } } - else { - node = (pm_node_t *) cast->statements; + + if (cast->else_clause != NULL) { + node = (pm_node_t *) cast->else_clause; + } else { + return void_node; } + } else { + node = (pm_node_t *) cast->statements; } break; @@ -2065,7 +2080,11 @@ pm_arguments_node_arguments_append(pm_arguments_node_t *node, pm_node_t *argumen pm_node_list_append(&node->arguments, argument); if (PM_NODE_TYPE_P(argument, PM_SPLAT_NODE)) { - pm_node_flag_set((pm_node_t *) node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT); + if (PM_NODE_FLAG_P(node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) { + pm_node_flag_set((pm_node_t *) node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS); + } else { + pm_node_flag_set((pm_node_t *) node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT); + } } } @@ -2985,6 +3004,7 @@ pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, cons pm_index_arguments_check(parser, target->arguments, target->block); + assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE)); *node = (pm_index_and_write_node_t) { { .type = PM_INDEX_AND_WRITE_NODE, @@ -3000,7 +3020,7 @@ pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, cons .opening_loc = target->opening_loc, .arguments = target->arguments, .closing_loc = target->closing_loc, - .block = target->block, + .block = (pm_block_argument_node_t *) target->block, .operator_loc = PM_LOCATION_TOKEN_VALUE(operator), .value = value }; @@ -3060,6 +3080,7 @@ pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, pm_index_arguments_check(parser, target->arguments, target->block); + assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE)); *node = (pm_index_operator_write_node_t) { { .type = PM_INDEX_OPERATOR_WRITE_NODE, @@ -3075,7 +3096,7 @@ pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, .opening_loc = target->opening_loc, .arguments = target->arguments, .closing_loc = target->closing_loc, - .block = target->block, + .block = (pm_block_argument_node_t *) target->block, .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1), .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator), .value = value @@ -3137,6 +3158,7 @@ pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_index_arguments_check(parser, target->arguments, target->block); + assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE)); *node = (pm_index_or_write_node_t) { { .type = PM_INDEX_OR_WRITE_NODE, @@ -3152,7 +3174,7 @@ pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const .opening_loc = target->opening_loc, .arguments = target->arguments, .closing_loc = target->closing_loc, - .block = target->block, + .block = (pm_block_argument_node_t *) target->block, .operator_loc = PM_LOCATION_TOKEN_VALUE(operator), .value = value }; @@ -3205,6 +3227,7 @@ pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) { pm_index_arguments_check(parser, target->arguments, target->block); + assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE)); *node = (pm_index_target_node_t) { { .type = PM_INDEX_TARGET_NODE, @@ -3216,7 +3239,7 @@ pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) { .opening_loc = target->opening_loc, .arguments = target->arguments, .closing_loc = target->closing_loc, - .block = target->block + .block = (pm_block_argument_node_t *) target->block, }; // Here we're going to free the target, since it is no longer necessary. @@ -3231,7 +3254,7 @@ pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) { * Allocate and initialize a new CapturePatternNode node. */ static pm_capture_pattern_node_t * -pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *target, const pm_token_t *operator) { +pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_local_variable_target_node_t *target, const pm_token_t *operator) { pm_capture_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_capture_pattern_node_t); *node = (pm_capture_pattern_node_t) { @@ -3240,7 +3263,7 @@ pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t .node_id = PM_NODE_IDENTIFY(parser), .location = { .start = value->location.start, - .end = target->location.end + .end = target->base.location.end }, }, .value = value, @@ -4032,14 +4055,25 @@ pm_find_pattern_node_create(pm_parser_t *parser, pm_node_list_t *nodes) { pm_find_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_find_pattern_node_t); pm_node_t *left = nodes->nodes[0]; + assert(PM_NODE_TYPE_P(left, PM_SPLAT_NODE)); + pm_splat_node_t *left_splat_node = (pm_splat_node_t *) left; + pm_node_t *right; if (nodes->size == 1) { right = (pm_node_t *) pm_missing_node_create(parser, left->location.end, left->location.end); } else { right = nodes->nodes[nodes->size - 1]; + assert(PM_NODE_TYPE_P(right, PM_SPLAT_NODE)); } +#if PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS + // FindPatternNode#right is typed as SplatNode in this case, so replace the potential MissingNode with a SplatNode. + // The resulting AST will anyway be ignored, but this file still needs to compile. + pm_splat_node_t *right_splat_node = PM_NODE_TYPE_P(right, PM_SPLAT_NODE) ? (pm_splat_node_t *) right : left_splat_node; +#else + pm_node_t *right_splat_node = right; +#endif *node = (pm_find_pattern_node_t) { { .type = PM_FIND_PATTERN_NODE, @@ -4050,8 +4084,8 @@ pm_find_pattern_node_create(pm_parser_t *parser, pm_node_list_t *nodes) { }, }, .constant = NULL, - .left = left, - .right = right, + .left = left_splat_node, + .right = right_splat_node, .requireds = { 0 }, .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE, .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE @@ -6147,14 +6181,14 @@ pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *to errno = 0; unsigned long value = strtoul(digits, &endptr, 10); - if ((digits == endptr) || (*endptr != '\0') || (errno == ERANGE)) { + if ((digits == endptr) || (*endptr != '\0')) { pm_parser_err(parser, start, end, PM_ERR_INVALID_NUMBER_DECIMAL); value = 0; } xfree(digits); - if (value > NTH_REF_MAX) { + if ((errno == ERANGE) || (value > NTH_REF_MAX)) { PM_PARSER_WARN_FORMAT(parser, start, end, PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start); value = 0; } @@ -11273,7 +11307,16 @@ parser_lex(pm_parser_t *parser) { pm_token_type_t type = PM_TOKEN_AMPERSAND; if (lex_state_spcarg_p(parser, space_seen)) { - pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND); + if ((peek(parser) != ':') || (peek_offset(parser, 1) == '\0')) { + pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND); + } else { + const uint8_t delim = peek_offset(parser, 1); + + if ((delim != '\'') && (delim != '"') && !char_is_identifier(parser, parser->current.end + 1)) { + pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND); + } + } + type = PM_TOKEN_UAMPERSAND; } else if (lex_state_beg_p(parser)) { type = PM_TOKEN_UAMPERSAND; @@ -11409,10 +11452,7 @@ parser_lex(pm_parser_t *parser) { if (match(parser, '.')) { if (match(parser, '.')) { // If we're _not_ inside a range within default parameters - if ( - !context_p(parser, PM_CONTEXT_DEFAULT_PARAMS) && - context_p(parser, PM_CONTEXT_DEF_PARAMS) - ) { + if (!context_p(parser, PM_CONTEXT_DEFAULT_PARAMS) && context_p(parser, PM_CONTEXT_DEF_PARAMS)) { if (lex_state_p(parser, PM_LEX_STATE_END)) { lex_state_set(parser, PM_LEX_STATE_BEG); } else { @@ -13138,15 +13178,15 @@ expect1_heredoc_term(pm_parser_t *parser, pm_lex_mode_t *lex_mode) { } static pm_node_t * -parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id); +parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call, bool accepts_label, pm_diagnostic_id_t diag_id, uint16_t depth); /** * This is a wrapper of parse_expression, which also checks whether the * resulting node is a value expression. */ static pm_node_t * -parse_value_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id) { - pm_node_t *node = parse_expression(parser, binding_power, accepts_command_call, diag_id); +parse_value_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call, bool accepts_label, pm_diagnostic_id_t diag_id, uint16_t depth) { + pm_node_t *node = parse_expression(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth); pm_assert_value_expression(parser, node); return node; } @@ -13230,14 +13270,14 @@ token_begins_expression_p(pm_token_type_t type) { * prefixed by the * operator. */ static pm_node_t * -parse_starred_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id) { +parse_starred_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id, uint16_t depth) { if (accept1(parser, PM_TOKEN_USTAR)) { pm_token_t operator = parser->previous; - pm_node_t *expression = parse_value_expression(parser, binding_power, false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR); + pm_node_t *expression = parse_value_expression(parser, binding_power, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1)); return (pm_node_t *) pm_splat_node_create(parser, &operator, expression); } - return parse_value_expression(parser, binding_power, accepts_command_call, diag_id); + return parse_value_expression(parser, binding_power, accepts_command_call, false, diag_id, depth); } /** @@ -13731,7 +13771,7 @@ parse_unwriteable_write(pm_parser_t *parser, pm_node_t *target, const pm_token_t * target node or a multi-target node. */ static pm_node_t * -parse_targets(pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t binding_power) { +parse_targets(pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) { bool has_rest = PM_NODE_TYPE_P(first_target, PM_SPLAT_NODE); pm_multi_target_node_t *result = pm_multi_target_node_create(parser); @@ -13750,7 +13790,7 @@ parse_targets(pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t b pm_node_t *name = NULL; if (token_begins_expression_p(parser->current.type)) { - name = parse_expression(parser, binding_power, false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR); + name = parse_expression(parser, binding_power, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1)); name = parse_target(parser, name, true, true); } @@ -13758,7 +13798,7 @@ parse_targets(pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t b pm_multi_target_node_targets_append(parser, result, splat); has_rest = true; } else if (token_begins_expression_p(parser->current.type)) { - pm_node_t *target = parse_expression(parser, binding_power, false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA); + pm_node_t *target = parse_expression(parser, binding_power, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1)); target = parse_target(parser, target, true, false); pm_multi_target_node_targets_append(parser, result, target); @@ -13779,8 +13819,8 @@ parse_targets(pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t b * assignment. */ static pm_node_t * -parse_targets_validate(pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t binding_power) { - pm_node_t *result = parse_targets(parser, first_target, binding_power); +parse_targets_validate(pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) { + pm_node_t *result = parse_targets(parser, first_target, binding_power, depth); accept1(parser, PM_TOKEN_NEWLINE); // Ensure that we have either an = or a ) after the targets. @@ -13795,7 +13835,7 @@ parse_targets_validate(pm_parser_t *parser, pm_node_t *first_target, pm_binding_ * Parse a list of statements separated by newlines or semicolons. */ static pm_statements_node_t * -parse_statements(pm_parser_t *parser, pm_context_t context) { +parse_statements(pm_parser_t *parser, pm_context_t context, uint16_t depth) { // First, skip past any optional terminators that might be at the beginning // of the statements. while (accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE)); @@ -13810,7 +13850,7 @@ parse_statements(pm_parser_t *parser, pm_context_t context) { context_push(parser, context); while (true) { - pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, true, PM_ERR_CANNOT_PARSE_EXPRESSION); + pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, true, false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1)); pm_statements_node_body_append(parser, statements, node, true); // If we're recovering from a syntax error, then we need to stop parsing @@ -13930,7 +13970,7 @@ pm_when_clause_static_literals_add(pm_parser_t *parser, pm_static_literals_t *li * Parse all of the elements of a hash. Return true if a double splat was found. */ static bool -parse_assocs(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *node) { +parse_assocs(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *node, uint16_t depth) { assert(PM_NODE_TYPE_P(node, PM_HASH_NODE) || PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE)); bool contains_keyword_splat = false; @@ -13949,9 +13989,9 @@ parse_assocs(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *nod // inner hash to share the static literals with the outer // hash. parser->current_hash_keys = literals; - value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH); + value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1)); } else if (token_begins_expression_p(parser->current.type)) { - value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH); + value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1)); } else { pm_parser_scope_forwarding_keywords_check(parser, &operator); } @@ -13971,7 +14011,7 @@ parse_assocs(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *nod pm_node_t *value = NULL; if (token_begins_expression_p(parser->current.type)) { - value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_HASH_EXPRESSION_AFTER_LABEL); + value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_HASH_EXPRESSION_AFTER_LABEL, (uint16_t) (depth + 1)); } else { if (parser->encoding->isupper_char(label.start, (label.end - 1) - label.start)) { pm_token_t constant = { .type = PM_TOKEN_CONSTANT, .start = label.start, .end = label.end - 1 }; @@ -14001,7 +14041,7 @@ parse_assocs(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *nod break; } default: { - pm_node_t *key = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_HASH_KEY); + pm_node_t *key = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, true, PM_ERR_HASH_KEY, (uint16_t) (depth + 1)); // Hash keys that are strings are automatically frozen. We will // mark that here. @@ -14019,7 +14059,7 @@ parse_assocs(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *nod operator = parser->previous; } - pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_HASH_VALUE); + pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1)); element = (pm_node_t *) pm_assoc_node_create(parser, key, &operator, value); break; } @@ -14065,7 +14105,7 @@ parse_arguments_append(pm_parser_t *parser, pm_arguments_t *arguments, pm_node_t * Parse a list of arguments. */ static void -parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_forwarding, pm_token_type_t terminator) { +parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_forwarding, pm_token_type_t terminator, uint16_t depth) { pm_binding_power_t binding_power = pm_binding_powers[parser->current.type].left; // First we need to check if the next token is one that could be the start of @@ -14084,9 +14124,6 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for bool parsed_forwarding_arguments = false; while (!match1(parser, PM_TOKEN_EOF)) { - if (parsed_block_argument) { - pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK); - } if (parsed_forwarding_arguments) { pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES); } @@ -14104,7 +14141,7 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for argument = (pm_node_t *) hash; pm_static_literals_t hash_keys = { 0 }; - bool contains_keyword_splat = parse_assocs(parser, &hash_keys, (pm_node_t *) hash); + bool contains_keyword_splat = parse_assocs(parser, &hash_keys, (pm_node_t *) hash, (uint16_t) (depth + 1)); parse_arguments_append(parser, arguments, argument); @@ -14123,7 +14160,7 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for pm_node_t *expression = NULL; if (token_begins_expression_p(parser->current.type)) { - expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_EXPECT_ARGUMENT); + expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1)); } else { pm_parser_scope_forwarding_block_check(parser, &operator); } @@ -14135,6 +14172,10 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for arguments->block = argument; } + if (match1(parser, PM_TOKEN_COMMA)) { + pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK); + } + parsed_block_argument = true; break; } @@ -14146,7 +14187,7 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for pm_parser_scope_forwarding_positionals_check(parser, &operator); argument = (pm_node_t *) pm_splat_node_create(parser, &operator, NULL); } else { - pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT); + pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT, (uint16_t) (depth + 1)); if (parsed_bare_hash) { pm_parser_err(parser, operator.start, expression->location.end, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT); @@ -14163,10 +14204,20 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for parser_lex(parser); if (token_begins_expression_p(parser->current.type)) { - // If the token begins an expression then this ... was not actually - // argument forwarding but was instead a range. + // If the token begins an expression then this ... was + // not actually argument forwarding but was instead a + // range. pm_token_t operator = parser->previous; - pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_RANGE, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_RANGE, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1)); + + // If we parse a range, we need to validate that we + // didn't accidentally violate the nonassoc rules of the + // ... operator. + if (PM_NODE_TYPE_P(right, PM_RANGE_NODE)) { + pm_range_node_t *range = (pm_range_node_t *) right; + pm_parser_err(parser, range->operator_loc.start, range->operator_loc.end, PM_ERR_UNEXPECTED_RANGE_OPERATOR); + } + argument = (pm_node_t *) pm_range_node_create(parser, NULL, &operator, right); } else { pm_parser_scope_forwarding_all_check(parser, &parser->previous); @@ -14176,6 +14227,7 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for argument = (pm_node_t *) pm_forwarding_arguments_node_create(parser, &parser->previous); parse_arguments_append(parser, arguments, argument); + pm_node_flag_set((pm_node_t *) arguments->arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING); arguments->has_forwarding = true; parsed_forwarding_arguments = true; break; @@ -14185,7 +14237,7 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for /* fallthrough */ default: { if (argument == NULL) { - argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, !parsed_first_argument, PM_ERR_EXPECT_ARGUMENT); + argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, !parsed_first_argument, true, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1)); } bool contains_keywords = false; @@ -14211,7 +14263,7 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for pm_hash_key_static_literals_add(parser, &hash_keys, argument); // Finish parsing the one we are part way through. - pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_HASH_VALUE); + pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1)); argument = (pm_node_t *) pm_assoc_node_create(parser, argument, &operator, value); pm_keyword_hash_node_elements_append(bare_hash, argument); @@ -14222,14 +14274,11 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for token_begins_expression_p(parser->current.type) || match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL) )) { - contains_keyword_splat = parse_assocs(parser, &hash_keys, (pm_node_t *) bare_hash); + contains_keyword_splat = parse_assocs(parser, &hash_keys, (pm_node_t *) bare_hash, (uint16_t) (depth + 1)); } pm_static_literals_free(&hash_keys); parsed_bare_hash = true; - } else if (accept1(parser, PM_TOKEN_KEYWORD_IN)) { - // TODO: Could we solve this with binding powers instead? - pm_parser_err_current(parser, PM_ERR_ARGUMENT_IN); } parse_arguments_append(parser, arguments, argument); @@ -14417,7 +14466,9 @@ parse_parameters( pm_binding_power_t binding_power, bool uses_parentheses, bool allows_trailing_comma, - bool allows_forwarding_parameters + bool allows_forwarding_parameters, + bool accepts_blocks_in_defaults, + uint16_t depth ) { pm_parameters_node_t *params = pm_parameters_node_create(parser); bool looping = true; @@ -14528,18 +14579,22 @@ parse_parameters( bool repeated = pm_parser_parameter_name_check(parser, &name); pm_parser_local_add_token(parser, &name, 1); - if (accept1(parser, PM_TOKEN_EQUAL)) { - pm_token_t operator = parser->previous; + if (match1(parser, PM_TOKEN_EQUAL)) { + pm_token_t operator = parser->current; context_push(parser, PM_CONTEXT_DEFAULT_PARAMS); + parser_lex(parser); pm_constant_id_t name_id = pm_parser_constant_id_token(parser, &name); uint32_t reads = parser->version == PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0; - pm_node_t *value = parse_value_expression(parser, binding_power, false, PM_ERR_PARAMETER_NO_DEFAULT); + if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser, true); + pm_node_t *value = parse_value_expression(parser, binding_power, false, false, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1)); + if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser); + pm_optional_parameter_node_t *param = pm_optional_parameter_node_create(parser, &name, &operator, value); if (repeated) { - pm_node_flag_set_repeated_parameter((pm_node_t *)param); + pm_node_flag_set_repeated_parameter((pm_node_t *) param); } pm_parameters_node_optionals_append(params, param); @@ -14578,6 +14633,8 @@ parse_parameters( case PM_TOKEN_LABEL: { if (!uses_parentheses) parser->in_keyword_arg = true; update_parameter_state(parser, &parser->current, &order); + + context_push(parser, PM_CONTEXT_DEFAULT_PARAMS); parser_lex(parser); pm_token_t name = parser->previous; @@ -14597,15 +14654,20 @@ parse_parameters( case PM_TOKEN_COMMA: case PM_TOKEN_PARENTHESIS_RIGHT: case PM_TOKEN_PIPE: { + context_pop(parser); + pm_node_t *param = (pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name); if (repeated) { pm_node_flag_set_repeated_parameter(param); } + pm_parameters_node_keywords_append(params, param); break; } case PM_TOKEN_SEMICOLON: case PM_TOKEN_NEWLINE: { + context_pop(parser); + if (uses_parentheses) { looping = false; break; @@ -14615,6 +14677,7 @@ parse_parameters( if (repeated) { pm_node_flag_set_repeated_parameter(param); } + pm_parameters_node_keywords_append(params, param); break; } @@ -14622,17 +14685,17 @@ parse_parameters( pm_node_t *param; if (token_begins_expression_p(parser->current.type)) { - context_push(parser, PM_CONTEXT_DEFAULT_PARAMS); - pm_constant_id_t name_id = pm_parser_constant_id_token(parser, &local); uint32_t reads = parser->version == PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0; - pm_node_t *value = parse_value_expression(parser, binding_power, false, PM_ERR_PARAMETER_NO_DEFAULT_KW); + + if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser, true); + pm_node_t *value = parse_value_expression(parser, binding_power, false, false, PM_ERR_PARAMETER_NO_DEFAULT_KW, (uint16_t) (depth + 1)); + if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser); if (parser->version == PM_OPTIONS_VERSION_CRUBY_3_3 && (pm_locals_reads(&parser->current_scope->locals, name_id) != reads)) { PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_PARAMETER_CIRCULAR); } - context_pop(parser); param = (pm_node_t *) pm_optional_keyword_parameter_node_create(parser, &name, value); } else { @@ -14642,6 +14705,8 @@ parse_parameters( if (repeated) { pm_node_flag_set_repeated_parameter(param); } + + context_pop(parser); pm_parameters_node_keywords_append(params, param); // If parsing the value of the parameter resulted in error recovery, @@ -14734,7 +14799,7 @@ parse_parameters( } default: if (parser->previous.type == PM_TOKEN_COMMA) { - if (allows_trailing_comma) { + if (allows_trailing_comma && order >= PM_PARAMETERS_ORDER_NAMED) { // If we get here, then we have a trailing comma in a // block parameter list. pm_node_t *param = (pm_node_t *) pm_implicit_rest_node_create(parser, &parser->previous); @@ -14831,7 +14896,7 @@ token_column(const pm_parser_t *parser, size_t newline_index, const pm_token_t * * function warns if the indentation of the two tokens does not match. */ static void -parser_warn_indentation_mismatch(pm_parser_t *parser, size_t opening_newline_index, const pm_token_t *opening_token, bool if_after_else) { +parser_warn_indentation_mismatch(pm_parser_t *parser, size_t opening_newline_index, const pm_token_t *opening_token, bool if_after_else, bool allow_indent) { // If these warnings are disabled (unlikely), then we can just return. if (!parser->warn_mismatched_indentation) return; @@ -14853,6 +14918,10 @@ parser_warn_indentation_mismatch(pm_parser_t *parser, size_t opening_newline_ind int64_t closing_column = token_column(parser, closing_newline_index, closing_token, true); if ((closing_column == -1) || (opening_column == closing_column)) return; + // If the closing column is greater than the opening column and we are + // allowing indentation, then we do not warn. + if (allow_indent && (closing_column > opening_column)) return; + // Otherwise, add a warning. PM_PARSER_WARN_FORMAT( parser, @@ -14882,11 +14951,11 @@ typedef enum { * nodes pointing to each other from the top. */ static inline void -parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_t *opening, pm_begin_node_t *parent_node, pm_rescues_type_t type) { +parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_t *opening, pm_begin_node_t *parent_node, pm_rescues_type_t type, uint16_t depth) { pm_rescue_node_t *current = NULL; while (match1(parser, PM_TOKEN_KEYWORD_RESCUE)) { - if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening, false); + if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening, false, false); parser_lex(parser); pm_rescue_node_t *rescue = pm_rescue_node_create(parser, &parser->previous); @@ -14899,7 +14968,7 @@ parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_ parser_lex(parser); pm_rescue_node_operator_set(rescue, &parser->previous); - pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, false, PM_ERR_RESCUE_VARIABLE); + pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, false, false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1)); reference = parse_target(parser, reference, false, false); pm_rescue_node_reference_set(rescue, reference); @@ -14917,7 +14986,7 @@ parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_ // we'll attempt to parse it here and any others delimited by commas. do { - pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_RESCUE_EXPRESSION); + pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_RESCUE_EXPRESSION, (uint16_t) (depth + 1)); pm_rescue_node_exceptions_append(rescue, expression); // If we hit a newline, then this is the end of the rescue expression. We @@ -14929,7 +14998,7 @@ parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_ if (accept1(parser, PM_TOKEN_EQUAL_GREATER)) { pm_rescue_node_operator_set(rescue, &parser->previous); - pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, false, PM_ERR_RESCUE_VARIABLE); + pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, false, false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1)); reference = parse_target(parser, reference, false, false); pm_rescue_node_reference_set(rescue, reference); @@ -14961,7 +15030,7 @@ parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_ default: assert(false && "unreachable"); context = PM_CONTEXT_BEGIN_RESCUE; break; } - pm_statements_node_t *statements = parse_statements(parser, context); + pm_statements_node_t *statements = parse_statements(parser, context, (uint16_t) (depth + 1)); if (statements != NULL) pm_rescue_node_statements_set(rescue, statements); pm_accepts_block_stack_pop(parser); @@ -14992,7 +15061,7 @@ parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_ pm_token_t else_keyword; if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) { - if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening, false); + if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening, false, false); opening_newline_index = token_newline_index(parser); else_keyword = parser->current; @@ -15017,7 +15086,7 @@ parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_ default: assert(false && "unreachable"); context = PM_CONTEXT_BEGIN_RESCUE; break; } - else_statements = parse_statements(parser, context); + else_statements = parse_statements(parser, context, (uint16_t) (depth + 1)); pm_accepts_block_stack_pop(parser); accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON); @@ -15032,7 +15101,7 @@ parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_ } if (match1(parser, PM_TOKEN_KEYWORD_ENSURE)) { - if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening, false); + if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening, false, false); pm_token_t ensure_keyword = parser->current; parser_lex(parser); @@ -15054,7 +15123,7 @@ parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_ default: assert(false && "unreachable"); context = PM_CONTEXT_BEGIN_RESCUE; break; } - ensure_statements = parse_statements(parser, context); + ensure_statements = parse_statements(parser, context, (uint16_t) (depth + 1)); pm_accepts_block_stack_pop(parser); accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON); @@ -15065,7 +15134,7 @@ parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_ } if (match1(parser, PM_TOKEN_KEYWORD_END)) { - if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening, false); + if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening, false, false); pm_begin_node_end_keyword_set(parent_node, &parser->current); } else { pm_token_t end_keyword = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end }; @@ -15078,11 +15147,11 @@ parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_ * class, module, def, etc.). */ static pm_begin_node_t * -parse_rescues_implicit_begin(pm_parser_t *parser, size_t opening_newline_index, const pm_token_t *opening, const uint8_t *start, pm_statements_node_t *statements, pm_rescues_type_t type) { +parse_rescues_implicit_begin(pm_parser_t *parser, size_t opening_newline_index, const pm_token_t *opening, const uint8_t *start, pm_statements_node_t *statements, pm_rescues_type_t type, uint16_t depth) { pm_token_t begin_keyword = not_provided(parser); pm_begin_node_t *node = pm_begin_node_create(parser, &begin_keyword, statements); - parse_rescues(parser, opening_newline_index, opening, node, type); + parse_rescues(parser, opening_newline_index, opening, node, type, (uint16_t) (depth + 1)); node->base.location.start = start; return node; @@ -15096,7 +15165,9 @@ parse_block_parameters( pm_parser_t *parser, bool allows_trailing_comma, const pm_token_t *opening, - bool is_lambda_literal + bool is_lambda_literal, + bool accepts_blocks_in_defaults, + uint16_t depth ) { pm_parameters_node_t *parameters = NULL; if (!match1(parser, PM_TOKEN_SEMICOLON)) { @@ -15105,7 +15176,9 @@ parse_block_parameters( is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX, false, allows_trailing_comma, - false + false, + accepts_blocks_in_defaults, + (uint16_t) (depth + 1) ); } @@ -15259,7 +15332,7 @@ parse_blocklike_parameters(pm_parser_t *parser, pm_node_t *parameters, const pm_ * Parse a block. */ static pm_block_node_t * -parse_block(pm_parser_t *parser) { +parse_block(pm_parser_t *parser, uint16_t depth) { pm_token_t opening = parser->previous; accept1(parser, PM_TOKEN_NEWLINE); @@ -15275,7 +15348,7 @@ parse_block(pm_parser_t *parser) { parser->command_start = true; parser_lex(parser); } else { - block_parameters = parse_block_parameters(parser, true, &block_parameters_opening, false); + block_parameters = parse_block_parameters(parser, true, &block_parameters_opening, false, true, (uint16_t) (depth + 1)); accept1(parser, PM_TOKEN_NEWLINE); parser->command_start = true; expect1(parser, PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM); @@ -15289,7 +15362,7 @@ parse_block(pm_parser_t *parser) { if (opening.type == PM_TOKEN_BRACE_LEFT) { if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) { - statements = (pm_node_t *) parse_statements(parser, PM_CONTEXT_BLOCK_BRACES); + statements = (pm_node_t *) parse_statements(parser, PM_CONTEXT_BLOCK_BRACES, (uint16_t) (depth + 1)); } expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE); @@ -15297,13 +15370,13 @@ parse_block(pm_parser_t *parser) { if (!match1(parser, PM_TOKEN_KEYWORD_END)) { if (!match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE)) { pm_accepts_block_stack_push(parser, true); - statements = (pm_node_t *) parse_statements(parser, PM_CONTEXT_BLOCK_KEYWORDS); + statements = (pm_node_t *) parse_statements(parser, PM_CONTEXT_BLOCK_KEYWORDS, (uint16_t) (depth + 1)); pm_accepts_block_stack_pop(parser); } if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) { assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE)); - statements = (pm_node_t *) parse_rescues_implicit_begin(parser, 0, NULL, opening.start, (pm_statements_node_t *) statements, PM_RESCUES_BLOCK); + statements = (pm_node_t *) parse_rescues_implicit_begin(parser, 0, NULL, opening.start, (pm_statements_node_t *) statements, PM_RESCUES_BLOCK, (uint16_t) (depth + 1)); } } @@ -15326,7 +15399,7 @@ parse_block(pm_parser_t *parser) { * arguments, or blocks). */ static bool -parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_block, bool accepts_command_call) { +parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_block, bool accepts_command_call, uint16_t depth) { bool found = false; if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) { @@ -15337,7 +15410,7 @@ parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accept arguments->closing_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous); } else { pm_accepts_block_stack_push(parser, true); - parse_arguments(parser, arguments, accepts_block, PM_TOKEN_PARENTHESIS_RIGHT); + parse_arguments(parser, arguments, accepts_block, PM_TOKEN_PARENTHESIS_RIGHT, (uint16_t) (depth + 1)); if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) { PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_ARGUMENT_TERM_PAREN, pm_token_type_human(parser->current.type)); @@ -15355,13 +15428,13 @@ parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accept // 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. - parse_arguments(parser, arguments, accepts_block, PM_TOKEN_EOF); + parse_arguments(parser, arguments, accepts_block, PM_TOKEN_EOF, (uint16_t) (depth + 1)); // If we have done with the arguments and still not consumed the comma, // then we have a trailing comma where we need to check whether it is // allowed or not. if (parser->previous.type == PM_TOKEN_COMMA && !match1(parser, PM_TOKEN_SEMICOLON)) { - pm_parser_err_previous(parser, PM_ERR_EXPECT_ARGUMENT); + PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, PM_ERR_EXPECT_ARGUMENT, pm_token_type_human(parser->current.type)); } pm_accepts_block_stack_pop(parser); @@ -15375,11 +15448,11 @@ parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accept if (accept1(parser, PM_TOKEN_BRACE_LEFT)) { found |= true; - block = parse_block(parser); + block = parse_block(parser, (uint16_t) (depth + 1)); pm_arguments_validate_block(parser, arguments, block); } else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) { found |= true; - block = parse_block(parser); + block = parse_block(parser, (uint16_t) (depth + 1)); } if (block != NULL) { @@ -15418,7 +15491,6 @@ parse_return(pm_parser_t *parser, pm_node_t *node) { case PM_CONTEXT_CASE_IN: case PM_CONTEXT_CASE_WHEN: case PM_CONTEXT_DEFAULT_PARAMS: - case PM_CONTEXT_DEF_PARAMS: case PM_CONTEXT_DEFINED: case PM_CONTEXT_ELSE: case PM_CONTEXT_ELSIF: @@ -15464,6 +15536,7 @@ parse_return(pm_parser_t *parser, pm_node_t *node) { case PM_CONTEXT_BLOCK_RESCUE: case PM_CONTEXT_DEF_ELSE: case PM_CONTEXT_DEF_ENSURE: + case PM_CONTEXT_DEF_PARAMS: case PM_CONTEXT_DEF_RESCUE: case PM_CONTEXT_DEF: case PM_CONTEXT_LAMBDA_BRACES: @@ -15634,10 +15707,10 @@ pop_block_exits(pm_parser_t *parser, pm_node_list_t *previous_block_exits) { } static inline pm_node_t * -parse_predicate(pm_parser_t *parser, pm_binding_power_t binding_power, pm_context_t context, pm_token_t *then_keyword) { +parse_predicate(pm_parser_t *parser, pm_binding_power_t binding_power, pm_context_t context, pm_token_t *then_keyword, uint16_t depth) { context_push(parser, PM_CONTEXT_PREDICATE); pm_diagnostic_id_t error_id = context == PM_CONTEXT_IF ? PM_ERR_CONDITIONAL_IF_PREDICATE : PM_ERR_CONDITIONAL_UNLESS_PREDICATE; - pm_node_t *predicate = parse_value_expression(parser, binding_power, true, error_id); + pm_node_t *predicate = parse_value_expression(parser, binding_power, true, false, error_id, (uint16_t) (depth + 1)); // Predicates are closed by a term, a "then", or a term and then a "then". bool predicate_closed = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON); @@ -15656,19 +15729,19 @@ parse_predicate(pm_parser_t *parser, pm_binding_power_t binding_power, pm_contex } static inline pm_node_t * -parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newline_index, bool if_after_else) { +parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newline_index, bool if_after_else, uint16_t depth) { pm_node_list_t current_block_exits = { 0 }; pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits); pm_token_t keyword = parser->previous; pm_token_t then_keyword = not_provided(parser); - pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context, &then_keyword); + pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context, &then_keyword, (uint16_t) (depth + 1)); pm_statements_node_t *statements = NULL; if (!match3(parser, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) { pm_accepts_block_stack_push(parser, true); - statements = parse_statements(parser, context); + statements = parse_statements(parser, context, (uint16_t) (depth + 1)); pm_accepts_block_stack_pop(parser); accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON); } @@ -15698,14 +15771,14 @@ parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newl PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_WARN_KEYWORD_EOL); } - parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, false); + parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, false, false); pm_token_t elsif_keyword = parser->current; parser_lex(parser); - pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, PM_CONTEXT_ELSIF, &then_keyword); + pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1)); pm_accepts_block_stack_push(parser, true); - pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_ELSIF); + pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_ELSIF, (uint16_t) (depth + 1)); pm_accepts_block_stack_pop(parser); accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON); @@ -15716,18 +15789,18 @@ parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newl } if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) { - parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, false); + parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, false, false); opening_newline_index = token_newline_index(parser); parser_lex(parser); pm_token_t else_keyword = parser->previous; pm_accepts_block_stack_push(parser, true); - pm_statements_node_t *else_statements = parse_statements(parser, PM_CONTEXT_ELSE); + pm_statements_node_t *else_statements = parse_statements(parser, PM_CONTEXT_ELSE, (uint16_t) (depth + 1)); pm_accepts_block_stack_pop(parser); accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON); - parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword, false); + parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword, false, false); expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE); pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->previous); @@ -15744,7 +15817,7 @@ parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newl break; } } else { - parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else); + parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else, false); expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM); } @@ -15880,7 +15953,7 @@ parse_unescaped_encoding(const pm_parser_t *parser) { * parsed as a string part, then NULL is returned. */ static pm_node_t * -parse_string_part(pm_parser_t *parser) { +parse_string_part(pm_parser_t *parser, uint16_t depth) { switch (parser->current.type) { // Here the lexer has returned to us plain string content. In this case // we'll create a string node that has no opening or closing and return that @@ -15921,7 +15994,7 @@ parse_string_part(pm_parser_t *parser) { if (!match1(parser, PM_TOKEN_EMBEXPR_END)) { pm_accepts_block_stack_push(parser, true); - statements = parse_statements(parser, PM_CONTEXT_EMBEXPR); + statements = parse_statements(parser, PM_CONTEXT_EMBEXPR, (uint16_t) (depth + 1)); pm_accepts_block_stack_pop(parser); } @@ -16046,7 +16119,7 @@ parse_operator_symbol(pm_parser_t *parser, const pm_token_t *opening, pm_lex_sta * symbols. */ static pm_node_t * -parse_symbol(pm_parser_t *parser, pm_lex_mode_t *lex_mode, pm_lex_state_t next_state) { +parse_symbol(pm_parser_t *parser, pm_lex_mode_t *lex_mode, pm_lex_state_t next_state, uint16_t depth) { const pm_token_t opening = parser->previous; if (lex_mode->mode != PM_LEX_STRING) { @@ -16092,7 +16165,7 @@ parse_symbol(pm_parser_t *parser, pm_lex_mode_t *lex_mode, pm_lex_state_t next_s } // Now we can parse the first part of the symbol. - pm_node_t *part = parse_string_part(parser); + pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1)); // If we got a string part, then it's possible that we could transform // what looks like an interpolated symbol into a regular symbol. @@ -16107,7 +16180,7 @@ parse_symbol(pm_parser_t *parser, pm_lex_mode_t *lex_mode, pm_lex_state_t next_s if (part) pm_interpolated_symbol_node_append(symbol, part); while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) { - if ((part = parse_string_part(parser)) != NULL) { + if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) { pm_interpolated_symbol_node_append(symbol, part); } } @@ -16183,7 +16256,7 @@ parse_symbol(pm_parser_t *parser, pm_lex_mode_t *lex_mode, pm_lex_state_t next_s * constant, or an interpolated symbol. */ static inline pm_node_t * -parse_undef_argument(pm_parser_t *parser) { +parse_undef_argument(pm_parser_t *parser, uint16_t depth) { switch (parser->current.type) { case PM_CASE_OPERATOR: { const pm_token_t opening = not_provided(parser); @@ -16208,7 +16281,7 @@ parse_undef_argument(pm_parser_t *parser) { pm_lex_mode_t lex_mode = *parser->lex_modes.current; parser_lex(parser); - return parse_symbol(parser, &lex_mode, PM_LEX_STATE_NONE); + return parse_symbol(parser, &lex_mode, PM_LEX_STATE_NONE, (uint16_t) (depth + 1)); } default: pm_parser_err_current(parser, PM_ERR_UNDEF_ARGUMENT); @@ -16223,7 +16296,7 @@ parse_undef_argument(pm_parser_t *parser) { * between the first and second arguments. */ static inline pm_node_t * -parse_alias_argument(pm_parser_t *parser, bool first) { +parse_alias_argument(pm_parser_t *parser, bool first, uint16_t depth) { switch (parser->current.type) { case PM_CASE_OPERATOR: { const pm_token_t opening = not_provided(parser); @@ -16249,7 +16322,7 @@ parse_alias_argument(pm_parser_t *parser, bool first) { pm_lex_mode_t lex_mode = *parser->lex_modes.current; parser_lex(parser); - return parse_symbol(parser, &lex_mode, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE); + return parse_symbol(parser, &lex_mode, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE, (uint16_t) (depth + 1)); } case PM_TOKEN_BACK_REFERENCE: parser_lex(parser); @@ -16449,11 +16522,9 @@ parse_strings_empty_content(const uint8_t *location) { * Parse a set of strings that could be concatenated together. */ static inline pm_node_t * -parse_strings(pm_parser_t *parser, pm_node_t *current) { +parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint16_t depth) { assert(parser->current.type == PM_TOKEN_STRING_BEGIN); - bool concating = false; - bool state_is_arg_labeled = lex_state_arg_labeled_p(parser); while (match1(parser, PM_TOKEN_STRING_BEGIN)) { pm_node_t *node = NULL; @@ -16463,6 +16534,7 @@ parse_strings(pm_parser_t *parser, pm_node_t *current) { const pm_lex_mode_t *lex_mode = parser->lex_modes.current; assert(lex_mode->mode == PM_LEX_STRING); bool lex_interpolation = lex_mode->as.string.interpolation; + bool label_allowed = lex_mode->as.string.label_allowed && accepts_label; pm_token_t opening = parser->current; parser_lex(parser); @@ -16486,6 +16558,8 @@ parse_strings(pm_parser_t *parser, pm_node_t *current) { pm_string_shared_init(&symbol->unescaped, content.start, content.end); node = (pm_node_t *) symbol; + + if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL); } else if (!lex_interpolation) { // If we don't accept interpolation then we expect the string to // start with a single string content node. @@ -16529,8 +16603,9 @@ parse_strings(pm_parser_t *parser, pm_node_t *current) { node = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous); pm_node_list_free(&parts); - } else if (accept1(parser, PM_TOKEN_LABEL_END) && !state_is_arg_labeled) { + } else if (accept1(parser, PM_TOKEN_LABEL_END)) { node = (pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped, true)); + if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL); } else if (match1(parser, PM_TOKEN_EOF)) { pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF); node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped); @@ -16569,6 +16644,7 @@ parse_strings(pm_parser_t *parser, pm_node_t *current) { } } else if (accept1(parser, PM_TOKEN_LABEL_END)) { node = (pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped, true)); + if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL); } else { // If we get here, then we have interpolation so we'll need // to create a string or symbol node with interpolation. @@ -16581,13 +16657,14 @@ parse_strings(pm_parser_t *parser, pm_node_t *current) { pm_node_list_append(&parts, part); while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) { - if ((part = parse_string_part(parser)) != NULL) { + if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) { pm_node_list_append(&parts, part); } } - if (accept1(parser, PM_TOKEN_LABEL_END) && !state_is_arg_labeled) { + if (accept1(parser, PM_TOKEN_LABEL_END)) { node = (pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous); + if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL); } else if (match1(parser, PM_TOKEN_EOF)) { pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM); node = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->current); @@ -16606,13 +16683,14 @@ parse_strings(pm_parser_t *parser, pm_node_t *current) { pm_node_t *part; while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) { - if ((part = parse_string_part(parser)) != NULL) { + if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) { pm_node_list_append(&parts, part); } } if (accept1(parser, PM_TOKEN_LABEL_END)) { node = (pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous); + if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL); } else if (match1(parser, PM_TOKEN_EOF)) { pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM); node = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->current); @@ -16666,7 +16744,7 @@ parse_strings(pm_parser_t *parser, pm_node_t *current) { #define PM_PARSE_PATTERN_MULTI 2 static pm_node_t * -parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flags, pm_diagnostic_id_t diag_id); +parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth); /** * Add the newly created local to the list of captures for this pattern matching @@ -16689,7 +16767,7 @@ parse_pattern_capture(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_c * Accept any number of constants joined by :: delimiters. */ static pm_node_t * -parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node_t *node) { +parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node_t *node, uint16_t depth) { // Now, if there are any :: operators that follow, parse them as constant // path nodes. while (accept1(parser, PM_TOKEN_COLON_COLON)) { @@ -16714,7 +16792,7 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures accept1(parser, PM_TOKEN_NEWLINE); if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) { - inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET); + inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1)); accept1(parser, PM_TOKEN_NEWLINE); expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET); } @@ -16726,7 +16804,7 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures accept1(parser, PM_TOKEN_NEWLINE); if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) { - inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN); + inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1)); accept1(parser, PM_TOKEN_NEWLINE); expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN); } @@ -16952,7 +17030,7 @@ parse_pattern_hash_key(pm_parser_t *parser, pm_static_literals_t *keys, pm_node_ * Parse a hash pattern. */ static pm_hash_pattern_node_t * -parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node_t *first_node) { +parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node_t *first_node, uint16_t depth) { pm_node_list_t assocs = { 0 }; pm_static_literals_t keys = { 0 }; pm_node_t *rest = NULL; @@ -16974,7 +17052,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node } else { // Here we have a value for the first assoc in the list, so // we will parse it now. - value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY); + value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1)); } pm_token_t operator = not_provided(parser); @@ -17021,7 +17099,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node pm_node_t *key; if (match1(parser, PM_TOKEN_STRING_BEGIN)) { - key = parse_strings(parser, NULL); + key = parse_strings(parser, NULL, true, (uint16_t) (depth + 1)); if (PM_NODE_TYPE_P(key, PM_INTERPOLATED_SYMBOL_NODE)) { pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED); @@ -17039,7 +17117,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node if (match7(parser, PM_TOKEN_COMMA, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) { value = parse_pattern_hash_implicit_value(parser, captures, (pm_symbol_node_t *) key); } else { - value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY); + value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1)); } pm_token_t operator = not_provided(parser); @@ -17064,7 +17142,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node * Parse a pattern expression primitive. */ static pm_node_t * -parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_diagnostic_id_t diag_id) { +parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_diagnostic_id_t diag_id, uint16_t depth) { switch (parser->current.type) { case PM_TOKEN_IDENTIFIER: case PM_TOKEN_METHOD_NAME: { @@ -17096,7 +17174,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm // Otherwise, we'll parse the inner pattern, then deal with it depending // on the type it returns. - pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET); + pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1)); accept1(parser, PM_TOKEN_NEWLINE); expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET); @@ -17163,7 +17241,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm first_node = parse_pattern_keyword_rest(parser, captures); break; case PM_TOKEN_STRING_BEGIN: - first_node = parse_expression(parser, PM_BINDING_POWER_MAX, false, PM_ERR_PATTERN_HASH_KEY_LABEL); + first_node = parse_expression(parser, PM_BINDING_POWER_MAX, false, true, PM_ERR_PATTERN_HASH_KEY_LABEL, (uint16_t) (depth + 1)); break; default: { PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_PATTERN_HASH_KEY, pm_token_type_human(parser->current.type)); @@ -17174,7 +17252,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm } } - node = parse_pattern_hash(parser, captures, first_node); + node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1)); accept1(parser, PM_TOKEN_NEWLINE); expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE); @@ -17199,7 +17277,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm // expression as the right side of the range. switch (parser->current.type) { case PM_CASE_PRIMITIVE: { - pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX, false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE); + pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX, false, false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1)); return (pm_node_t *) pm_range_node_create(parser, NULL, &operator, right); } default: { @@ -17210,7 +17288,10 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm } } case PM_CASE_PRIMITIVE: { - pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX, false, diag_id); + pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX, false, true, diag_id, (uint16_t) (depth + 1)); + + // If we found a label, we need to immediately return to the caller. + if (pm_symbol_node_label_p(node)) return node; // Now that we have a primitive, we need to check if it's part of a range. if (accept2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) { @@ -17221,7 +17302,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm // node. Otherwise, we'll create an endless range. switch (parser->current.type) { case PM_CASE_PRIMITIVE: { - pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX, false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE); + pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX, false, false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1)); return (pm_node_t *) pm_range_node_create(parser, node, &operator, right); } default: @@ -17286,7 +17367,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm pm_token_t lparen = parser->current; parser_lex(parser); - pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT, true, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN); + pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT, true, false, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN, (uint16_t) (depth + 1)); parser->pattern_matching_newlines = previous_pattern_matching_newlines; accept1(parser, PM_TOKEN_NEWLINE); @@ -17309,14 +17390,14 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT); pm_constant_path_node_t *node = pm_constant_path_node_create(parser, NULL, &delimiter, &parser->previous); - return parse_pattern_constant_path(parser, captures, (pm_node_t *) node); + return parse_pattern_constant_path(parser, captures, (pm_node_t *) node, (uint16_t) (depth + 1)); } case PM_TOKEN_CONSTANT: { pm_token_t constant = parser->current; parser_lex(parser); pm_node_t *node = (pm_node_t *) pm_constant_read_node_create(parser, &constant); - return parse_pattern_constant_path(parser, captures, node); + return parse_pattern_constant_path(parser, captures, node, (uint16_t) (depth + 1)); } default: pm_parser_err_current(parser, diag_id); @@ -17329,10 +17410,10 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm * assignment. */ static pm_node_t * -parse_pattern_primitives(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_diagnostic_id_t diag_id) { - pm_node_t *node = NULL; +parse_pattern_primitives(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node_t *first_node, pm_diagnostic_id_t diag_id, uint16_t depth) { + pm_node_t *node = first_node; - do { + while ((node == NULL) || accept1(parser, PM_TOKEN_PIPE)) { pm_token_t operator = parser->previous; switch (parser->current.type) { @@ -17346,9 +17427,9 @@ parse_pattern_primitives(pm_parser_t *parser, pm_constant_id_list_t *captures, p case PM_TOKEN_UDOT_DOT_DOT: case PM_CASE_PRIMITIVE: { if (node == NULL) { - node = parse_pattern_primitive(parser, captures, diag_id); + node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1)); } else { - pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE); + pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1)); node = (pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &operator); } @@ -17359,7 +17440,7 @@ parse_pattern_primitives(pm_parser_t *parser, pm_constant_id_list_t *captures, p pm_token_t opening = parser->current; parser_lex(parser); - pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN); + pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1)); accept1(parser, PM_TOKEN_NEWLINE); expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN); pm_node_t *right = (pm_node_t *) pm_parentheses_node_create(parser, &opening, body, &parser->previous); @@ -17385,7 +17466,7 @@ parse_pattern_primitives(pm_parser_t *parser, pm_constant_id_list_t *captures, p break; } } - } while (accept1(parser, PM_TOKEN_PIPE)); + } // If we have an =>, then we are assigning this pattern to a variable. // In this case we should create an assignment node. @@ -17401,7 +17482,7 @@ parse_pattern_primitives(pm_parser_t *parser, pm_constant_id_list_t *captures, p } parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->previous)); - pm_node_t *target = (pm_node_t *) pm_local_variable_target_node_create( + pm_local_variable_target_node_t *target = pm_local_variable_target_node_create( parser, &PM_LOCATION_TOKEN_VALUE(&parser->previous), constant_id, @@ -17418,7 +17499,7 @@ parse_pattern_primitives(pm_parser_t *parser, pm_constant_id_list_t *captures, p * Parse a pattern matching expression. */ static pm_node_t * -parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flags, pm_diagnostic_id_t diag_id) { +parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) { pm_node_t *node = NULL; bool leading_rest = false; @@ -17428,7 +17509,7 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag case PM_TOKEN_LABEL: { parser_lex(parser); pm_node_t *key = (pm_node_t *) pm_symbol_node_label_create(parser, &parser->previous); - node = (pm_node_t *) parse_pattern_hash(parser, captures, key); + node = (pm_node_t *) parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1)); if (!(flags & PM_PARSE_PATTERN_TOP)) { pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT); @@ -17438,7 +17519,7 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag } case PM_TOKEN_USTAR_STAR: { node = parse_pattern_keyword_rest(parser, captures); - node = (pm_node_t *) parse_pattern_hash(parser, captures, node); + node = (pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)); if (!(flags & PM_PARSE_PATTERN_TOP)) { pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT); @@ -17446,6 +17527,24 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag return node; } + case PM_TOKEN_STRING_BEGIN: { + // We need special handling for string beginnings because they could + // be dynamic symbols leading to hash patterns. + node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1)); + + if (pm_symbol_node_label_p(node)) { + node = (pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)); + + if (!(flags & PM_PARSE_PATTERN_TOP)) { + pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT); + } + + return node; + } + + node = parse_pattern_primitives(parser, captures, node, diag_id, (uint16_t) (depth + 1)); + break; + } case PM_TOKEN_USTAR: { if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) { parser_lex(parser); @@ -17456,14 +17555,14 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag } /* fallthrough */ default: - node = parse_pattern_primitives(parser, captures, diag_id); + node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1)); break; } // If we got a dynamic label symbol, then we need to treat it like the // beginning of a hash pattern. if (pm_symbol_node_label_p(node)) { - return (pm_node_t *) parse_pattern_hash(parser, captures, node); + return (pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)); } if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser, PM_TOKEN_COMMA)) { @@ -17476,7 +17575,7 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag // Gather up all of the patterns into the list. while (accept1(parser, PM_TOKEN_COMMA)) { // Break early here in case we have a trailing comma. - if (match6(parser, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_EOF)) { + if (match4(parser, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_SEMICOLON)) { node = (pm_node_t *) pm_implicit_rest_node_create(parser, &parser->previous); pm_node_list_append(&nodes, node); break; @@ -17494,7 +17593,7 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag trailing_rest = true; } else { - node = parse_pattern_primitives(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA); + node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1)); } pm_node_list_append(&nodes, node); @@ -17586,7 +17685,8 @@ pm_parser_err_prefix(pm_parser_t *parser, pm_diagnostic_id_t diag_id) { PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, diag_id, human, parser->previous.start[0]); break; } - case PM_ERR_UNARY_DISALLOWED: { + case PM_ERR_UNARY_DISALLOWED: + case PM_ERR_EXPECT_ARGUMENT: { PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, diag_id, pm_token_type_human(parser->current.type)); break; } @@ -17601,7 +17701,12 @@ pm_parser_err_prefix(pm_parser_t *parser, pm_diagnostic_id_t diag_id) { */ static void parse_retry(pm_parser_t *parser, const pm_node_t *node) { +#define CONTEXT_NONE 0 +#define CONTEXT_THROUGH_ENSURE 1 +#define CONTEXT_THROUGH_ELSE 2 + pm_context_node_t *context_node = parser->current_context; + int context = CONTEXT_NONE; while (context_node != NULL) { switch (context_node->context) { @@ -17625,7 +17730,13 @@ parse_retry(pm_parser_t *parser, const pm_node_t *node) { case PM_CONTEXT_SCLASS: // These are the bad cases. We're not allowed to have a retry in // these contexts. - pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_WITHOUT_RESCUE); + if (context == CONTEXT_NONE) { + pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_WITHOUT_RESCUE); + } else if (context == CONTEXT_THROUGH_ENSURE) { + pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ENSURE); + } else if (context == CONTEXT_THROUGH_ELSE) { + pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ELSE); + } return; case PM_CONTEXT_BEGIN_ELSE: case PM_CONTEXT_BLOCK_ELSE: @@ -17636,8 +17747,8 @@ parse_retry(pm_parser_t *parser, const pm_node_t *node) { case PM_CONTEXT_SCLASS_ELSE: // These are also bad cases, but with a more specific error // message indicating the else. - pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ELSE); - return; + context = CONTEXT_THROUGH_ELSE; + break; case PM_CONTEXT_BEGIN_ENSURE: case PM_CONTEXT_BLOCK_ENSURE: case PM_CONTEXT_CLASS_ENSURE: @@ -17647,8 +17758,8 @@ parse_retry(pm_parser_t *parser, const pm_node_t *node) { case PM_CONTEXT_SCLASS_ENSURE: // These are also bad cases, but with a more specific error // message indicating the ensure. - pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ENSURE); - return; + context = CONTEXT_THROUGH_ENSURE; + break; case PM_CONTEXT_NONE: // This case should never happen. assert(false && "unreachable"); @@ -17682,6 +17793,10 @@ parse_retry(pm_parser_t *parser, const pm_node_t *node) { context_node = context_node->prev; } + +#undef CONTEXT_NONE +#undef CONTEXT_ENSURE +#undef CONTEXT_ELSE } /** @@ -17826,7 +17941,7 @@ parse_regular_expression_errors(pm_parser_t *parser, pm_regular_expression_node_ * Parse an expression that begins with the previous node that we just lexed. */ static inline pm_node_t * -parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id) { +parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call, bool accepts_label, pm_diagnostic_id_t diag_id, uint16_t depth) { switch (parser->current.type) { case PM_TOKEN_BRACKET_LEFT_ARRAY: { parser_lex(parser); @@ -17865,7 +17980,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b if (match3(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_EOF)) { pm_parser_scope_forwarding_positionals_check(parser, &operator); } else { - expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR); + expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1)); } element = (pm_node_t *) pm_splat_node_create(parser, &operator, expression); @@ -17878,13 +17993,13 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_static_literals_t hash_keys = { 0 }; if (!match8(parser, PM_TOKEN_EOF, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_EOF, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_KEYWORD_DO, PM_TOKEN_PARENTHESIS_RIGHT)) { - parse_assocs(parser, &hash_keys, element); + parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1)); } pm_static_literals_free(&hash_keys); parsed_bare_hash = true; } else { - element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_ARRAY_EXPRESSION); + element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, true, PM_ERR_ARRAY_EXPRESSION, (uint16_t) (depth + 1)); if (pm_symbol_node_label_p(element) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) { if (parsed_bare_hash) { @@ -17902,13 +18017,13 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b operator = not_provided(parser); } - pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_HASH_VALUE); + pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1)); pm_node_t *assoc = (pm_node_t *) pm_assoc_node_create(parser, element, &operator, value); pm_keyword_hash_node_elements_append(hash, assoc); element = (pm_node_t *) hash; if (accept1(parser, PM_TOKEN_COMMA) && !match1(parser, PM_TOKEN_BRACKET_RIGHT)) { - parse_assocs(parser, &hash_keys, element); + parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1)); } pm_static_literals_free(&hash_keys); @@ -17921,7 +18036,13 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } accept1(parser, PM_TOKEN_NEWLINE); - expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_ARRAY_TERM); + + if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) { + PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_ARRAY_TERM, pm_token_type_human(parser->current.type)); + parser->previous.start = parser->previous.end; + parser->previous.type = PM_TOKEN_MISSING; + } + pm_array_node_close_set(array, &parser->previous); pm_accepts_block_stack_pop(parser); @@ -17952,7 +18073,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b // of statements within the parentheses. pm_accepts_block_stack_push(parser, true); context_push(parser, PM_CONTEXT_PARENS); - pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT, true, PM_ERR_CANNOT_PARSE_EXPRESSION); + pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT, true, false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1)); context_pop(parser); // Determine if this statement is followed by a terminator. In the @@ -18000,7 +18121,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b if (match1(parser, PM_TOKEN_COMMA)) { if (binding_power == PM_BINDING_POWER_STATEMENT) { - return parse_targets_validate(parser, (pm_node_t *) multi_target, PM_BINDING_POWER_INDEX); + return parse_targets_validate(parser, (pm_node_t *) multi_target, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1)); } return (pm_node_t *) multi_target; } @@ -18032,7 +18153,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b // Parse each statement within the parentheses. while (true) { - pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, true, PM_ERR_CANNOT_PARSE_EXPRESSION); + pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, true, false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1)); pm_statements_node_body_append(parser, statements, node, true); // If we're recovering from a syntax error, then we need to stop @@ -18090,10 +18211,10 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b if (!match2(parser, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_EOF)) { if (current_hash_keys != NULL) { - parse_assocs(parser, current_hash_keys, (pm_node_t *) node); + parse_assocs(parser, current_hash_keys, (pm_node_t *) node, (uint16_t) (depth + 1)); } else { pm_static_literals_t hash_keys = { 0 }; - parse_assocs(parser, &hash_keys, (pm_node_t *) node); + parse_assocs(parser, &hash_keys, (pm_node_t *) node, (uint16_t) (depth + 1)); pm_static_literals_free(&hash_keys); } @@ -18124,7 +18245,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b // Characters can be followed by strings in which case they are // automatically concatenated. if (match1(parser, PM_TOKEN_STRING_BEGIN)) { - return parse_strings(parser, node); + return parse_strings(parser, node, false, (uint16_t) (depth + 1)); } return node; @@ -18134,7 +18255,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_node_t *node = (pm_node_t *) pm_class_variable_read_node_create(parser, &parser->previous); if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) { - node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX); + node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1)); } return node; @@ -18152,7 +18273,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b match1(parser, PM_TOKEN_BRACE_LEFT) ) { pm_arguments_t arguments = { 0 }; - parse_arguments_list(parser, &arguments, true, accepts_command_call); + parse_arguments_list(parser, &arguments, true, accepts_command_call, (uint16_t) (depth + 1)); return (pm_node_t *) pm_call_node_fcall_create(parser, &constant, &arguments); } @@ -18161,7 +18282,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_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_validate(parser, node, PM_BINDING_POWER_INDEX); + node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1)); } return node; @@ -18174,7 +18295,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_node_t *node = (pm_node_t *) pm_constant_path_node_create(parser, NULL, &delimiter, &parser->previous); if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) { - node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX); + node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1)); } return node; @@ -18184,7 +18305,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_token_t operator = parser->current; parser_lex(parser); - pm_node_t *right = parse_expression(parser, pm_binding_powers[operator.type].left, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *right = parse_expression(parser, pm_binding_powers[operator.type].left, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1)); // Unary .. and ... are special because these are non-associative // operators that can also be unary operators. In this case we need @@ -18213,7 +18334,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_node_t *node = (pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->previous); if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) { - node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX); + node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1)); } return node; @@ -18223,7 +18344,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_node_t *node = (pm_node_t *) pm_global_variable_read_node_create(parser, &parser->previous); if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) { - node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX); + node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1)); } return node; @@ -18233,7 +18354,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_node_t *node = (pm_node_t *) pm_back_reference_read_node_create(parser, &parser->previous); if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) { - node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX); + node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1)); } return node; @@ -18252,7 +18373,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_call_node_t *call = (pm_call_node_t *) node; pm_arguments_t arguments = { 0 }; - if (parse_arguments_list(parser, &arguments, true, accepts_command_call)) { + if (parse_arguments_list(parser, &arguments, true, accepts_command_call, (uint16_t) (depth + 1))) { // Since we found arguments, we need to turn off the // variable call bit in the flags. pm_node_flag_unset((pm_node_t *)call, PM_CALL_NODE_FLAGS_VARIABLE_CALL); @@ -18284,7 +18405,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b match1(parser, PM_TOKEN_BRACE_LEFT) ) { pm_arguments_t arguments = { 0 }; - parse_arguments_list(parser, &arguments, true, accepts_command_call); + parse_arguments_list(parser, &arguments, true, accepts_command_call, (uint16_t) (depth + 1)); pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments); if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) { @@ -18313,7 +18434,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) { - node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX); + node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1)); } return node; @@ -18345,7 +18466,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } node->location.end = opening.end; - } else if ((part = parse_string_part(parser)) == NULL) { + } else if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) == 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. @@ -18385,7 +18506,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_node_list_append(&parts, part); while (!match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) { - if ((part = parse_string_part(parser)) != NULL) { + if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) { pm_node_list_append(&parts, part); } } @@ -18429,7 +18550,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } if (match1(parser, PM_TOKEN_STRING_BEGIN)) { - return parse_strings(parser, node); + return parse_strings(parser, node, false, (uint16_t) (depth + 1)); } return node; @@ -18439,7 +18560,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_node_t *node = (pm_node_t *) pm_instance_variable_read_node_create(parser, &parser->previous); if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) { - node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX); + node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1)); } return node; @@ -18481,8 +18602,8 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b parser_lex(parser); pm_token_t keyword = parser->previous; - pm_node_t *new_name = parse_alias_argument(parser, true); - pm_node_t *old_name = parse_alias_argument(parser, false); + pm_node_t *new_name = parse_alias_argument(parser, true, (uint16_t) (depth + 1)); + pm_node_t *old_name = parse_alias_argument(parser, false, (uint16_t) (depth + 1)); switch (PM_NODE_TYPE(new_name)) { case PM_BACK_REFERENCE_READ_NODE: @@ -18527,12 +18648,12 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } else if (!token_begins_expression_p(parser->current.type)) { predicate = NULL; } else { - predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, PM_ERR_CASE_EXPRESSION_AFTER_CASE); + predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_CASE_EXPRESSION_AFTER_CASE, (uint16_t) (depth + 1)); while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)); } if (match1(parser, PM_TOKEN_KEYWORD_END)) { - parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword, false); + parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword, false, false); parser_lex(parser); pop_block_exits(parser, previous_block_exits); @@ -18555,7 +18676,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b // case-when node. We will continue to parse the when nodes // until we hit the end of the list. while (match1(parser, PM_TOKEN_KEYWORD_WHEN)) { - parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword, false); + parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword, false, true); parser_lex(parser); pm_token_t when_keyword = parser->previous; @@ -18564,14 +18685,14 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b do { if (accept1(parser, PM_TOKEN_USTAR)) { pm_token_t operator = parser->previous; - pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR); + pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1)); pm_splat_node_t *splat_node = pm_splat_node_create(parser, &operator, expression); pm_when_node_conditions_append(when_node, (pm_node_t *) splat_node); if (PM_NODE_TYPE_P(expression, PM_MISSING_NODE)) break; } else { - pm_node_t *condition = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_CASE_EXPRESSION_AFTER_WHEN); + pm_node_t *condition = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_CASE_EXPRESSION_AFTER_WHEN, (uint16_t) (depth + 1)); pm_when_node_conditions_append(when_node, condition); // If we found a missing node, then this is a syntax @@ -18600,7 +18721,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } if (!match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) { - pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_CASE_WHEN); + pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_CASE_WHEN, (uint16_t) (depth + 1)); if (statements != NULL) { pm_when_node_statements_set(when_node, statements); } @@ -18630,7 +18751,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b // will continue to parse the in nodes until we hit the end of // the list. while (match1(parser, PM_TOKEN_KEYWORD_IN)) { - parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword, false); + parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword, false, true); bool previous_pattern_matching_newlines = parser->pattern_matching_newlines; parser->pattern_matching_newlines = true; @@ -18642,7 +18763,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_token_t in_keyword = parser->previous; pm_constant_id_list_t captures = { 0 }; - pm_node_t *pattern = parse_pattern(parser, &captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_IN); + pm_node_t *pattern = parse_pattern(parser, &captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_IN, (uint16_t) (depth + 1)); parser->pattern_matching_newlines = previous_pattern_matching_newlines; pm_constant_id_list_free(&captures); @@ -18652,11 +18773,11 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b // `unless` statements. if (accept1(parser, PM_TOKEN_KEYWORD_IF_MODIFIER)) { pm_token_t keyword = parser->previous; - pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, PM_ERR_CONDITIONAL_IF_PREDICATE); + pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1)); pattern = (pm_node_t *) pm_if_node_modifier_create(parser, pattern, &keyword, predicate); } else if (accept1(parser, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) { pm_token_t keyword = parser->previous; - pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, PM_ERR_CONDITIONAL_UNLESS_PREDICATE); + pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1)); pattern = (pm_node_t *) pm_unless_node_modifier_create(parser, pattern, &keyword, predicate); } @@ -18681,7 +18802,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b if (match3(parser, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) { statements = NULL; } else { - statements = parse_statements(parser, PM_CONTEXT_CASE_IN); + statements = parse_statements(parser, PM_CONTEXT_CASE_IN, (uint16_t) (depth + 1)); } // Now that we have the full pattern and statements, we can @@ -18705,7 +18826,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_else_node_t *else_node; if (!match1(parser, PM_TOKEN_KEYWORD_END)) { - else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser, PM_CONTEXT_ELSE), &parser->current); + else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser, PM_CONTEXT_ELSE, (uint16_t) (depth + 1)), &parser->current); } else { else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->current); } @@ -18717,7 +18838,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } } - parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword, false); + parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword, false, false); expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM); if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) { @@ -18744,13 +18865,13 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) { pm_accepts_block_stack_push(parser, true); - begin_statements = parse_statements(parser, PM_CONTEXT_BEGIN); + begin_statements = parse_statements(parser, PM_CONTEXT_BEGIN, (uint16_t) (depth + 1)); pm_accepts_block_stack_pop(parser); accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON); } pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements); - parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN); + parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1)); expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM); begin_node->base.location.end = parser->previous.end; @@ -18774,7 +18895,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_BEGIN_UPCASE_BRACE); pm_token_t opening = parser->previous; - pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_PREEXE); + pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_PREEXE, (uint16_t) (depth + 1)); expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM); pm_context_t context = parser->current_context->context; @@ -18802,19 +18923,19 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_binding_power_t binding_power = pm_binding_powers[parser->current.type].left; if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) { - parse_arguments(parser, &arguments, false, PM_TOKEN_EOF); + parse_arguments(parser, &arguments, false, PM_TOKEN_EOF, (uint16_t) (depth + 1)); } } switch (keyword.type) { case PM_TOKEN_KEYWORD_BREAK: { pm_node_t *node = (pm_node_t *) pm_break_node_create(parser, &keyword, arguments.arguments); - if (!parser->parsing_eval) parse_block_exit(parser, node); + if (!parser->partial_script) parse_block_exit(parser, node); return node; } case PM_TOKEN_KEYWORD_NEXT: { pm_node_t *node = (pm_node_t *) pm_next_node_create(parser, &keyword, arguments.arguments); - if (!parser->parsing_eval) parse_block_exit(parser, node); + if (!parser->partial_script) parse_block_exit(parser, node); return node; } case PM_TOKEN_KEYWORD_RETURN: { @@ -18832,7 +18953,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_token_t keyword = parser->previous; pm_arguments_t arguments = { 0 }; - parse_arguments_list(parser, &arguments, true, accepts_command_call); + parse_arguments_list(parser, &arguments, true, accepts_command_call, (uint16_t) (depth + 1)); if ( arguments.opening_loc.start == NULL && @@ -18849,7 +18970,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_token_t keyword = parser->previous; pm_arguments_t arguments = { 0 }; - parse_arguments_list(parser, &arguments, false, accepts_command_call); + parse_arguments_list(parser, &arguments, false, accepts_command_call, (uint16_t) (depth + 1)); // It's possible that we've parsed a block argument through our // call to parse_arguments_list. If we found one, we should mark it @@ -18862,7 +18983,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } pm_node_t *node = (pm_node_t *) pm_yield_node_create(parser, &keyword, &arguments.opening_loc, arguments.arguments, &arguments.closing_loc); - if (!parser->parsing_eval) parse_yield(parser, node); + if (!parser->parsing_eval && !parser->partial_script) parse_yield(parser, node); return node; } @@ -18878,23 +18999,25 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b if (accept1(parser, PM_TOKEN_LESS_LESS)) { pm_token_t operator = parser->previous; - pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, PM_ERR_EXPECT_EXPRESSION_AFTER_LESS_LESS); + pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_EXPECT_EXPRESSION_AFTER_LESS_LESS, (uint16_t) (depth + 1)); pm_parser_scope_push(parser, true); - accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON); + if (!match2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) { + PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_EXPECT_SINGLETON_CLASS_DELIMITER, pm_token_type_human(parser->current.type)); + } pm_node_t *statements = NULL; if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) { pm_accepts_block_stack_push(parser, true); - statements = (pm_node_t *) parse_statements(parser, PM_CONTEXT_SCLASS); + statements = (pm_node_t *) parse_statements(parser, PM_CONTEXT_SCLASS, (uint16_t) (depth + 1)); pm_accepts_block_stack_pop(parser); } if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) { assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE)); - statements = (pm_node_t *) parse_rescues_implicit_begin(parser, opening_newline_index, &class_keyword, class_keyword.start, (pm_statements_node_t *) statements, PM_RESCUES_SCLASS); + statements = (pm_node_t *) parse_rescues_implicit_begin(parser, opening_newline_index, &class_keyword, class_keyword.start, (pm_statements_node_t *) statements, PM_RESCUES_SCLASS, (uint16_t) (depth + 1)); } else { - parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword, false); + parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword, false, false); } expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM); @@ -18911,7 +19034,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b return (pm_node_t *) pm_singleton_class_node_create(parser, &locals, &class_keyword, &operator, expression, statements, &parser->previous); } - pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX, false, PM_ERR_CLASS_NAME); + pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX, false, false, PM_ERR_CLASS_NAME, (uint16_t) (depth + 1)); pm_token_t name = parser->previous; if (name.type != PM_TOKEN_CONSTANT) { pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME); @@ -18927,7 +19050,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b parser->command_start = true; parser_lex(parser); - superclass = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, PM_ERR_CLASS_SUPERCLASS); + superclass = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_CLASS_SUPERCLASS, (uint16_t) (depth + 1)); } else { inheritance_operator = not_provided(parser); superclass = NULL; @@ -18944,15 +19067,15 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) { pm_accepts_block_stack_push(parser, true); - statements = (pm_node_t *) parse_statements(parser, PM_CONTEXT_CLASS); + statements = (pm_node_t *) parse_statements(parser, PM_CONTEXT_CLASS, (uint16_t) (depth + 1)); pm_accepts_block_stack_pop(parser); } if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) { assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE)); - statements = (pm_node_t *) parse_rescues_implicit_begin(parser, opening_newline_index, &class_keyword, class_keyword.start, (pm_statements_node_t *) statements, PM_RESCUES_CLASS); + statements = (pm_node_t *) parse_rescues_implicit_begin(parser, opening_newline_index, &class_keyword, class_keyword.start, (pm_statements_node_t *) statements, PM_RESCUES_CLASS, (uint16_t) (depth + 1)); } else { - parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword, false); + parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword, false, false); } expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM); @@ -19096,7 +19219,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b parser_lex(parser); pm_token_t lparen = parser->previous; - pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT, true, PM_ERR_DEF_RECEIVER); + pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_DEF_RECEIVER, (uint16_t) (depth + 1)); accept1(parser, PM_TOKEN_NEWLINE); expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN); @@ -19133,12 +19256,13 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) { params = NULL; } else { - params = parse_parameters(parser, PM_BINDING_POWER_DEFINED, true, false, true); + params = parse_parameters(parser, PM_BINDING_POWER_DEFINED, true, false, true, true, (uint16_t) (depth + 1)); } lex_state_set(parser, PM_LEX_STATE_BEG); parser->command_start = true; + context_pop(parser); if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) { PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_DEF_PARAMS_TERM_PAREN, pm_token_type_human(parser->current.type)); parser->previous.start = parser->previous.end; @@ -19157,18 +19281,21 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b lparen = not_provided(parser); rparen = not_provided(parser); - params = parse_parameters(parser, PM_BINDING_POWER_DEFINED, false, false, true); + params = parse_parameters(parser, PM_BINDING_POWER_DEFINED, false, false, true, true, (uint16_t) (depth + 1)); + + context_pop(parser); break; } default: { lparen = not_provided(parser); rparen = not_provided(parser); params = NULL; + + context_pop(parser); break; } } - context_pop(parser); pm_node_t *statements = NULL; pm_token_t equal; pm_token_t end_keyword; @@ -19183,13 +19310,13 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_do_loop_stack_push(parser, false); statements = (pm_node_t *) pm_statements_node_create(parser); - pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_DEFINED + 1, binding_power < PM_BINDING_POWER_COMPOSITION, PM_ERR_DEF_ENDLESS); + pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_DEFINED + 1, binding_power < PM_BINDING_POWER_COMPOSITION, false, PM_ERR_DEF_ENDLESS, (uint16_t) (depth + 1)); if (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) { context_push(parser, PM_CONTEXT_RESCUE_MODIFIER); pm_token_t rescue_keyword = parser->previous; - pm_node_t *value = parse_expression(parser, binding_power, false, PM_ERR_RESCUE_MODIFIER_VALUE); + pm_node_t *value = parse_expression(parser, binding_power, false, false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1)); context_pop(parser); statement = (pm_node_t *) pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value); @@ -19215,15 +19342,15 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) { pm_accepts_block_stack_push(parser, true); - statements = (pm_node_t *) parse_statements(parser, PM_CONTEXT_DEF); + statements = (pm_node_t *) parse_statements(parser, PM_CONTEXT_DEF, (uint16_t) (depth + 1)); pm_accepts_block_stack_pop(parser); } if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) { assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE)); - statements = (pm_node_t *) parse_rescues_implicit_begin(parser, opening_newline_index, &def_keyword, def_keyword.start, (pm_statements_node_t *) statements, PM_RESCUES_DEF); + statements = (pm_node_t *) parse_rescues_implicit_begin(parser, opening_newline_index, &def_keyword, def_keyword.start, (pm_statements_node_t *) statements, PM_RESCUES_DEF, (uint16_t) (depth + 1)); } else { - parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword, false); + parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword, false, false); } pm_accepts_block_stack_pop(parser); @@ -19274,7 +19401,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) { lparen = parser->previous; - expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, true, PM_ERR_DEFINED_EXPRESSION); + expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1)); if (parser->recovering) { rparen = not_provided(parser); @@ -19286,7 +19413,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } else { lparen = not_provided(parser); rparen = not_provided(parser); - expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_DEFINED_EXPRESSION); + expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1)); } context_pop(parser); @@ -19312,7 +19439,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_END_UPCASE_BRACE); pm_token_t opening = parser->previous; - pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_POSTEXE); + pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_POSTEXE, (uint16_t) (depth + 1)); expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM); return (pm_node_t *) pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->previous); @@ -19335,12 +19462,12 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_node_t *name = NULL; if (token_begins_expression_p(parser->current.type)) { - name = parse_expression(parser, PM_BINDING_POWER_INDEX, false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR); + name = parse_expression(parser, PM_BINDING_POWER_INDEX, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1)); } index = (pm_node_t *) pm_splat_node_create(parser, &star_operator, name); } else if (token_begins_expression_p(parser->current.type)) { - index = parse_expression(parser, PM_BINDING_POWER_INDEX, false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA); + index = parse_expression(parser, PM_BINDING_POWER_INDEX, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1)); } else { pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX); index = (pm_node_t *) pm_missing_node_create(parser, for_keyword.start, for_keyword.end); @@ -19348,7 +19475,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b // Now, if there are multiple index expressions, parse them out. if (match1(parser, PM_TOKEN_COMMA)) { - index = parse_targets(parser, index, PM_BINDING_POWER_INDEX); + index = parse_targets(parser, index, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1)); } else { index = parse_target(parser, index, false, false); } @@ -19359,7 +19486,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b expect1(parser, PM_TOKEN_KEYWORD_IN, PM_ERR_FOR_IN); pm_token_t in_keyword = parser->previous; - pm_node_t *collection = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, PM_ERR_FOR_COLLECTION); + pm_node_t *collection = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_FOR_COLLECTION, (uint16_t) (depth + 1)); pm_do_loop_stack_pop(parser); pm_token_t do_keyword; @@ -19367,16 +19494,17 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b do_keyword = parser->previous; } else { do_keyword = not_provided(parser); + if (!match2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE)) { + PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_EXPECT_FOR_DELIMITER, pm_token_type_human(parser->current.type)); + } } - accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE); - pm_statements_node_t *statements = NULL; if (!match1(parser, PM_TOKEN_KEYWORD_END)) { - statements = parse_statements(parser, PM_CONTEXT_FOR); + statements = parse_statements(parser, PM_CONTEXT_FOR, (uint16_t) (depth + 1)); } - parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword, false); + parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword, false, false); expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM); return (pm_node_t *) pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, &do_keyword, &parser->previous); @@ -19390,7 +19518,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b bool if_after_else = parser->previous.type == PM_TOKEN_KEYWORD_ELSE; parser_lex(parser); - return parse_conditional(parser, PM_CONTEXT_IF, opening_newline_index, if_after_else); + return parse_conditional(parser, PM_CONTEXT_IF, opening_newline_index, if_after_else, (uint16_t) (depth + 1)); case PM_TOKEN_KEYWORD_UNDEF: { if (binding_power != PM_BINDING_POWER_STATEMENT) { pm_parser_err_current(parser, PM_ERR_STATEMENT_UNDEF); @@ -19398,7 +19526,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b parser_lex(parser); pm_undef_node_t *undef = pm_undef_node_create(parser, &parser->previous); - pm_node_t *name = parse_undef_argument(parser); + pm_node_t *name = parse_undef_argument(parser, (uint16_t) (depth + 1)); if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) { pm_node_destroy(parser, name); @@ -19408,7 +19536,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b while (match1(parser, PM_TOKEN_COMMA)) { lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM); parser_lex(parser); - name = parse_undef_argument(parser); + name = parse_undef_argument(parser, (uint16_t) (depth + 1)); if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) { pm_node_destroy(parser, name); @@ -19436,7 +19564,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) { arguments.closing_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous); } else { - receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, true, PM_ERR_NOT_EXPRESSION); + receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1)); if (!parser->recovering) { accept1(parser, PM_TOKEN_NEWLINE); @@ -19445,7 +19573,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b } } } else { - receiver = parse_expression(parser, PM_BINDING_POWER_NOT, true, PM_ERR_NOT_EXPRESSION); + receiver = parse_expression(parser, PM_BINDING_POWER_NOT, true, false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1)); } return (pm_node_t *) pm_call_node_not_create(parser, receiver, &message, &arguments); @@ -19454,7 +19582,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b size_t opening_newline_index = token_newline_index(parser); parser_lex(parser); - return parse_conditional(parser, PM_CONTEXT_UNLESS, opening_newline_index, false); + return parse_conditional(parser, PM_CONTEXT_UNLESS, opening_newline_index, false, (uint16_t) (depth + 1)); } case PM_TOKEN_KEYWORD_MODULE: { pm_node_list_t current_block_exits = { 0 }; @@ -19464,7 +19592,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b parser_lex(parser); pm_token_t module_keyword = parser->previous; - pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX, false, PM_ERR_MODULE_NAME); + pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX, false, false, PM_ERR_MODULE_NAME, (uint16_t) (depth + 1)); pm_token_t name; // If we can recover from a syntax error that occurred while parsing @@ -19498,15 +19626,15 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) { pm_accepts_block_stack_push(parser, true); - statements = (pm_node_t *) parse_statements(parser, PM_CONTEXT_MODULE); + statements = (pm_node_t *) parse_statements(parser, PM_CONTEXT_MODULE, (uint16_t) (depth + 1)); pm_accepts_block_stack_pop(parser); } if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) { assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE)); - statements = (pm_node_t *) parse_rescues_implicit_begin(parser, opening_newline_index, &module_keyword, module_keyword.start, (pm_statements_node_t *) statements, PM_RESCUES_MODULE); + statements = (pm_node_t *) parse_rescues_implicit_begin(parser, opening_newline_index, &module_keyword, module_keyword.start, (pm_statements_node_t *) statements, PM_RESCUES_MODULE, (uint16_t) (depth + 1)); } else { - parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword, false); + parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword, false, false); } pm_constant_id_list_t locals; @@ -19531,7 +19659,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b parser_lex(parser); pm_node_t *node = (pm_node_t *) pm_redo_node_create(parser, &parser->previous); - if (!parser->parsing_eval) parse_block_exit(parser, node); + if (!parser->partial_script) parse_block_exit(parser, node); return node; } @@ -19557,7 +19685,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b parser_lex(parser); pm_token_t keyword = parser->previous; - pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, PM_ERR_CONDITIONAL_UNTIL_PREDICATE); + pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1)); pm_do_loop_stack_pop(parser); context_pop(parser); @@ -19567,12 +19695,12 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b if (!match1(parser, PM_TOKEN_KEYWORD_END)) { pm_accepts_block_stack_push(parser, true); - statements = parse_statements(parser, PM_CONTEXT_UNTIL); + statements = parse_statements(parser, PM_CONTEXT_UNTIL, (uint16_t) (depth + 1)); pm_accepts_block_stack_pop(parser); accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON); } - parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, false); + parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, false, false); expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM); return (pm_node_t *) pm_until_node_create(parser, &keyword, &parser->previous, predicate, statements, 0); @@ -19585,7 +19713,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b parser_lex(parser); pm_token_t keyword = parser->previous; - pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, PM_ERR_CONDITIONAL_WHILE_PREDICATE); + pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1)); pm_do_loop_stack_pop(parser); context_pop(parser); @@ -19595,12 +19723,12 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b if (!match1(parser, PM_TOKEN_KEYWORD_END)) { pm_accepts_block_stack_push(parser, true); - statements = parse_statements(parser, PM_CONTEXT_WHILE); + statements = parse_statements(parser, PM_CONTEXT_WHILE, (uint16_t) (depth + 1)); pm_accepts_block_stack_pop(parser); accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON); } - parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, false); + parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, false, false); expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM); return (pm_node_t *) pm_while_node_create(parser, &keyword, &parser->previous, predicate, statements, 0); @@ -19728,7 +19856,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b // interpolated string, then we'll just add the embedded variable. } - pm_node_t *part = parse_string_part(parser); + pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1)); pm_interpolated_symbol_node_append((pm_interpolated_symbol_node_t *) current, part); if (!start_location_set) { current->location.start = part->location.start; @@ -19765,7 +19893,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b assert(false && "unreachable"); } - pm_node_t *part = parse_string_part(parser); + pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1)); pm_interpolated_symbol_node_append((pm_interpolated_symbol_node_t *) current, part); if (!start_location_set) { current->location.start = part->location.start; @@ -19918,7 +20046,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b // add the embedded variable. } - pm_node_t *part = parse_string_part(parser); + pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1)); pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current, part); break; } @@ -19949,7 +20077,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b assert(false && "unreachable"); } - pm_node_t *part = parse_string_part(parser); + pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1)); pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current, part); break; } @@ -20055,7 +20183,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b // parts into the list. pm_node_t *part; while (!match2(parser, PM_TOKEN_REGEXP_END, PM_TOKEN_EOF)) { - if ((part = parse_string_part(parser)) != NULL) { + if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) { pm_interpolated_regular_expression_node_append(interpolated, part); } } @@ -20132,7 +20260,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_node_t *part; while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) { - if ((part = parse_string_part(parser)) != NULL) { + if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) { pm_interpolated_xstring_node_append(node, part); } } @@ -20163,13 +20291,13 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b pm_node_t *name = NULL; if (token_begins_expression_p(parser->current.type)) { - name = parse_expression(parser, PM_BINDING_POWER_INDEX, false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR); + name = parse_expression(parser, PM_BINDING_POWER_INDEX, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1)); } pm_node_t *splat = (pm_node_t *) pm_splat_node_create(parser, &operator, name); if (match1(parser, PM_TOKEN_COMMA)) { - return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX); + return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1)); } else { return parse_target_validate(parser, splat, true); } @@ -20182,7 +20310,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b parser_lex(parser); pm_token_t operator = parser->previous; - pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, binding_power < PM_BINDING_POWER_MATCH, PM_ERR_UNARY_RECEIVER); + pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, binding_power < PM_BINDING_POWER_MATCH, false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1)); pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "!"); pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT); @@ -20195,7 +20323,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b parser_lex(parser); pm_token_t operator = parser->previous; - pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, PM_ERR_UNARY_RECEIVER); + pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1)); pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "~"); return (pm_node_t *) node; @@ -20207,7 +20335,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b parser_lex(parser); pm_token_t operator = parser->previous; - pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, PM_ERR_UNARY_RECEIVER); + pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1)); pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "-@"); return (pm_node_t *) node; @@ -20216,11 +20344,11 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b parser_lex(parser); pm_token_t operator = parser->previous; - pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, PM_ERR_UNARY_RECEIVER); + pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1)); if (accept1(parser, PM_TOKEN_STAR_STAR)) { pm_token_t exponent_operator = parser->previous; - pm_node_t *exponent = parse_expression(parser, pm_binding_powers[exponent_operator.type].right, false, PM_ERR_EXPECT_ARGUMENT); + pm_node_t *exponent = parse_expression(parser, pm_binding_powers[exponent_operator.type].right, false, false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1)); node = (pm_node_t *) pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0); node = (pm_node_t *) pm_call_node_unary_create(parser, &operator, node, "-@"); } else { @@ -20260,7 +20388,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) { block_parameters = pm_block_parameters_node_create(parser, NULL, &opening); } else { - block_parameters = parse_block_parameters(parser, false, &opening, true); + block_parameters = parse_block_parameters(parser, false, &opening, true, true, (uint16_t) (depth + 1)); } accept1(parser, PM_TOKEN_NEWLINE); @@ -20272,7 +20400,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b case PM_CASE_PARAMETER: { pm_accepts_block_stack_push(parser, false); pm_token_t opening = not_provided(parser); - block_parameters = parse_block_parameters(parser, false, &opening, true); + block_parameters = parse_block_parameters(parser, false, &opening, true, false, (uint16_t) (depth + 1)); pm_accepts_block_stack_pop(parser); break; } @@ -20290,10 +20418,10 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b opening = parser->previous; if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) { - body = (pm_node_t *) parse_statements(parser, PM_CONTEXT_LAMBDA_BRACES); + body = (pm_node_t *) parse_statements(parser, PM_CONTEXT_LAMBDA_BRACES, (uint16_t) (depth + 1)); } - parser_warn_indentation_mismatch(parser, opening_newline_index, &operator, false); + parser_warn_indentation_mismatch(parser, opening_newline_index, &operator, false, false); expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE); } else { expect1(parser, PM_TOKEN_KEYWORD_DO, PM_ERR_LAMBDA_OPEN); @@ -20301,15 +20429,15 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b if (!match3(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) { pm_accepts_block_stack_push(parser, true); - body = (pm_node_t *) parse_statements(parser, PM_CONTEXT_LAMBDA_DO_END); + body = (pm_node_t *) parse_statements(parser, PM_CONTEXT_LAMBDA_DO_END, (uint16_t) (depth + 1)); pm_accepts_block_stack_pop(parser); } if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) { assert(body == NULL || PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE)); - body = (pm_node_t *) parse_rescues_implicit_begin(parser, opening_newline_index, &operator, opening.start, (pm_statements_node_t *) body, PM_RESCUES_LAMBDA); + body = (pm_node_t *) parse_rescues_implicit_begin(parser, opening_newline_index, &operator, opening.start, (pm_statements_node_t *) body, PM_RESCUES_LAMBDA, (uint16_t) (depth + 1)); } else { - parser_warn_indentation_mismatch(parser, opening_newline_index, &operator, false); + parser_warn_indentation_mismatch(parser, opening_newline_index, &operator, false, false); } expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END); @@ -20331,18 +20459,18 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b parser_lex(parser); pm_token_t operator = parser->previous; - pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, PM_ERR_UNARY_RECEIVER); + pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1)); pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "+@"); return (pm_node_t *) node; } case PM_TOKEN_STRING_BEGIN: - return parse_strings(parser, NULL); + return parse_strings(parser, NULL, accepts_label, (uint16_t) (depth + 1)); case PM_TOKEN_SYMBOL_BEGIN: { pm_lex_mode_t lex_mode = *parser->lex_modes.current; parser_lex(parser); - return parse_symbol(parser, &lex_mode, PM_LEX_STATE_END); + return parse_symbol(parser, &lex_mode, PM_LEX_STATE_END, (uint16_t) (depth + 1)); } default: { pm_context_t recoverable = context_recoverable(parser, &parser->current); @@ -20385,8 +20513,8 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b * or any of the binary operators that can be written to a variable. */ static pm_node_t * -parse_assignment_value(pm_parser_t *parser, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id) { - pm_node_t *value = parse_value_expression(parser, binding_power, previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? accepts_command_call : previous_binding_power < PM_BINDING_POWER_MATCH, diag_id); +parse_assignment_value(pm_parser_t *parser, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id, uint16_t depth) { + pm_node_t *value = parse_value_expression(parser, binding_power, previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? accepts_command_call : previous_binding_power < PM_BINDING_POWER_MATCH, false, diag_id, (uint16_t) (depth + 1)); // Contradicting binding powers, the right-hand-side value of the assignment // allows the `rescue` modifier. @@ -20396,7 +20524,7 @@ parse_assignment_value(pm_parser_t *parser, pm_binding_power_t previous_binding_ pm_token_t rescue = parser->current; parser_lex(parser); - pm_node_t *right = parse_expression(parser, binding_power, false, PM_ERR_RESCUE_MODIFIER_VALUE); + pm_node_t *right = parse_expression(parser, binding_power, false, false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1)); context_pop(parser); return (pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right); @@ -20454,11 +20582,11 @@ parse_assignment_value_local(pm_parser_t *parser, const pm_node_t *node) { * operator that allows multiple values after it. */ static pm_node_t * -parse_assignment_values(pm_parser_t *parser, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id) { +parse_assignment_values(pm_parser_t *parser, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id, uint16_t depth) { bool permitted = true; if (previous_binding_power != PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_USTAR)) permitted = false; - pm_node_t *value = parse_starred_expression(parser, binding_power, previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? accepts_command_call : previous_binding_power < PM_BINDING_POWER_MATCH, diag_id); + pm_node_t *value = parse_starred_expression(parser, binding_power, previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? accepts_command_call : previous_binding_power < PM_BINDING_POWER_MATCH, diag_id, (uint16_t) (depth + 1)); if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE); parse_assignment_value_local(parser, value); @@ -20474,7 +20602,7 @@ parse_assignment_values(pm_parser_t *parser, pm_binding_power_t previous_binding value = (pm_node_t *) array; while (accept1(parser, PM_TOKEN_COMMA)) { - pm_node_t *element = parse_starred_expression(parser, binding_power, false, PM_ERR_ARRAY_ELEMENT); + pm_node_t *element = parse_starred_expression(parser, binding_power, false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1)); pm_array_node_elements_append(array, element); if (PM_NODE_TYPE_P(element, PM_MISSING_NODE)) break; @@ -20502,7 +20630,7 @@ parse_assignment_values(pm_parser_t *parser, pm_binding_power_t previous_binding } } - pm_node_t *right = parse_expression(parser, binding_power, accepts_command_call_inner, PM_ERR_RESCUE_MODIFIER_VALUE); + pm_node_t *right = parse_expression(parser, binding_power, accepts_command_call_inner, false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1)); context_pop(parser); return (pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right); @@ -20657,7 +20785,7 @@ parse_regular_expression_named_captures(pm_parser_t *parser, const pm_string_t * } static inline pm_node_t * -parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, bool accepts_command_call) { +parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, bool accepts_command_call, uint16_t depth) { pm_token_t token = parser->current; switch (token.type) { @@ -20676,7 +20804,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t /* fallthrough */ case PM_CASE_WRITABLE: { parser_lex(parser); - pm_node_t *value = parse_assignment_values(parser, previous_binding_power, PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) ? PM_BINDING_POWER_MULTI_ASSIGNMENT + 1 : binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL); + pm_node_t *value = parse_assignment_values(parser, previous_binding_power, PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) ? PM_BINDING_POWER_MULTI_ASSIGNMENT + 1 : binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1)); if (PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) && previous_binding_power != PM_BINDING_POWER_STATEMENT) { pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_MULTI_WRITE); @@ -20689,7 +20817,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t pm_multi_target_node_targets_append(parser, multi_target, node); parser_lex(parser); - pm_node_t *value = parse_assignment_values(parser, previous_binding_power, PM_BINDING_POWER_MULTI_ASSIGNMENT + 1, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL); + pm_node_t *value = parse_assignment_values(parser, previous_binding_power, PM_BINDING_POWER_MULTI_ASSIGNMENT + 1, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1)); return parse_write(parser, (pm_node_t *) multi_target, &token, value); } case PM_SOURCE_ENCODING_NODE: @@ -20702,7 +20830,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t // In these special cases, we have specific error messages // and we will replace them with local variable writes. parser_lex(parser); - pm_node_t *value = parse_assignment_values(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL); + pm_node_t *value = parse_assignment_values(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1)); return parse_unwriteable_write(parser, node, &token, value); } default: @@ -20723,7 +20851,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_GLOBAL_VARIABLE_READ_NODE: { parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1)); pm_node_t *result = (pm_node_t *) pm_global_variable_and_write_node_create(parser, node, &token, value); pm_node_destroy(parser, node); @@ -20732,7 +20860,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_CLASS_VARIABLE_READ_NODE: { parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1)); pm_node_t *result = (pm_node_t *) pm_class_variable_and_write_node_create(parser, (pm_class_variable_read_node_t *) node, &token, value); pm_node_destroy(parser, node); @@ -20741,7 +20869,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_CONSTANT_PATH_NODE: { parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1)); pm_node_t *write = (pm_node_t *) pm_constant_path_and_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value); return parse_shareable_constant_write(parser, write); @@ -20749,7 +20877,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_CONSTANT_READ_NODE: { parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1)); pm_node_t *write = (pm_node_t *) pm_constant_and_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value); pm_node_destroy(parser, node); @@ -20758,7 +20886,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_INSTANCE_VARIABLE_READ_NODE: { parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1)); pm_node_t *result = (pm_node_t *) pm_instance_variable_and_write_node_create(parser, (pm_instance_variable_read_node_t *) node, &token, value); pm_node_destroy(parser, node); @@ -20768,7 +20896,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t pm_local_variable_read_node_t *cast = (pm_local_variable_read_node_t *) node; parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1)); pm_node_t *result = (pm_node_t *) pm_local_variable_and_write_node_create(parser, node, &token, value, cast->name, cast->depth); pm_node_destroy(parser, node); @@ -20787,7 +20915,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc->start, message_loc->end, 1); parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1)); pm_node_t *result = (pm_node_t *) pm_local_variable_and_write_node_create(parser, (pm_node_t *) cast, &token, value, constant_id, 0); pm_node_destroy(parser, (pm_node_t *) cast); @@ -20802,7 +20930,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t // this is an aref expression, and we can transform it into // an aset expression. if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) { - pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1)); return (pm_node_t *) pm_index_and_write_node_create(parser, cast, &token, value); } @@ -20814,7 +20942,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t } parse_call_operator_write(parser, cast, &token); - pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1)); return (pm_node_t *) pm_call_and_write_node_create(parser, cast, &token, value); } case PM_MULTI_WRITE_NODE: { @@ -20841,7 +20969,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_GLOBAL_VARIABLE_READ_NODE: { parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1)); pm_node_t *result = (pm_node_t *) pm_global_variable_or_write_node_create(parser, node, &token, value); pm_node_destroy(parser, node); @@ -20850,7 +20978,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_CLASS_VARIABLE_READ_NODE: { parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1)); pm_node_t *result = (pm_node_t *) pm_class_variable_or_write_node_create(parser, (pm_class_variable_read_node_t *) node, &token, value); pm_node_destroy(parser, node); @@ -20859,7 +20987,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_CONSTANT_PATH_NODE: { parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1)); pm_node_t *write = (pm_node_t *) pm_constant_path_or_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value); return parse_shareable_constant_write(parser, write); @@ -20867,7 +20995,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_CONSTANT_READ_NODE: { parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1)); pm_node_t *write = (pm_node_t *) pm_constant_or_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value); pm_node_destroy(parser, node); @@ -20876,7 +21004,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_INSTANCE_VARIABLE_READ_NODE: { parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1)); pm_node_t *result = (pm_node_t *) pm_instance_variable_or_write_node_create(parser, (pm_instance_variable_read_node_t *) node, &token, value); pm_node_destroy(parser, node); @@ -20886,7 +21014,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t pm_local_variable_read_node_t *cast = (pm_local_variable_read_node_t *) node; parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1)); pm_node_t *result = (pm_node_t *) pm_local_variable_or_write_node_create(parser, node, &token, value, cast->name, cast->depth); pm_node_destroy(parser, node); @@ -20905,7 +21033,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc->start, message_loc->end, 1); parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1)); pm_node_t *result = (pm_node_t *) pm_local_variable_or_write_node_create(parser, (pm_node_t *) cast, &token, value, constant_id, 0); pm_node_destroy(parser, (pm_node_t *) cast); @@ -20920,7 +21048,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t // this is an aref expression, and we can transform it into // an aset expression. if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) { - pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1)); return (pm_node_t *) pm_index_or_write_node_create(parser, cast, &token, value); } @@ -20932,7 +21060,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t } parse_call_operator_write(parser, cast, &token); - pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1)); return (pm_node_t *) pm_call_or_write_node_create(parser, cast, &token, value); } case PM_MULTI_WRITE_NODE: { @@ -20969,7 +21097,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_GLOBAL_VARIABLE_READ_NODE: { parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1)); pm_node_t *result = (pm_node_t *) pm_global_variable_operator_write_node_create(parser, node, &token, value); pm_node_destroy(parser, node); @@ -20978,7 +21106,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_CLASS_VARIABLE_READ_NODE: { parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1)); pm_node_t *result = (pm_node_t *) pm_class_variable_operator_write_node_create(parser, (pm_class_variable_read_node_t *) node, &token, value); pm_node_destroy(parser, node); @@ -20987,7 +21115,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_CONSTANT_PATH_NODE: { parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1)); pm_node_t *write = (pm_node_t *) pm_constant_path_operator_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value); return parse_shareable_constant_write(parser, write); @@ -20995,7 +21123,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_CONSTANT_READ_NODE: { parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1)); pm_node_t *write = (pm_node_t *) pm_constant_operator_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value); pm_node_destroy(parser, node); @@ -21004,7 +21132,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_INSTANCE_VARIABLE_READ_NODE: { parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1)); pm_node_t *result = (pm_node_t *) pm_instance_variable_operator_write_node_create(parser, (pm_instance_variable_read_node_t *) node, &token, value); pm_node_destroy(parser, node); @@ -21014,7 +21142,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t pm_local_variable_read_node_t *cast = (pm_local_variable_read_node_t *) node; parser_lex(parser); - pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1)); pm_node_t *result = (pm_node_t *) pm_local_variable_operator_write_node_create(parser, node, &token, value, cast->name, cast->depth); pm_node_destroy(parser, node); @@ -21032,7 +21160,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t pm_refute_numbered_parameter(parser, message_loc->start, message_loc->end); pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc->start, message_loc->end, 1); - pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1)); pm_node_t *result = (pm_node_t *) pm_local_variable_operator_write_node_create(parser, (pm_node_t *) cast, &token, value, constant_id, 0); pm_node_destroy(parser, (pm_node_t *) cast); @@ -21043,7 +21171,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t // this is an aref expression, and we can transform it into // an aset expression. if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) { - pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1)); return (pm_node_t *) pm_index_operator_write_node_create(parser, cast, &token, value); } @@ -21055,7 +21183,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t } parse_call_operator_write(parser, cast, &token); - pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1)); return (pm_node_t *) pm_call_operator_write_node_create(parser, cast, &token, value); } case PM_MULTI_WRITE_NODE: { @@ -21077,14 +21205,14 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_TOKEN_KEYWORD_AND: { parser_lex(parser); - pm_node_t *right = parse_expression(parser, binding_power, parser->previous.type == PM_TOKEN_KEYWORD_AND, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *right = parse_expression(parser, binding_power, parser->previous.type == PM_TOKEN_KEYWORD_AND, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1)); return (pm_node_t *) pm_and_node_create(parser, node, &token, right); } case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_PIPE_PIPE: { parser_lex(parser); - pm_node_t *right = parse_expression(parser, binding_power, parser->previous.type == PM_TOKEN_KEYWORD_OR, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *right = parse_expression(parser, binding_power, parser->previous.type == PM_TOKEN_KEYWORD_OR, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1)); return (pm_node_t *) pm_or_node_create(parser, node, &token, right); } case PM_TOKEN_EQUAL_TILDE: { @@ -21096,7 +21224,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t // // In this case, `foo` should be a method call and not a local yet. parser_lex(parser); - pm_node_t *argument = parse_expression(parser, binding_power, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *argument = parse_expression(parser, binding_power, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1)); // By default, we're going to create a call node and then return it. pm_call_node_t *call = pm_call_node_binary_create(parser, node, &token, argument, 0); @@ -21175,7 +21303,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t case PM_TOKEN_STAR: case PM_TOKEN_STAR_STAR: { parser_lex(parser); - pm_node_t *argument = parse_expression(parser, binding_power, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *argument = parse_expression(parser, binding_power, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1)); return (pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument, 0); } case PM_TOKEN_GREATER: @@ -21187,7 +21315,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t } parser_lex(parser); - pm_node_t *argument = parse_expression(parser, binding_power, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + pm_node_t *argument = parse_expression(parser, binding_power, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1)); return (pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON); } case PM_TOKEN_AMPERSAND_DOT: @@ -21198,7 +21326,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t // This if statement handles the foo.() syntax. if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) { - parse_arguments_list(parser, &arguments, true, false); + parse_arguments_list(parser, &arguments, true, false, (uint16_t) (depth + 1)); return (pm_node_t *) pm_call_node_shorthand_create(parser, node, &operator, &arguments); } @@ -21220,7 +21348,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t } } - parse_arguments_list(parser, &arguments, true, accepts_command_call); + parse_arguments_list(parser, &arguments, true, accepts_command_call, (uint16_t) (depth + 1)); pm_call_node_t *call = pm_call_node_call_create(parser, node, &operator, &message, &arguments); if ( @@ -21229,7 +21357,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t arguments.opening_loc.start == NULL && match1(parser, PM_TOKEN_COMMA) ) { - return parse_targets_validate(parser, (pm_node_t *) call, PM_BINDING_POWER_INDEX); + return parse_targets_validate(parser, (pm_node_t *) call, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1)); } else { return (pm_node_t *) call; } @@ -21240,7 +21368,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t pm_node_t *right = NULL; if (token_begins_expression_p(parser->current.type)) { - right = parse_expression(parser, binding_power, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR); + right = parse_expression(parser, binding_power, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1)); } return (pm_node_t *) pm_range_node_create(parser, node, &token, right); @@ -21249,14 +21377,14 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t pm_token_t keyword = parser->current; parser_lex(parser); - pm_node_t *predicate = parse_value_expression(parser, binding_power, true, PM_ERR_CONDITIONAL_IF_PREDICATE); + pm_node_t *predicate = parse_value_expression(parser, binding_power, true, false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1)); return (pm_node_t *) pm_if_node_modifier_create(parser, node, &keyword, predicate); } case PM_TOKEN_KEYWORD_UNLESS_MODIFIER: { pm_token_t keyword = parser->current; parser_lex(parser); - pm_node_t *predicate = parse_value_expression(parser, binding_power, true, PM_ERR_CONDITIONAL_UNLESS_PREDICATE); + pm_node_t *predicate = parse_value_expression(parser, binding_power, true, false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1)); return (pm_node_t *) pm_unless_node_modifier_create(parser, node, &keyword, predicate); } case PM_TOKEN_KEYWORD_UNTIL_MODIFIER: { @@ -21264,7 +21392,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t pm_statements_node_t *statements = pm_statements_node_create(parser); pm_statements_node_body_append(parser, statements, node, true); - pm_node_t *predicate = parse_value_expression(parser, binding_power, true, PM_ERR_CONDITIONAL_UNTIL_PREDICATE); + pm_node_t *predicate = parse_value_expression(parser, binding_power, true, false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1)); return (pm_node_t *) pm_until_node_modifier_create(parser, &token, predicate, statements, PM_NODE_TYPE_P(node, PM_BEGIN_NODE) ? PM_LOOP_FLAGS_BEGIN_MODIFIER : 0); } case PM_TOKEN_KEYWORD_WHILE_MODIFIER: { @@ -21272,7 +21400,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t pm_statements_node_t *statements = pm_statements_node_create(parser); pm_statements_node_body_append(parser, statements, node, true); - pm_node_t *predicate = parse_value_expression(parser, binding_power, true, PM_ERR_CONDITIONAL_WHILE_PREDICATE); + pm_node_t *predicate = parse_value_expression(parser, binding_power, true, false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1)); return (pm_node_t *) pm_while_node_modifier_create(parser, &token, predicate, statements, PM_NODE_TYPE_P(node, PM_BEGIN_NODE) ? PM_LOOP_FLAGS_BEGIN_MODIFIER : 0); } case PM_TOKEN_QUESTION_MARK: { @@ -21283,7 +21411,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t pm_token_t qmark = parser->current; parser_lex(parser); - pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_TERNARY_EXPRESSION_TRUE); + pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_TERNARY_EXPRESSION_TRUE, (uint16_t) (depth + 1)); if (parser->recovering) { // If parsing the true expression of this ternary resulted in a syntax @@ -21306,7 +21434,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t expect1(parser, PM_TOKEN_COLON, PM_ERR_TERNARY_COLON); pm_token_t colon = parser->previous; - pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_TERNARY_EXPRESSION_FALSE); + pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_TERNARY_EXPRESSION_FALSE, (uint16_t) (depth + 1)); context_pop(parser); pop_block_exits(parser, previous_block_exits); @@ -21336,7 +21464,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t pm_token_t message = parser->previous; pm_arguments_t arguments = { 0 }; - parse_arguments_list(parser, &arguments, true, accepts_command_call); + parse_arguments_list(parser, &arguments, true, accepts_command_call, (uint16_t) (depth + 1)); path = (pm_node_t *) pm_call_node_call_create(parser, node, &delimiter, &message, &arguments); } else { // Otherwise, this is a constant path. That would look like Foo::Bar. @@ -21345,7 +21473,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t // If this is followed by a comma then it is a multiple assignment. if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) { - return parse_targets_validate(parser, path, PM_BINDING_POWER_INDEX); + return parse_targets_validate(parser, path, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1)); } return path; @@ -21360,12 +21488,12 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t // If we have an identifier following a '::' operator, then it is for // sure a method call. pm_arguments_t arguments = { 0 }; - parse_arguments_list(parser, &arguments, true, accepts_command_call); + parse_arguments_list(parser, &arguments, true, accepts_command_call, (uint16_t) (depth + 1)); pm_call_node_t *call = pm_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 == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) { - return parse_targets_validate(parser, (pm_node_t *) call, PM_BINDING_POWER_INDEX); + return parse_targets_validate(parser, (pm_node_t *) call, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1)); } return (pm_node_t *) call; @@ -21374,7 +21502,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t // If we have a parenthesis following a '::' operator, then it is the // method call shorthand. That would look like Foo::(bar). pm_arguments_t arguments = { 0 }; - parse_arguments_list(parser, &arguments, true, false); + parse_arguments_list(parser, &arguments, true, false, (uint16_t) (depth + 1)); return (pm_node_t *) pm_call_node_shorthand_create(parser, node, &delimiter, &arguments); } @@ -21389,7 +21517,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t parser_lex(parser); accept1(parser, PM_TOKEN_NEWLINE); - pm_node_t *value = parse_expression(parser, binding_power, true, PM_ERR_RESCUE_MODIFIER_VALUE); + pm_node_t *value = parse_expression(parser, binding_power, true, false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1)); context_pop(parser); return (pm_node_t *) pm_rescue_modifier_node_create(parser, node, &token, value); @@ -21402,7 +21530,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) { pm_accepts_block_stack_push(parser, true); - parse_arguments(parser, &arguments, false, PM_TOKEN_BRACKET_RIGHT); + parse_arguments(parser, &arguments, false, PM_TOKEN_BRACKET_RIGHT, (uint16_t) (depth + 1)); pm_accepts_block_stack_pop(parser); expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_EXPECT_RBRACKET); } @@ -21413,7 +21541,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t // assignment and we should parse the targets. if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) { pm_call_node_t *aref = pm_call_node_aref_create(parser, node, &arguments); - return parse_targets_validate(parser, (pm_node_t *) aref, PM_BINDING_POWER_INDEX); + return parse_targets_validate(parser, (pm_node_t *) aref, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1)); } // If we're at the end of the arguments, we can now check if there is a @@ -21421,10 +21549,10 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t // add it to the arguments. pm_block_node_t *block = NULL; if (accept1(parser, PM_TOKEN_BRACE_LEFT)) { - block = parse_block(parser); + block = parse_block(parser, (uint16_t) (depth + 1)); pm_arguments_validate_block(parser, &arguments, block); } else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) { - block = parse_block(parser); + block = parse_block(parser, (uint16_t) (depth + 1)); } if (block != NULL) { @@ -21451,7 +21579,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t parser_lex(parser); pm_constant_id_list_t captures = { 0 }; - pm_node_t *pattern = parse_pattern(parser, &captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_IN); + pm_node_t *pattern = parse_pattern(parser, &captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_IN, (uint16_t) (depth + 1)); parser->pattern_matching_newlines = previous_pattern_matching_newlines; pm_constant_id_list_free(&captures); @@ -21468,7 +21596,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t parser_lex(parser); pm_constant_id_list_t captures = { 0 }; - pm_node_t *pattern = parse_pattern(parser, &captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_HROCKET); + pm_node_t *pattern = parse_pattern(parser, &captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_HROCKET, (uint16_t) (depth + 1)); parser->pattern_matching_newlines = previous_pattern_matching_newlines; pm_constant_id_list_free(&captures); @@ -21485,6 +21613,19 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t #undef PM_PARSE_PATTERN_TOP #undef PM_PARSE_PATTERN_MULTI +/** + * Determine if a given call node looks like a "command", which means it has + * arguments but does not have parentheses. + */ +static inline bool +pm_call_node_command_p(const pm_call_node_t *node) { + return ( + (node->opening_loc.start == NULL) && + (node->block == NULL || PM_NODE_TYPE_P(node->block, PM_BLOCK_ARGUMENT_NODE)) && + (node->arguments != NULL || node->block != NULL) + ); +} + /** * Parse an expression at the given point of the parser using the given binding * power to parse subsequent chains. If this function finds a syntax error, it @@ -21494,8 +21635,13 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t * determine if they need to perform additional cleanup. */ static pm_node_t * -parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id) { - pm_node_t *node = parse_expression_prefix(parser, binding_power, accepts_command_call, diag_id); +parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call, bool accepts_label, pm_diagnostic_id_t diag_id, uint16_t depth) { + if (PRISM_UNLIKELY(depth >= PRISM_DEPTH_MAXIMUM)) { + pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP); + return (pm_node_t *) pm_missing_node_create(parser, parser->current.start, parser->current.end); + } + + pm_node_t *node = parse_expression_prefix(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth); switch (PM_NODE_TYPE(node)) { case PM_MISSING_NODE: @@ -21514,6 +21660,23 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc return node; } break; + case PM_CALL_NODE: + // If we have a call node, then we need to check if it looks like a + // method call without parentheses that contains arguments. If it + // does, then it has different rules for parsing infix operators, + // namely that it only accepts composition (and/or) and modifiers + // (if/unless/etc.). + if ((pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_COMPOSITION) && pm_call_node_command_p((pm_call_node_t *) node)) { + return node; + } + break; + case PM_SYMBOL_NODE: + // If we have a symbol node that is being parsed as a label, then we + // need to immediately return, because there should never be an + // infix operator following this node. + if (pm_symbol_node_label_p(node)) { + return node; + } default: break; } @@ -21526,9 +21689,16 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc binding_power <= current_binding_powers.left && current_binding_powers.binary ) { - node = parse_expression_infix(parser, node, binding_power, current_binding_powers.right, accepts_command_call); + node = parse_expression_infix(parser, node, binding_power, current_binding_powers.right, accepts_command_call, (uint16_t) (depth + 1)); switch (PM_NODE_TYPE(node)) { + case PM_MULTI_WRITE_NODE: + // Multi-write nodes are statements, and cannot be followed by + // operators except modifiers. + if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER) { + return node; + } + break; case PM_CLASS_VARIABLE_WRITE_NODE: case PM_CONSTANT_PATH_WRITE_NODE: case PM_CONSTANT_WRITE_NODE: @@ -21553,16 +21723,26 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc break; } + // If the operator is nonassoc and we should not be able to parse the + // upcoming infix operator, break. if (current_binding_powers.nonassoc) { - bool endless_range_p = PM_NODE_TYPE_P(node, PM_RANGE_NODE) && ((pm_range_node_t *) node)->right == NULL; - pm_binding_power_t left = endless_range_p ? PM_BINDING_POWER_TERM : current_binding_powers.left; - if ( - left <= pm_binding_powers[parser->current.type].left || - // Exceptionally to operator precedences, '1.. & 2' is rejected. - // '1.. || 2' is also an exception, but it is handled by the lexer. - // (Here, parser->current is PM_TOKEN_PIPE, not PM_TOKEN_PIPE_PIPE). - (endless_range_p && match1(parser, PM_TOKEN_AMPERSAND)) - ) { + // If this is an endless range, then we need to reject a couple of + // additional operators because it violates the normal operator + // precedence rules. Those patterns are: + // + // 1.. & 2 + // 1.. * 2 + // + if (PM_NODE_TYPE_P(node, PM_RANGE_NODE) && ((pm_range_node_t *) node)->right == NULL) { + if (match4(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_DOT, PM_TOKEN_AMPERSAND_DOT)) { + PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_NON_ASSOCIATIVE_OPERATOR, pm_token_type_human(parser->current.type), pm_token_type_human(parser->previous.type)); + break; + } + + if (PM_BINDING_POWER_TERM <= pm_binding_powers[parser->current.type].left) { + break; + } + } else if (current_binding_powers.left <= pm_binding_powers[parser->current.type].left) { break; } } @@ -21708,7 +21888,7 @@ parse_program(pm_parser_t *parser) { pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits); parser_lex(parser); - pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_MAIN); + pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_MAIN, 0); if (statements == NULL) { statements = pm_statements_node_create(parser); @@ -21767,6 +21947,9 @@ pm_strnstr(const char *big, const char *little, size_t big_length) { return NULL; } +#ifdef _WIN32 +#define pm_parser_warn_shebang_carriage_return(parser, start, length) ((void) 0) +#else /** * Potentially warn the user if the shebang that has been found to include * "ruby" has a carriage return at the end, as that can cause problems on some @@ -21778,6 +21961,7 @@ pm_parser_warn_shebang_carriage_return(pm_parser_t *parser, const uint8_t *start pm_parser_warn(parser, start, start + length, PM_WARN_SHEBANG_CARRIAGE_RETURN); } } +#endif /** * Process the shebang when initializing the parser. This function assumes that @@ -21852,6 +22036,7 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm .explicit_encoding = NULL, .command_line = 0, .parsing_eval = false, + .partial_script = false, .command_start = true, .recovering = false, .encoding_locked = false, @@ -21915,8 +22100,12 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm // version option parser->version = options->version; + // partial_script + parser->partial_script = options->partial_script; + // scopes option parser->parsing_eval = options->scopes_count > 0; + if (parser->parsing_eval) parser->warn_mismatched_indentation = false; for (size_t scope_index = 0; scope_index < options->scopes_count; scope_index++) { const pm_options_scope_t *scope = pm_options_scope_get(options, scope_index); @@ -21959,27 +22148,42 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm // "ruby" and start parsing from there. bool search_shebang = PM_PARSER_COMMAND_LINE_OPTION_X(parser); - // If the first two bytes of the source are a shebang, then we'll indicate - // that the encoding comment is at the end of the shebang. + // If the first two bytes of the source are a shebang, then we will do a bit + // of extra processing. + // + // First, we'll indicate that the encoding comment is at the end of the + // shebang. This means that when a shebang is present the encoding comment + // can begin on the second line. + // + // Second, we will check if the shebang includes "ruby". If it does, then we + // we will start parsing from there. We will also potentially warning the + // user if there is a carriage return at the end of the shebang. We will + // also potentially call the shebang callback if this is the main script to + // allow the caller to parse the shebang and find any command-line options. + // If the shebang does not include "ruby" and this is the main script being + // parsed, then we will start searching the file for a shebang that does + // contain "ruby" as if -x were passed on the command line. const uint8_t *newline = next_newline(parser->start, parser->end - parser->start); size_t length = (size_t) ((newline != NULL ? newline : parser->end) - parser->start); if (length > 2 && parser->current.end[0] == '#' && parser->current.end[1] == '!') { const char *engine; + if ((engine = pm_strnstr((const char *) parser->start, "ruby", length)) != NULL) { if (newline != NULL) { - size_t length_including_newline = length + 1; - pm_parser_warn_shebang_carriage_return(parser, parser->start, length_including_newline); - parser->encoding_comment_start = newline + 1; + + if (options == NULL || options->main_script) { + pm_parser_warn_shebang_carriage_return(parser, parser->start, length + 1); + } } - if (options != NULL && options->shebang_callback != NULL) { + if (options != NULL && options->main_script && options->shebang_callback != NULL) { pm_parser_init_shebang(parser, options, engine, length - ((size_t) (engine - (const char *) parser->start))); } search_shebang = false; - } else if (!parser->parsing_eval) { + } else if (options->main_script && !parser->parsing_eval) { search_shebang = true; } } @@ -22010,10 +22214,9 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm const char *engine; if ((engine = pm_strnstr((const char *) cursor, "ruby", length)) != NULL) { found_shebang = true; - if (newline != NULL) { - size_t length_including_newline = length + 1; - pm_parser_warn_shebang_carriage_return(parser, cursor, length_including_newline); + if (newline != NULL) { + pm_parser_warn_shebang_carriage_return(parser, cursor, length + 1); parser->encoding_comment_start = newline + 1; } diff --git a/src/main/c/yarp/src/util/pm_string.c b/src/main/c/yarp/src/util/pm_string.c index 0a67accd866..7e56dec9f7e 100644 --- a/src/main/c/yarp/src/util/pm_string.c +++ b/src/main/c/yarp/src/util/pm_string.c @@ -47,6 +47,62 @@ pm_string_constant_init(pm_string_t *string, const char *source, size_t length) }; } +#ifdef _WIN32 +/** + * Represents a file handle on Windows, where the path will need to be freed + * when the file is closed. + */ +typedef struct { + /** The path to the file, which will become allocated memory. */ + WCHAR *path; + + /** The handle to the file, which will start as uninitialized memory. */ + HANDLE file; +} pm_string_file_handle_t; + +/** + * Open the file indicated by the filepath parameter for reading on Windows. + * Perform any kind of normalization that needs to happen on the filepath. + */ +static pm_string_init_result_t +pm_string_file_handle_open(pm_string_file_handle_t *handle, const char *filepath) { + int length = MultiByteToWideChar(CP_UTF8, 0, filepath, -1, NULL, 0); + if (length == 0) return PM_STRING_INIT_ERROR_GENERIC; + + handle->path = xmalloc(sizeof(WCHAR) * ((size_t) length)); + if ((handle->path == NULL) || (MultiByteToWideChar(CP_UTF8, 0, filepath, -1, handle->path, length) == 0)) { + xfree(handle->path); + return PM_STRING_INIT_ERROR_GENERIC; + } + + handle->file = CreateFileW(handle->path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); + if (handle->file == INVALID_HANDLE_VALUE) { + pm_string_init_result_t result = PM_STRING_INIT_ERROR_GENERIC; + + if (GetLastError() == ERROR_ACCESS_DENIED) { + DWORD attributes = GetFileAttributesW(handle->path); + if ((attributes != INVALID_FILE_ATTRIBUTES) && (attributes & FILE_ATTRIBUTE_DIRECTORY)) { + result = PM_STRING_INIT_ERROR_DIRECTORY; + } + } + + xfree(handle->path); + return result; + } + + return PM_STRING_INIT_SUCCESS; +} + +/** + * Close the file handle and free the path. + */ +static void +pm_string_file_handle_close(pm_string_file_handle_t *handle) { + xfree(handle->path); + CloseHandle(handle->file); +} +#endif + /** * Read the file indicated by the filepath parameter into source and load its * contents and size into the given `pm_string_t`. The given `pm_string_t` @@ -58,69 +114,66 @@ pm_string_constant_init(pm_string_t *string, const char *source, size_t length) * `MapViewOfFile`, on POSIX systems that have access to `mmap` we'll use * `mmap`, and on other POSIX systems we'll use `read`. */ -PRISM_EXPORTED_FUNCTION bool +PRISM_EXPORTED_FUNCTION pm_string_init_result_t pm_string_mapped_init(pm_string_t *string, const char *filepath) { #ifdef _WIN32 // Open the file for reading. - HANDLE file = CreateFile(filepath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - - if (file == INVALID_HANDLE_VALUE) { - return false; - } + pm_string_file_handle_t handle; + pm_string_init_result_t result = pm_string_file_handle_open(&handle, filepath); + if (result != PM_STRING_INIT_SUCCESS) return result; // Get the file size. - DWORD file_size = GetFileSize(file, NULL); + DWORD file_size = GetFileSize(handle.file, NULL); if (file_size == INVALID_FILE_SIZE) { - CloseHandle(file); - return false; + pm_string_file_handle_close(&handle); + return PM_STRING_INIT_ERROR_GENERIC; } // If the file is empty, then we don't need to do anything else, we'll set // the source to a constant empty string and return. if (file_size == 0) { - CloseHandle(file); + pm_string_file_handle_close(&handle); const uint8_t source[] = ""; *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 }; - return true; + return PM_STRING_INIT_SUCCESS; } // Create a mapping of the file. - HANDLE mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL); + HANDLE mapping = CreateFileMapping(handle.file, NULL, PAGE_READONLY, 0, 0, NULL); if (mapping == NULL) { - CloseHandle(file); - return false; + pm_string_file_handle_close(&handle); + return PM_STRING_INIT_ERROR_GENERIC; } // Map the file into memory. uint8_t *source = (uint8_t *) MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0); CloseHandle(mapping); - CloseHandle(file); + pm_string_file_handle_close(&handle); if (source == NULL) { - return false; + return PM_STRING_INIT_ERROR_GENERIC; } *string = (pm_string_t) { .type = PM_STRING_MAPPED, .source = source, .length = (size_t) file_size }; - return true; + return PM_STRING_INIT_SUCCESS; #elif defined(_POSIX_MAPPED_FILES) // Open the file for reading int fd = open(filepath, O_RDONLY); if (fd == -1) { - return false; + return PM_STRING_INIT_ERROR_GENERIC; } // Stat the file to get the file size struct stat sb; if (fstat(fd, &sb) == -1) { close(fd); - return false; + return PM_STRING_INIT_ERROR_GENERIC; } // Ensure it is a file and not a directory if (S_ISDIR(sb.st_mode)) { - errno = EISDIR; close(fd); - return false; + return PM_STRING_INIT_ERROR_DIRECTORY; } // mmap the file descriptor to virtually get the contents @@ -131,17 +184,17 @@ pm_string_mapped_init(pm_string_t *string, const char *filepath) { close(fd); const uint8_t source[] = ""; *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 }; - return true; + return PM_STRING_INIT_SUCCESS; } source = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); if (source == MAP_FAILED) { - return false; + return PM_STRING_INIT_ERROR_GENERIC; } close(fd); *string = (pm_string_t) { .type = PM_STRING_MAPPED, .source = source, .length = size }; - return true; + return PM_STRING_INIT_SUCCESS; #else return pm_string_file_init(string, filepath); #endif @@ -152,100 +205,105 @@ pm_string_mapped_init(pm_string_t *string, const char *filepath) { * contents and size into the given `pm_string_t`. The given `pm_string_t` * should be freed using `pm_string_free` when it is no longer used. */ -PRISM_EXPORTED_FUNCTION bool +PRISM_EXPORTED_FUNCTION pm_string_init_result_t pm_string_file_init(pm_string_t *string, const char *filepath) { #ifdef _WIN32 // Open the file for reading. - HANDLE file = CreateFile(filepath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - - if (file == INVALID_HANDLE_VALUE) { - return false; - } + pm_string_file_handle_t handle; + pm_string_init_result_t result = pm_string_file_handle_open(&handle, filepath); + if (result != PM_STRING_INIT_SUCCESS) return result; // Get the file size. - DWORD file_size = GetFileSize(file, NULL); + DWORD file_size = GetFileSize(handle.file, NULL); if (file_size == INVALID_FILE_SIZE) { - CloseHandle(file); - return false; + pm_string_file_handle_close(&handle); + return PM_STRING_INIT_ERROR_GENERIC; } // If the file is empty, then we don't need to do anything else, we'll set // the source to a constant empty string and return. if (file_size == 0) { - CloseHandle(file); + pm_string_file_handle_close(&handle); const uint8_t source[] = ""; *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 }; - return true; + return PM_STRING_INIT_SUCCESS; } // Create a buffer to read the file into. uint8_t *source = xmalloc(file_size); if (source == NULL) { - CloseHandle(file); - return false; + pm_string_file_handle_close(&handle); + return PM_STRING_INIT_ERROR_GENERIC; } // Read the contents of the file DWORD bytes_read; - if (!ReadFile(file, source, file_size, &bytes_read, NULL)) { - CloseHandle(file); - return false; + if (!ReadFile(handle.file, source, file_size, &bytes_read, NULL)) { + pm_string_file_handle_close(&handle); + return PM_STRING_INIT_ERROR_GENERIC; } // Check the number of bytes read if (bytes_read != file_size) { xfree(source); - CloseHandle(file); - return false; + pm_string_file_handle_close(&handle); + return PM_STRING_INIT_ERROR_GENERIC; } - CloseHandle(file); + pm_string_file_handle_close(&handle); *string = (pm_string_t) { .type = PM_STRING_OWNED, .source = source, .length = (size_t) file_size }; - return true; + return PM_STRING_INIT_SUCCESS; #elif defined(PRISM_HAS_FILESYSTEM) - FILE *file = fopen(filepath, "rb"); - if (file == NULL) { - return false; + // Open the file for reading + int fd = open(filepath, O_RDONLY); + if (fd == -1) { + return PM_STRING_INIT_ERROR_GENERIC; } - fseek(file, 0, SEEK_END); - long file_size = ftell(file); + // Stat the file to get the file size + struct stat sb; + if (fstat(fd, &sb) == -1) { + close(fd); + return PM_STRING_INIT_ERROR_GENERIC; + } - if (file_size == -1) { - fclose(file); - return false; + // Ensure it is a file and not a directory + if (S_ISDIR(sb.st_mode)) { + close(fd); + return PM_STRING_INIT_ERROR_DIRECTORY; } - if (file_size == 0) { - fclose(file); + // Check the size to see if it's empty + size_t size = (size_t) sb.st_size; + if (size == 0) { + close(fd); const uint8_t source[] = ""; *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 }; - return true; + return PM_STRING_INIT_SUCCESS; } - size_t length = (size_t) file_size; + size_t length = (size_t) size; uint8_t *source = xmalloc(length); if (source == NULL) { - fclose(file); - return false; + close(fd); + return PM_STRING_INIT_ERROR_GENERIC; } - fseek(file, 0, SEEK_SET); - size_t bytes_read = fread(source, length, 1, file); - fclose(file); + long bytes_read = (long) read(fd, source, length); + close(fd); - if (bytes_read != 1) { + if (bytes_read == -1) { xfree(source); - return false; + return PM_STRING_INIT_ERROR_GENERIC; } *string = (pm_string_t) { .type = PM_STRING_OWNED, .source = source, .length = length }; - return true; + return PM_STRING_INIT_SUCCESS; #else (void) string; (void) filepath; perror("pm_string_file_init is not implemented for this platform"); - return false; + return PM_STRING_INIT_ERROR_GENERIC; #endif } diff --git a/src/main/java/org/truffleruby/cext/CExtNodes.java b/src/main/java/org/truffleruby/cext/CExtNodes.java index ef5a1b54330..9098ba6d957 100644 --- a/src/main/java/org/truffleruby/cext/CExtNodes.java +++ b/src/main/java/org/truffleruby/cext/CExtNodes.java @@ -95,7 +95,6 @@ import org.truffleruby.language.arguments.ArgumentsDescriptor; import org.truffleruby.language.arguments.NoKeywordArgumentsDescriptor; import org.truffleruby.language.arguments.KeywordArgumentsDescriptor; -import org.truffleruby.language.arguments.KeywordArgumentsDescriptorManager; import org.truffleruby.language.arguments.RubyArguments; import org.truffleruby.language.backtrace.Backtrace; import org.truffleruby.language.constants.GetConstantNode; @@ -396,7 +395,7 @@ Object sendWithoutCExtLock(VirtualFrame frame, Object receiver, RubySymbol metho dispatchNode, PRIVATE, ownedProfile); } else { return sendWithoutCExtLock(frame, receiver, method, block, - KeywordArgumentsDescriptorManager.EMPTY, args, + KeywordArgumentsDescriptor.EMPTY, args, dispatchNode, PRIVATE, ownedProfile); } } @@ -434,7 +433,7 @@ Object sendWithoutCExtLock(VirtualFrame frame, Object receiver, RubySymbol metho dispatchNode, PUBLIC, ownedProfile); } else { return sendWithoutCExtLock(frame, receiver, method, block, - KeywordArgumentsDescriptorManager.EMPTY, args, + KeywordArgumentsDescriptor.EMPTY, args, dispatchNode, PUBLIC, ownedProfile); } } diff --git a/src/main/java/org/truffleruby/debug/TruffleDebugNodes.java b/src/main/java/org/truffleruby/debug/TruffleDebugNodes.java index 65e4990f5be..937e370d0b9 100644 --- a/src/main/java/org/truffleruby/debug/TruffleDebugNodes.java +++ b/src/main/java/org/truffleruby/debug/TruffleDebugNodes.java @@ -279,7 +279,8 @@ private static ParseResult getParseResult(RubyLanguage language, RubySource ruby String sourcePath = rubySource.getSourcePath(language).intern(); return YARPTranslatorDriver.parseToYARPAST(rubySource, sourcePath, rubySource.getBytes(), - Collections.emptyList(), language.options.FROZEN_STRING_LITERALS, null); + Collections.emptyList(), language.options.FROZEN_STRING_LITERALS, null, + ParserContext.TOP_LEVEL_FIRST); } } diff --git a/src/main/java/org/truffleruby/language/arguments/KeywordArgumentsDescriptor.java b/src/main/java/org/truffleruby/language/arguments/KeywordArgumentsDescriptor.java index 923b98c470d..3f2892bd467 100644 --- a/src/main/java/org/truffleruby/language/arguments/KeywordArgumentsDescriptor.java +++ b/src/main/java/org/truffleruby/language/arguments/KeywordArgumentsDescriptor.java @@ -18,6 +18,9 @@ * arguments were passed. The callee must handle that for now. */ public final class KeywordArgumentsDescriptor extends ArgumentsDescriptor { + public static final KeywordArgumentsDescriptor EMPTY = new KeywordArgumentsDescriptor( + StringUtils.EMPTY_STRING_ARRAY); + @CompilationFinal(dimensions = 1) private final String[] keywords; /** Use {@link KeywordArgumentsDescriptorManager} to get an instance. */ diff --git a/src/main/java/org/truffleruby/language/arguments/KeywordArgumentsDescriptorManager.java b/src/main/java/org/truffleruby/language/arguments/KeywordArgumentsDescriptorManager.java index 1e578c2cc52..ec7fb2845d2 100644 --- a/src/main/java/org/truffleruby/language/arguments/KeywordArgumentsDescriptorManager.java +++ b/src/main/java/org/truffleruby/language/arguments/KeywordArgumentsDescriptorManager.java @@ -16,13 +16,10 @@ public final class KeywordArgumentsDescriptorManager { - public static final KeywordArgumentsDescriptor EMPTY = new KeywordArgumentsDescriptor( - StringUtils.EMPTY_STRING_ARRAY); - private final WeakValueCache CANONICAL_KEYWORD_DESCRIPTORS = new WeakValueCache<>(); public KeywordArgumentsDescriptorManager() { - CANONICAL_KEYWORD_DESCRIPTORS.put(new Key(StringUtils.EMPTY_STRING_ARRAY), EMPTY); + CANONICAL_KEYWORD_DESCRIPTORS.put(new Key(StringUtils.EMPTY_STRING_ARRAY), KeywordArgumentsDescriptor.EMPTY); } public KeywordArgumentsDescriptor getArgumentsDescriptor(String[] keywords) { diff --git a/src/main/java/org/truffleruby/language/dispatch/DispatchNode.java b/src/main/java/org/truffleruby/language/dispatch/DispatchNode.java index 7c078578f01..3eda0d653ab 100644 --- a/src/main/java/org/truffleruby/language/dispatch/DispatchNode.java +++ b/src/main/java/org/truffleruby/language/dispatch/DispatchNode.java @@ -27,8 +27,8 @@ import org.truffleruby.language.RubyRootNode; import org.truffleruby.language.SpecialVariablesSendingNode; import org.truffleruby.language.arguments.ArgumentsDescriptor; +import org.truffleruby.language.arguments.KeywordArgumentsDescriptor; import org.truffleruby.language.arguments.NoKeywordArgumentsDescriptor; -import org.truffleruby.language.arguments.KeywordArgumentsDescriptorManager; import org.truffleruby.language.arguments.RubyArguments; import org.truffleruby.language.methods.CallInternalMethodNode; import org.truffleruby.language.methods.InternalMethod; @@ -149,7 +149,7 @@ public Object callWithKeywords(Object receiver, String method, Object arg1, final Object[] rubyArgs = RubyArguments.allocate(2); RubyArguments.setSelf(rubyArgs, receiver); RubyArguments.setBlock(rubyArgs, nil); - RubyArguments.setDescriptor(rubyArgs, KeywordArgumentsDescriptorManager.EMPTY); + RubyArguments.setDescriptor(rubyArgs, KeywordArgumentsDescriptor.EMPTY); RubyArguments.setArgument(rubyArgs, 0, arg1); RubyArguments.setArgument(rubyArgs, 1, keywords); return execute(null, receiver, method, rubyArgs, PRIVATE); diff --git a/src/main/java/org/truffleruby/language/dispatch/LiteralCallNode.java b/src/main/java/org/truffleruby/language/dispatch/LiteralCallNode.java index e654af2c270..a26796bee05 100644 --- a/src/main/java/org/truffleruby/language/dispatch/LiteralCallNode.java +++ b/src/main/java/org/truffleruby/language/dispatch/LiteralCallNode.java @@ -20,7 +20,6 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import org.truffleruby.language.arguments.NoKeywordArgumentsDescriptor; import org.truffleruby.language.arguments.KeywordArgumentsDescriptor; -import org.truffleruby.language.arguments.KeywordArgumentsDescriptorManager; /** A literal call site in Ruby code: one of foo(), super or yield. */ public abstract class LiteralCallNode extends RubyContextSourceNode { @@ -58,7 +57,7 @@ protected ArgumentsDescriptor getArgumentsDescriptorAndCheckRuby2KeywordsHash(Ob RubyHash hash = (RubyHash) lastArgument; if (hash.ruby2_keywords) { // both branches profiled copyRuby2KeywordsHashBoundary(args, hash); - return KeywordArgumentsDescriptorManager.EMPTY; + return KeywordArgumentsDescriptor.EMPTY; } else { if (!notRuby2KeywordsHashProfile) { CompilerDirectives.transferToInterpreterAndInvalidate(); diff --git a/src/main/java/org/truffleruby/parser/YARPPatternMatchingTranslator.java b/src/main/java/org/truffleruby/parser/YARPPatternMatchingTranslator.java index e6e2a6add71..75b433b6eae 100644 --- a/src/main/java/org/truffleruby/parser/YARPPatternMatchingTranslator.java +++ b/src/main/java/org/truffleruby/parser/YARPPatternMatchingTranslator.java @@ -219,7 +219,7 @@ public RubyNode visitFindPatternNode(Nodes.FindPatternNode node) { } } - Nodes.SplatNode leftSplat = (Nodes.SplatNode) node.left; + Nodes.SplatNode leftSplat = node.left; int leftSlot = environment.declareLocalTemp("pattern_find_left"); var readLeftSlot = environment.readNode(leftSlot, node); var writeLeftSlot = readLeftSlot.makeWriteNode(null); @@ -233,7 +233,7 @@ public RubyNode visitFindPatternNode(Nodes.FindPatternNode node) { currentValueToMatch = prev; } - Nodes.SplatNode rightSplat = (Nodes.SplatNode) node.right; + Nodes.SplatNode rightSplat = node.right; int rightSlot = environment.declareLocalTemp("pattern_find_right"); var readRightSlot = environment.readNode(rightSlot, node); var writeRightSlot = readRightSlot.makeWriteNode(null); diff --git a/src/main/java/org/truffleruby/parser/YARPTranslator.java b/src/main/java/org/truffleruby/parser/YARPTranslator.java index b54d7b8d412..fcbf0718f62 100644 --- a/src/main/java/org/truffleruby/parser/YARPTranslator.java +++ b/src/main/java/org/truffleruby/parser/YARPTranslator.java @@ -61,7 +61,7 @@ import org.truffleruby.language.RubyRootNode; import org.truffleruby.language.RubyTopLevelRootNode; import org.truffleruby.language.arguments.ArgumentsDescriptor; -import org.truffleruby.language.arguments.KeywordArgumentsDescriptorManager; +import org.truffleruby.language.arguments.KeywordArgumentsDescriptor; import org.truffleruby.language.arguments.NoKeywordArgumentsDescriptor; import org.truffleruby.language.arguments.ProfileArgumentNodeGen; import org.truffleruby.language.arguments.ReadSelfNode; @@ -805,16 +805,13 @@ private ArgumentsDescriptor getKeywordArgumentsDescriptor(Nodes.Node[] arguments return NoKeywordArgumentsDescriptor.INSTANCE; } - // Fast path. - // Keyword arguments definitely present in method call arguments if the last argument is - // either a Hash or `...`. + // fast path to compute the descriptor without looking at all arguments Nodes.Node last = ArrayUtils.getLast(arguments); - + // if `...` then we know there are no literal keyword arguments, only **kwrest if (last instanceof Nodes.ForwardingArgumentsNode) { - return language.keywordArgumentsDescriptorManager - .getArgumentsDescriptor(StringUtils.EMPTY_STRING_ARRAY); + return KeywordArgumentsDescriptor.EMPTY; } - + // if there are no keywords the descriptor is NoKeywordArgumentsDescriptor.INSTANCE if (!(last instanceof Nodes.KeywordHashNode keywords)) { return NoKeywordArgumentsDescriptor.INSTANCE; } @@ -973,7 +970,7 @@ public RubyNode visitCaseMatchNode(Nodes.CaseMatchNode node) { } for (int n = node.conditions.length - 1; n >= 0; n--) { - Nodes.InNode inNode = (Nodes.InNode) node.conditions[n]; + Nodes.InNode inNode = node.conditions[n]; Nodes.Node patternNode = inNode.pattern; final RubyNode conditionNode = translator.translatePatternNode(patternNode, readPredicateNode); @@ -1013,15 +1010,11 @@ public RubyNode visitCaseNode(Nodes.CaseNode node) { // Work backwards to make the first if contain all the others in its `else` clause. RubyNode elseNode = translateNodeOrNil(node.else_clause); - final Nodes.Node[] conditions = node.conditions; + final Nodes.WhenNode[] whenNodes = node.conditions; - for (int n = conditions.length - 1; n >= 0; n--) { - // condition is either WhenNode or InNode - // don't handle InNode for now - assert conditions[n] instanceof Nodes.WhenNode; - - final Nodes.WhenNode when = (Nodes.WhenNode) conditions[n]; - final Nodes.Node[] whenConditions = when.conditions; + for (int n = whenNodes.length - 1; n >= 0; n--) { + final Nodes.WhenNode whenNode = whenNodes[n]; + final Nodes.Node[] whenConditions = whenNode.conditions; boolean containSplatOperator = containYARPSplatNode(whenConditions); if (containSplatOperator) { @@ -1033,7 +1026,7 @@ public RubyNode visitCaseNode(Nodes.CaseNode node) { final RubyNode predicateNode = createCallNode(receiver, "when_splat", arguments); // create `if` node - final RubyNode thenNode = translateNodeOrNil(when.statements); + final RubyNode thenNode = translateNodeOrNil(whenNode.statements); final IfElseNode ifNode = IfElseNodeGen.create(predicateNode, thenNode, elseNode); // this `if` becomes `else` branch of the outer `if` @@ -1060,7 +1053,7 @@ public RubyNode visitCaseNode(Nodes.CaseNode node) { } // create `if` node - final RubyNode thenNode = translateNodeOrNil(when.statements); + final RubyNode thenNode = translateNodeOrNil(whenNode.statements); final IfElseNode ifNode = IfElseNodeGen.create(predicateNode, thenNode, elseNode); // this `if` becomes `else` branch of the outer `if` @@ -1080,15 +1073,11 @@ public RubyNode visitCaseNode(Nodes.CaseNode node) { RubyNode elseNode = translateNodeOrNil(node.else_clause); - final Nodes.Node[] conditions = node.conditions; + final Nodes.WhenNode[] whenNodes = node.conditions; for (int n = node.conditions.length - 1; n >= 0; n--) { - // condition is either WhenNode or InNode - // don't handle InNode for now - assert conditions[n] instanceof Nodes.WhenNode; - - final Nodes.WhenNode when = (Nodes.WhenNode) conditions[n]; - final Nodes.Node[] whenConditions = when.conditions; + final Nodes.WhenNode whenNode = whenNodes[n]; + final Nodes.Node[] whenConditions = whenNode.conditions; boolean containSplatOperator = containYARPSplatNode(whenConditions); if (!containSplatOperator) { @@ -1111,7 +1100,7 @@ public RubyNode visitCaseNode(Nodes.CaseNode node) { } // create `if` node - final RubyNode thenNode = translateNodeOrNil(when.statements); + final RubyNode thenNode = translateNodeOrNil(whenNode.statements); final IfElseNode ifNode = IfElseNodeGen.create(predicateNode, thenNode, elseNode); // this `if` becomes `else` branch of the outer `if` @@ -1125,7 +1114,7 @@ public RubyNode visitCaseNode(Nodes.CaseNode node) { final RubyNode predicateNode = createCallNode(receiver, "any?", RubyNode.EMPTY_ARRAY); // create `if` node - final RubyNode thenNode = translateNodeOrNil(when.statements); + final RubyNode thenNode = translateNodeOrNil(whenNode.statements); final IfElseNode ifNode = IfElseNodeGen.create(predicateNode, thenNode, elseNode); // this `if` becomes `else` branch of the outer `if` @@ -1837,7 +1826,7 @@ public RubyNode visitForwardingSuperNode(Nodes.ForwardingSuperNode node) { final RubyNode[] reloadSequence = reloadTranslator.reload(parametersNode); var descriptor = (parametersNode.keywords.length > 0 || parametersNode.keyword_rest != null) - ? KeywordArgumentsDescriptorManager.EMPTY + ? KeywordArgumentsDescriptor.EMPTY : NoKeywordArgumentsDescriptor.INSTANCE; final int restParamIndex = reloadTranslator.getRestParameterIndex(); final RubyNode arguments = new ReadZSuperArgumentsNode(restParamIndex, reloadSequence); diff --git a/src/main/java/org/truffleruby/parser/YARPTranslatorDriver.java b/src/main/java/org/truffleruby/parser/YARPTranslatorDriver.java index 1050699d525..604fee6115c 100644 --- a/src/main/java/org/truffleruby/parser/YARPTranslatorDriver.java +++ b/src/main/java/org/truffleruby/parser/YARPTranslatorDriver.java @@ -169,7 +169,7 @@ public RootCallTarget parse(RubySource rubySource, ParserContext parserContext, "parsing", source.getName(), () -> parseToYARPAST(rubySource, sourcePath, sourceBytes, localsInScopes, - language.options.FROZEN_STRING_LITERALS, options)); + language.options.FROZEN_STRING_LITERALS, options, parserContext)); printParseTranslateExecuteMetric("after-parsing", context, source); } @@ -341,7 +341,8 @@ private String getMethodName(ParserContext parserContext, MaterializedFrame pare } public static ParseResult parseToYARPAST(RubySource rubySource, String sourcePath, byte[] sourceBytes, - List> localsInScopes, boolean frozenStringLiteral, Options cliOptions) { + List> localsInScopes, boolean frozenStringLiteral, Options cliOptions, + ParserContext parserContext) { TruffleSafepoint.poll(DummyNode.INSTANCE); final byte[] filepath = sourcePath.getBytes(Encodings.FILESYSTEM_CHARSET); @@ -352,6 +353,8 @@ public static ParseResult parseToYARPAST(RubySource rubySource, String sourcePat // Magic comments are already detected and rubySource's encoding takes them into account, // but encodingLocked is intended for a niche use-case and is supposed to be false in all other cases. final boolean encodingLocked = false; + final boolean mainScript = parserContext == ParserContext.TOP_LEVEL_FIRST; + final boolean partialScript = false; // Prism handles command line options (-n, -l, -a, -p) on its own final EnumSet commandline; @@ -406,7 +409,7 @@ public static ParseResult parseToYARPAST(RubySource rubySource, String sourcePat } byte[] parsingOptions = ParsingOptions.serialize(filepath, line, encoding, frozenStringLiteral, commandline, - version, encodingLocked, scopes); + version, encodingLocked, mainScript, partialScript, scopes); byte[] serializedBytes = Parser.parseAndSerialize(sourceBytes, parsingOptions); return YARPLoader.load(serializedBytes, sourceBytes, rubySource); diff --git a/src/yarp/java/org/prism/Loader.java b/src/yarp/java/org/prism/Loader.java index 85172de2e7c..eac38b082df 100644 --- a/src/yarp/java/org/prism/Loader.java +++ b/src/yarp/java/org/prism/Loader.java @@ -102,7 +102,7 @@ protected ParseResult load() { expect((byte) 'M', "incorrect prism header"); expect((byte) 1, "prism major version does not match"); - expect((byte) 0, "prism minor version does not match"); + expect((byte) 1, "prism minor version does not match"); expect((byte) 0, "prism patch version does not match"); expect((byte) 1, "Loader.java requires no location fields in the serialized output"); @@ -126,16 +126,21 @@ protected ParseResult load() { int constantPoolLength = loadVarUInt(); this.constantPool = new ConstantPool(this, source.bytes, constantPoolBufferOffset, constantPoolLength); - Nodes.Node node = loadNode(); + Nodes.Node node; + if (errors.length == 0) { + node = loadNode(); - int left = constantPoolBufferOffset - buffer.position(); - if (left != 0) { - throw new Error("Expected to consume all bytes while deserializing but there were " + left + " bytes left"); - } + int left = constantPoolBufferOffset - buffer.position(); + if (left != 0) { + throw new Error("Expected to consume all bytes while deserializing but there were " + left + " bytes left"); + } - boolean[] newlineMarked = new boolean[1 + source.getLineCount()]; - MarkNewlinesVisitor visitor = new MarkNewlinesVisitor(source, newlineMarked); - node.accept(visitor); + boolean[] newlineMarked = new boolean[1 + source.getLineCount()]; + MarkNewlinesVisitor visitor = new MarkNewlinesVisitor(source, newlineMarked); + node.accept(visitor); + } else { + node = null; + } return new ParseResult(node, magicComments, dataLocation, errors, warnings, source); } @@ -211,7 +216,7 @@ private ParseResult.Warning[] loadWarnings() { // warning messages only contain ASCII characters for (int i = 0; i < count; i++) { - Nodes.WarningType type = Nodes.WARNING_TYPES[loadVarUInt() - 284]; + Nodes.WarningType type = Nodes.WARNING_TYPES[loadVarUInt() - 288]; byte[] bytes = loadEmbeddedString(); String message = new String(bytes, StandardCharsets.US_ASCII); Nodes.Location location = loadLocation(); @@ -401,11 +406,11 @@ private Nodes.Node loadNode() { case 22: return new Nodes.CallTargetNode(startOffset, length, loadFlags(), loadNode(), loadConstant()); case 23: - return new Nodes.CapturePatternNode(startOffset, length, loadNode(), loadNode()); + return new Nodes.CapturePatternNode(startOffset, length, loadNode(), (Nodes.LocalVariableTargetNode) loadNode()); case 24: - return new Nodes.CaseMatchNode(startOffset, length, loadOptionalNode(), loadNodes(), (Nodes.ElseNode) loadOptionalNode()); + return new Nodes.CaseMatchNode(startOffset, length, loadOptionalNode(), loadInNodes(), (Nodes.ElseNode) loadOptionalNode()); case 25: - return new Nodes.CaseNode(startOffset, length, loadOptionalNode(), loadNodes(), (Nodes.ElseNode) loadOptionalNode()); + return new Nodes.CaseNode(startOffset, length, loadOptionalNode(), loadWhenNodes(), (Nodes.ElseNode) loadOptionalNode()); case 26: return new Nodes.ClassNode(startOffset, length, loadConstants(), loadNode(), loadOptionalNode(), loadOptionalNode(), loadConstant()); case 27: @@ -459,7 +464,7 @@ private Nodes.Node loadNode() { case 51: return new Nodes.FalseNode(startOffset, length); case 52: - return new Nodes.FindPatternNode(startOffset, length, loadOptionalNode(), loadNode(), loadNodes(), loadNode()); + return new Nodes.FindPatternNode(startOffset, length, loadOptionalNode(), (Nodes.SplatNode) loadNode(), loadNodes(), (Nodes.SplatNode) loadNode()); case 53: return new Nodes.FlipFlopNode(startOffset, length, loadFlags(), loadOptionalNode(), loadOptionalNode()); case 54: @@ -499,13 +504,13 @@ private Nodes.Node loadNode() { case 71: return new Nodes.InNode(startOffset, length, loadNode(), (Nodes.StatementsNode) loadOptionalNode()); case 72: - return new Nodes.IndexAndWriteNode(startOffset, length, loadFlags(), loadOptionalNode(), (Nodes.ArgumentsNode) loadOptionalNode(), loadOptionalNode(), loadNode()); + return new Nodes.IndexAndWriteNode(startOffset, length, loadFlags(), loadOptionalNode(), (Nodes.ArgumentsNode) loadOptionalNode(), (Nodes.BlockArgumentNode) loadOptionalNode(), loadNode()); case 73: - return new Nodes.IndexOperatorWriteNode(startOffset, length, loadFlags(), loadOptionalNode(), (Nodes.ArgumentsNode) loadOptionalNode(), loadOptionalNode(), loadConstant(), loadNode()); + return new Nodes.IndexOperatorWriteNode(startOffset, length, loadFlags(), loadOptionalNode(), (Nodes.ArgumentsNode) loadOptionalNode(), (Nodes.BlockArgumentNode) loadOptionalNode(), loadConstant(), loadNode()); case 74: - return new Nodes.IndexOrWriteNode(startOffset, length, loadFlags(), loadOptionalNode(), (Nodes.ArgumentsNode) loadOptionalNode(), loadOptionalNode(), loadNode()); + return new Nodes.IndexOrWriteNode(startOffset, length, loadFlags(), loadOptionalNode(), (Nodes.ArgumentsNode) loadOptionalNode(), (Nodes.BlockArgumentNode) loadOptionalNode(), loadNode()); case 75: - return new Nodes.IndexTargetNode(startOffset, length, loadFlags(), loadNode(), (Nodes.ArgumentsNode) loadOptionalNode(), loadOptionalNode()); + return new Nodes.IndexTargetNode(startOffset, length, loadFlags(), loadNode(), (Nodes.ArgumentsNode) loadOptionalNode(), (Nodes.BlockArgumentNode) loadOptionalNode()); case 76: return new Nodes.InstanceVariableAndWriteNode(startOffset, length, loadConstant(), loadNode()); case 77: @@ -691,6 +696,34 @@ private Nodes.BlockLocalVariableNode[] loadBlockLocalVariableNodes() { return nodes; } + private static final Nodes.InNode[] EMPTY_InNode_ARRAY = {}; + + private Nodes.InNode[] loadInNodes() { + int length = loadVarUInt(); + if (length == 0) { + return EMPTY_InNode_ARRAY; + } + Nodes.InNode[] nodes = new Nodes.InNode[length]; + for (int i = 0; i < length; i++) { + nodes[i] = (Nodes.InNode) loadNode(); + } + return nodes; + } + + private static final Nodes.WhenNode[] EMPTY_WhenNode_ARRAY = {}; + + private Nodes.WhenNode[] loadWhenNodes() { + int length = loadVarUInt(); + if (length == 0) { + return EMPTY_WhenNode_ARRAY; + } + Nodes.WhenNode[] nodes = new Nodes.WhenNode[length]; + for (int i = 0; i < length; i++) { + nodes[i] = (Nodes.WhenNode) loadNode(); + } + return nodes; + } + private static final Nodes.AssocNode[] EMPTY_AssocNode_ARRAY = {}; private Nodes.AssocNode[] loadAssocNodes() { diff --git a/src/yarp/java/org/prism/Nodes.java b/src/yarp/java/org/prism/Nodes.java index 3f1805028d9..1725bfc3462 100644 --- a/src/yarp/java/org/prism/Nodes.java +++ b/src/yarp/java/org/prism/Nodes.java @@ -147,14 +147,24 @@ public String toString() { */ public static final class ArgumentsNodeFlags implements Comparable { - // if arguments contain keywords - public static final short CONTAINS_KEYWORDS = 1 << 2; + // if the arguments contain forwarding + public static final short CONTAINS_FORWARDING = 1 << 2; - // if arguments contain keyword splat - public static final short CONTAINS_KEYWORD_SPLAT = 1 << 3; + // if the arguments contain keywords + public static final short CONTAINS_KEYWORDS = 1 << 3; - // if arguments contain splat - public static final short CONTAINS_SPLAT = 1 << 4; + // if the arguments contain a keyword splat + public static final short CONTAINS_KEYWORD_SPLAT = 1 << 4; + + // if the arguments contain a splat + public static final short CONTAINS_SPLAT = 1 << 5; + + // if the arguments contain multiple splats + public static final short CONTAINS_MULTIPLE_SPLATS = 1 << 6; + + public static boolean isContainsForwarding(short flags) { + return (flags & CONTAINS_FORWARDING) != 0; + } public static boolean isContainsKeywords(short flags) { return (flags & CONTAINS_KEYWORDS) != 0; @@ -168,6 +178,10 @@ public static boolean isContainsSplat(short flags) { return (flags & CONTAINS_SPLAT) != 0; } + public static boolean isContainsMultipleSplats(short flags) { + return (flags & CONTAINS_MULTIPLE_SPLATS) != 0; + } + private final short flags; public ArgumentsNodeFlags(short flags) { @@ -193,6 +207,10 @@ public int compareTo(ArgumentsNodeFlags other) { return flags - other.flags; } + public boolean isContainsForwarding() { + return (flags & CONTAINS_FORWARDING) != 0; + } + public boolean isContainsKeywords() { return (flags & CONTAINS_KEYWORDS) != 0; } @@ -205,6 +223,10 @@ public boolean isContainsSplat() { return (flags & CONTAINS_SPLAT) != 0; } + public boolean isContainsMultipleSplats() { + return (flags & CONTAINS_MULTIPLE_SPLATS) != 0; + } + } /** @@ -1068,7 +1090,7 @@ public static final class AliasGlobalVariableNode extends Node { * ^^^^ * */ - @UnionType({ GlobalVariableReadNode.class, BackReferenceReadNode.class, NumberedReferenceReadNode.class, SymbolNode.class, MissingNode.class }) + @UnionType({ GlobalVariableReadNode.class, BackReferenceReadNode.class, NumberedReferenceReadNode.class }) public final Node old_name; public AliasGlobalVariableNode(int startOffset, int length, Node new_name, Node old_name) { @@ -1118,9 +1140,37 @@ protected String toString(String indent) { * */ public static final class AliasMethodNode extends Node { + /** + *
+         * Represents the new name of the method that will be aliased.
+         *
+         *     alias foo bar
+         *           ^^^
+         *
+         *     alias :foo :bar
+         *           ^^^^
+         *
+         *     alias :"#{foo}" :"#{bar}"
+         *           ^^^^^^^^^
+         * 
+ */ @UnionType({ SymbolNode.class, InterpolatedSymbolNode.class }) public final Node new_name; - @UnionType({ SymbolNode.class, InterpolatedSymbolNode.class, GlobalVariableReadNode.class, MissingNode.class }) + /** + *
+         * Represents the old name of the method that will be aliased.
+         *
+         *     alias foo bar
+         *               ^^^
+         *
+         *     alias :foo :bar
+         *                ^^^^
+         *
+         *     alias :"#{foo}" :"#{bar}"
+         *                     ^^^^^^^^^
+         * 
+ */ + @UnionType({ SymbolNode.class, InterpolatedSymbolNode.class }) public final Node old_name; public AliasMethodNode(int startOffset, int length, Node new_name, Node old_name) { @@ -1170,7 +1220,23 @@ protected String toString(String indent) { * */ public static final class AlternationPatternNode extends Node { + /** + *
+         * Represents the left side of the expression.
+         *
+         *     foo => bar | baz
+         *            ^^^
+         * 
+ */ public final Node left; + /** + *
+         * Represents the right side of the expression.
+         *
+         *     foo => bar | baz
+         *                  ^^^
+         * 
+ */ public final Node right; public AlternationPatternNode(int startOffset, int length, Node left, Node right) { @@ -1234,7 +1300,7 @@ public static final class AndNode extends Node { public final Node left; /** *
-         * Represents the right side of the expression. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
+         * Represents the right side of the expression.
          *
          *     left && right
          *             ^^^^^
@@ -1301,6 +1367,10 @@ public ArgumentsNode(int startOffset, int length, short flags, Node[] arguments)
             this.arguments = arguments;
         }
         
+        public boolean isContainsForwarding() {
+            return ArgumentsNodeFlags.isContainsForwarding(flags);
+        }
+
         public boolean isContainsKeywords() {
             return ArgumentsNodeFlags.isContainsKeywords(flags);
         }
@@ -1312,6 +1382,10 @@ public boolean isContainsKeywordSplat() {
         public boolean isContainsSplat() {
             return ArgumentsNodeFlags.isContainsSplat(flags);
         }
+
+        public boolean isContainsMultipleSplats() {
+            return ArgumentsNodeFlags.isContainsMultipleSplats(flags);
+        }
         
         public  void visitChildNodes(AbstractNodeVisitor visitor) {
             for (Nodes.Node child : this.arguments) {
@@ -1442,6 +1516,7 @@ protected String toString(String indent) {
      */
     public static final class ArrayPatternNode extends Node {
         @Nullable
+        @UnionType({ ConstantReadNode.class, ConstantPathNode.class })
         public final Node constant;
         public final Node[] requireds;
         @Nullable
@@ -2257,6 +2332,7 @@ public static final class CallNode extends Node {
         @Nullable
         public final ArgumentsNode arguments;
         @Nullable
+        @UnionType({ BlockNode.class, BlockArgumentNode.class })
         public final Node block;
 
         public CallNode(int startOffset, int length, short flags, Node receiver, String name, ArgumentsNode arguments, Node block) {
@@ -2604,9 +2680,9 @@ protected String toString(String indent) {
      */
     public static final class CapturePatternNode extends Node {
         public final Node value;
-        public final Node target;
+        public final LocalVariableTargetNode target;
 
-        public CapturePatternNode(int startOffset, int length, Node value, Node target) {
+        public CapturePatternNode(int startOffset, int length, Node value, LocalVariableTargetNode target) {
             super(startOffset, length);
             this.value = value;
             this.target = target;
@@ -2657,11 +2733,11 @@ protected String toString(String indent) {
     public static final class CaseMatchNode extends Node {
         @Nullable
         public final Node predicate;
-        public final Node[] conditions;
+        public final InNode[] conditions;
         @Nullable
         public final ElseNode else_clause;
 
-        public CaseMatchNode(int startOffset, int length, Node predicate, Node[] conditions, ElseNode else_clause) {
+        public CaseMatchNode(int startOffset, int length, Node predicate, InNode[] conditions, ElseNode else_clause) {
             super(startOffset, length);
             this.predicate = predicate;
             this.conditions = conditions;
@@ -2731,11 +2807,11 @@ protected String toString(String indent) {
     public static final class CaseNode extends Node {
         @Nullable
         public final Node predicate;
-        public final Node[] conditions;
+        public final WhenNode[] conditions;
         @Nullable
         public final ElseNode else_clause;
 
-        public CaseNode(int startOffset, int length, Node predicate, Node[] conditions, ElseNode else_clause) {
+        public CaseNode(int startOffset, int length, Node predicate, WhenNode[] conditions, ElseNode else_clause) {
             super(startOffset, length);
             this.predicate = predicate;
             this.conditions = conditions;
@@ -2802,10 +2878,12 @@ protected String toString(String indent) {
      */
     public static final class ClassNode extends Node {
         public final String[] locals;
+        @UnionType({ ConstantReadNode.class, ConstantPathNode.class })
         public final Node constant_path;
         @Nullable
         public final Node superclass;
         @Nullable
+        @UnionType({ StatementsNode.class, BeginNode.class })
         public final Node body;
         public final String name;
 
@@ -3890,6 +3968,7 @@ public static final class DefNode extends Node {
         @Nullable
         public final ParametersNode parameters;
         @Nullable
+        @UnionType({ StatementsNode.class, BeginNode.class })
         public final Node body;
         public final String[] locals;
 
@@ -4103,6 +4182,7 @@ protected String toString(String indent) {
      * 
*/ public static final class EmbeddedVariableNode extends Node { + @UnionType({ InstanceVariableReadNode.class, ClassVariableReadNode.class, GlobalVariableReadNode.class, BackReferenceReadNode.class, NumberedReferenceReadNode.class }) public final Node variable; public EmbeddedVariableNode(int startOffset, int length, Node variable) { @@ -4243,12 +4323,13 @@ protected String toString(String indent) { */ public static final class FindPatternNode extends Node { @Nullable + @UnionType({ ConstantReadNode.class, ConstantPathNode.class }) public final Node constant; - public final Node left; + public final SplatNode left; public final Node[] requireds; - public final Node right; + public final SplatNode right; - public FindPatternNode(int startOffset, int length, Node constant, Node left, Node[] requireds, Node right) { + public FindPatternNode(int startOffset, int length, Node constant, SplatNode left, Node[] requireds, SplatNode right) { super(startOffset, length); this.constant = constant; this.left = left; @@ -4441,6 +4522,7 @@ public static final class ForNode extends Node { * ^ * */ + @UnionType({ LocalVariableTargetNode.class, InstanceVariableTargetNode.class, ClassVariableTargetNode.class, GlobalVariableTargetNode.class, ConstantTargetNode.class, ConstantPathTargetNode.class, CallTargetNode.class, IndexTargetNode.class, MultiTargetNode.class }) public final Node index; /** *
@@ -5035,6 +5117,7 @@ protected String toString(String indent) {
      */
     public static final class HashPatternNode extends Node {
         @Nullable
+        @UnionType({ ConstantReadNode.class, ConstantPathNode.class })
         public final Node constant;
         public final AssocNode[] elements;
         @Nullable
@@ -5277,6 +5360,7 @@ protected String toString(String indent) {
      * 
*/ public static final class ImplicitNode extends Node { + @UnionType({ LocalVariableReadNode.class, CallNode.class, ConstantReadNode.class, LocalVariableTargetNode.class }) public final Node value; public ImplicitNode(int startOffset, int length, Node value) { @@ -5427,10 +5511,10 @@ public static final class IndexAndWriteNode extends Node { @Nullable public final ArgumentsNode arguments; @Nullable - public final Node block; + public final BlockArgumentNode block; public final Node value; - public IndexAndWriteNode(int startOffset, int length, short flags, Node receiver, ArgumentsNode arguments, Node block, Node value) { + public IndexAndWriteNode(int startOffset, int length, short flags, Node receiver, ArgumentsNode arguments, BlockArgumentNode block, Node value) { super(startOffset, length); this.flags = flags; this.receiver = receiver; @@ -5520,11 +5604,11 @@ public static final class IndexOperatorWriteNode extends Node { @Nullable public final ArgumentsNode arguments; @Nullable - public final Node block; + public final BlockArgumentNode block; public final String binary_operator; public final Node value; - public IndexOperatorWriteNode(int startOffset, int length, short flags, Node receiver, ArgumentsNode arguments, Node block, String binary_operator, Node value) { + public IndexOperatorWriteNode(int startOffset, int length, short flags, Node receiver, ArgumentsNode arguments, BlockArgumentNode block, String binary_operator, Node value) { super(startOffset, length); this.flags = flags; this.receiver = receiver; @@ -5619,10 +5703,10 @@ public static final class IndexOrWriteNode extends Node { @Nullable public final ArgumentsNode arguments; @Nullable - public final Node block; + public final BlockArgumentNode block; public final Node value; - public IndexOrWriteNode(int startOffset, int length, short flags, Node receiver, ArgumentsNode arguments, Node block, Node value) { + public IndexOrWriteNode(int startOffset, int length, short flags, Node receiver, ArgumentsNode arguments, BlockArgumentNode block, Node value) { super(startOffset, length); this.flags = flags; this.receiver = receiver; @@ -5719,9 +5803,9 @@ public static final class IndexTargetNode extends Node { @Nullable public final ArgumentsNode arguments; @Nullable - public final Node block; + public final BlockArgumentNode block; - public IndexTargetNode(int startOffset, int length, short flags, Node receiver, ArgumentsNode arguments, Node block) { + public IndexTargetNode(int startOffset, int length, short flags, Node receiver, ArgumentsNode arguments, BlockArgumentNode block) { super(startOffset, length); this.flags = flags; this.receiver = receiver; @@ -6808,8 +6892,10 @@ protected String toString(String indent) { public static final class LambdaNode extends Node { public final String[] locals; @Nullable + @UnionType({ BlockParametersNode.class, NumberedParametersNode.class, ItParametersNode.class }) public final Node parameters; @Nullable + @UnionType({ StatementsNode.class, BeginNode.class }) public final Node body; public LambdaNode(int startOffset, int length, String[] locals, Node parameters, Node body) { @@ -7549,8 +7635,10 @@ protected String toString(String indent) { */ public static final class ModuleNode extends Node { public final String[] locals; + @UnionType({ ConstantReadNode.class, ConstantPathNode.class }) public final Node constant_path; @Nullable + @UnionType({ StatementsNode.class, BeginNode.class }) public final Node body; public final String name; @@ -7634,7 +7722,7 @@ public static final class MultiTargetNode extends Node { * ^^^^ * */ - @UnionType({ LocalVariableTargetNode.class, InstanceVariableTargetNode.class, ClassVariableTargetNode.class, GlobalVariableTargetNode.class, ConstantTargetNode.class, ConstantPathTargetNode.class, CallTargetNode.class, IndexTargetNode.class, MultiTargetNode.class, RequiredParameterNode.class, BackReferenceReadNode.class, NumberedReferenceReadNode.class }) + @UnionType({ LocalVariableTargetNode.class, InstanceVariableTargetNode.class, ClassVariableTargetNode.class, GlobalVariableTargetNode.class, ConstantTargetNode.class, ConstantPathTargetNode.class, CallTargetNode.class, IndexTargetNode.class, MultiTargetNode.class, RequiredParameterNode.class }) public final Node[] lefts; /** *
@@ -7648,7 +7736,7 @@ public static final class MultiTargetNode extends Node {
          *     a, (b, *) = 1, 2, 3, 4
          *            ^
          *
-         * If the `*` is omitted, the field will containt an `ImplicitRestNode`
+         * If the `*` is omitted, this field will contain an `ImplicitRestNode`
          *
          *     a, (b,) = 1, 2, 3, 4
          *          ^
@@ -7665,7 +7753,7 @@ public static final class MultiTargetNode extends Node {
          *            ^^^^
          * 
*/ - @UnionType({ LocalVariableTargetNode.class, InstanceVariableTargetNode.class, ClassVariableTargetNode.class, GlobalVariableTargetNode.class, ConstantTargetNode.class, ConstantPathTargetNode.class, CallTargetNode.class, IndexTargetNode.class, MultiTargetNode.class, RequiredParameterNode.class, BackReferenceReadNode.class }) + @UnionType({ LocalVariableTargetNode.class, InstanceVariableTargetNode.class, ClassVariableTargetNode.class, GlobalVariableTargetNode.class, ConstantTargetNode.class, ConstantPathTargetNode.class, CallTargetNode.class, IndexTargetNode.class, MultiTargetNode.class, RequiredParameterNode.class }) public final Node[] rights; public MultiTargetNode(int startOffset, int length, Node[] lefts, Node rest, Node[] rights) { @@ -7764,7 +7852,7 @@ public static final class MultiWriteNode extends Node { * a, b, * = 1, 2, 3, 4 * ^ * - * If the `*` is omitted, the field will containt an `ImplicitRestNode` + * If the `*` is omitted, this field will contain an `ImplicitRestNode` * * a, b, = 1, 2, 3, 4 * ^ @@ -8227,7 +8315,7 @@ public static final class OrNode extends Node { public final Node left; /** *
-         * Represents the right side of the expression. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
+         * Represents the right side of the expression.
          *
          *     left || right
          *             ^^^^^
@@ -8292,7 +8380,7 @@ public static final class ParametersNode extends Node {
         @Nullable
         @UnionType({ RestParameterNode.class, ImplicitRestNode.class })
         public final Node rest;
-        @UnionType({ RequiredParameterNode.class, MultiTargetNode.class, KeywordRestParameterNode.class, NoKeywordsParameterNode.class, ForwardingParameterNode.class })
+        @UnionType({ RequiredParameterNode.class, MultiTargetNode.class })
         public final Node[] posts;
         @UnionType({ RequiredKeywordParameterNode.class, OptionalKeywordParameterNode.class })
         public final Node[] keywords;
@@ -8505,6 +8593,7 @@ protected String toString(String indent) {
      * 
*/ public static final class PinnedVariableNode extends Node { + @UnionType({ LocalVariableReadNode.class, InstanceVariableReadNode.class, ClassVariableReadNode.class, GlobalVariableReadNode.class, BackReferenceReadNode.class, NumberedReferenceReadNode.class, ItLocalVariableReadNode.class }) public final Node variable; public PinnedVariableNode(int startOffset, int length, Node variable) { @@ -9175,6 +9264,7 @@ protected String toString(String indent) { public static final class RescueNode extends Node { public final Node[] exceptions; @Nullable + @UnionType({ LocalVariableTargetNode.class, InstanceVariableTargetNode.class, ClassVariableTargetNode.class, GlobalVariableTargetNode.class, ConstantTargetNode.class, ConstantPathTargetNode.class, CallTargetNode.class, IndexTargetNode.class }) public final Node reference; @Nullable public final StatementsNode statements; @@ -9506,6 +9596,7 @@ public static final class SingletonClassNode extends Node { public final String[] locals; public final Node expression; @Nullable + @UnionType({ StatementsNode.class, BeginNode.class }) public final Node body; public SingletonClassNode(int startOffset, int length, String[] locals, Node expression, Node body) { @@ -9889,6 +9980,7 @@ public static final class SuperNode extends Node { @Nullable public final ArgumentsNode arguments; @Nullable + @UnionType({ BlockNode.class, BlockArgumentNode.class }) public final Node block; public SuperNode(int startOffset, int length, ArgumentsNode arguments, Node block) { @@ -10515,7 +10607,6 @@ public enum ErrorType { ARGUMENT_FORMAL_GLOBAL, ARGUMENT_FORMAL_IVAR, ARGUMENT_FORWARDING_UNBOUND, - ARGUMENT_IN, ARGUMENT_NO_FORWARDING_AMPERSAND, ARGUMENT_NO_FORWARDING_ELLIPSES, ARGUMENT_NO_FORWARDING_STAR, @@ -10599,6 +10690,7 @@ public enum ErrorType { EXPECT_EXPRESSION_AFTER_SPLAT, EXPECT_EXPRESSION_AFTER_SPLAT_HASH, EXPECT_EXPRESSION_AFTER_STAR, + EXPECT_FOR_DELIMITER, EXPECT_IDENT_REQ_PARAMETER, EXPECT_IN_DELIMITER, EXPECT_LPAREN_REQ_PARAMETER, @@ -10607,6 +10699,7 @@ public enum ErrorType { EXPECT_RPAREN, EXPECT_RPAREN_AFTER_MULTI, EXPECT_RPAREN_REQ_PARAMETER, + EXPECT_SINGLETON_CLASS_DELIMITER, EXPECT_STRING_CONTENT, EXPECT_WHEN_DELIMITER, EXPRESSION_BARE_HASH, @@ -10685,7 +10778,9 @@ public enum ErrorType { MODULE_TERM, MULTI_ASSIGN_MULTI_SPLATS, MULTI_ASSIGN_UNEXPECTED_REST, + NESTING_TOO_DEEP, NO_LOCAL_VARIABLE, + NON_ASSOCIATIVE_OPERATOR, NOT_EXPRESSION, NUMBER_LITERAL_UNDERSCORE, NUMBERED_PARAMETER_INNER_BLOCK, @@ -10771,6 +10866,7 @@ public enum ErrorType { UNEXPECTED_BLOCK_ARGUMENT, UNEXPECTED_INDEX_BLOCK, UNEXPECTED_INDEX_KEYWORDS, + UNEXPECTED_LABEL, UNEXPECTED_MULTI_WRITE, UNEXPECTED_RANGE_OPERATOR, UNEXPECTED_SAFE_NAVIGATION, diff --git a/src/yarp/java/org/prism/ParsingOptions.java b/src/yarp/java/org/prism/ParsingOptions.java index 330c2df449f..35a6a7b0c94 100644 --- a/src/yarp/java/org/prism/ParsingOptions.java +++ b/src/yarp/java/org/prism/ParsingOptions.java @@ -44,10 +44,12 @@ public enum CommandLine { A, E, L, N, P, X }; * @param commandLine the set of flags that were set on the command line * @param version code of Ruby version which syntax will be used to parse * @param encodingLocked whether the encoding is locked (should almost always be false) + * @param mainScript whether the file is the main script + * @param partialScript whether the file is a partial script * @param scopes scopes surrounding the code that is being parsed with local variable names defined in every scope * ordered from the outermost scope to the innermost one */ - public static byte[] serialize(byte[] filepath, int line, byte[] encoding, boolean frozenStringLiteral, EnumSet commandLine, SyntaxVersion version, boolean encodingLocked, byte[][][] scopes) { + public static byte[] serialize(byte[] filepath, int line, byte[] encoding, boolean frozenStringLiteral, EnumSet commandLine, SyntaxVersion version, boolean encodingLocked, boolean mainScript, boolean partialScript, byte[][][] scopes) { final ByteArrayOutputStream output = new ByteArrayOutputStream(); // filepath @@ -73,6 +75,12 @@ public static byte[] serialize(byte[] filepath, int line, byte[] encoding, boole // encodingLocked output.write(encodingLocked ? 1 : 0); + // mainScript + output.write(mainScript ? 1 : 0); + + // partialScript + output.write(partialScript ? 1 : 0); + // scopes // number of scopes