diff --git a/bin/prism b/bin/prism index dbd0ddb174..ddf06a6d2a 100755 --- a/bin/prism +++ b/bin/prism @@ -166,7 +166,6 @@ module Prism source, filepath = read_source(argv) result = Prism.parse(source) - if result.errors.any? puts result.errors_format else diff --git a/config.yml b/config.yml index 0736f5a0bf..7527e01070 100644 --- a/config.yml +++ b/config.yml @@ -4065,6 +4065,9 @@ nodes: - on error: NoKeywordsParameterNode # On parsing error of `f(..., ...)`, the first forwarding parameter is moved here: - on error: ForwardingParameterNode + # On parsing error of `f(&nil, &foo)`/`f(&foo, &nil)`, the first forwarding parameter is moved here: + - on error: BlockParameterNode + - on error: NoBlockParameterNode - name: keywords type: node[] kind: diff --git a/lib/prism/node_ext.rb b/lib/prism/node_ext.rb index 1bb3ebcf5f..a05123d1bb 100644 --- a/lib/prism/node_ext.rb +++ b/lib/prism/node_ext.rb @@ -286,7 +286,9 @@ def signature case param when MultiTargetNode names << [:req] - when NoKeywordsParameterNode, KeywordRestParameterNode, ForwardingParameterNode + when NoKeywordsParameterNode, KeywordRestParameterNode, + NoBlockParameterNode, BlockParameterNode, + ForwardingParameterNode # Invalid syntax, e.g. "def f(**nil, ...)" moves the NoKeywordsParameterNode to posts raise "Invalid syntax" else diff --git a/snapshots/4.1/noblock.txt b/snapshots/4.1/noblock.txt new file mode 100644 index 0000000000..ce2827c24f --- /dev/null +++ b/snapshots/4.1/noblock.txt @@ -0,0 +1,61 @@ +@ ProgramNode (location: (1,0)-(4,12)) +├── flags: ∅ +├── locals: [] +└── statements: + @ StatementsNode (location: (1,0)-(4,12)) + ├── flags: ∅ + └── body: (length: 2) + ├── @ DefNode (location: (1,0)-(2,3)) + │ ├── flags: newline + │ ├── name: :foo + │ ├── name_loc: (1,4)-(1,7) = "foo" + │ ├── receiver: ∅ + │ ├── parameters: + │ │ @ ParametersNode (location: (1,8)-(1,12)) + │ │ ├── flags: ∅ + │ │ ├── requireds: (length: 0) + │ │ ├── optionals: (length: 0) + │ │ ├── rest: ∅ + │ │ ├── posts: (length: 0) + │ │ ├── keywords: (length: 0) + │ │ ├── keyword_rest: ∅ + │ │ └── block: + │ │ @ NoBlockParameterNode (location: (1,8)-(1,12)) + │ │ ├── flags: ∅ + │ │ ├── operator_loc: (1,8)-(1,9) = "&" + │ │ └── keyword_loc: (1,9)-(1,12) = "nil" + │ ├── body: ∅ + │ ├── locals: [] + │ ├── def_keyword_loc: (1,0)-(1,3) = "def" + │ ├── operator_loc: ∅ + │ ├── lparen_loc: (1,7)-(1,8) = "(" + │ ├── rparen_loc: (1,12)-(1,13) = ")" + │ ├── equal_loc: ∅ + │ └── end_keyword_loc: (2,0)-(2,3) = "end" + └── @ LambdaNode (location: (4,0)-(4,12)) + ├── flags: newline + ├── locals: [] + ├── operator_loc: (4,0)-(4,2) = "->" + ├── opening_loc: (4,10)-(4,11) = "{" + ├── closing_loc: (4,11)-(4,12) = "}" + ├── parameters: + │ @ BlockParametersNode (location: (4,3)-(4,9)) + │ ├── flags: ∅ + │ ├── parameters: + │ │ @ ParametersNode (location: (4,4)-(4,8)) + │ │ ├── flags: ∅ + │ │ ├── requireds: (length: 0) + │ │ ├── optionals: (length: 0) + │ │ ├── rest: ∅ + │ │ ├── posts: (length: 0) + │ │ ├── keywords: (length: 0) + │ │ ├── keyword_rest: ∅ + │ │ └── block: + │ │ @ NoBlockParameterNode (location: (4,4)-(4,8)) + │ │ ├── flags: ∅ + │ │ ├── operator_loc: (4,4)-(4,5) = "&" + │ │ └── keyword_loc: (4,5)-(4,8) = "nil" + │ ├── locals: (length: 0) + │ ├── opening_loc: (4,3)-(4,4) = "(" + │ └── closing_loc: (4,8)-(4,9) = ")" + └── body: ∅ diff --git a/src/prism.c b/src/prism.c index 81768024f2..56cb9e3fb3 100644 --- a/src/prism.c +++ b/src/prism.c @@ -13949,7 +13949,7 @@ parse_parameters( pm_token_t operator = parser->previous; pm_node_t *param; - if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) { + if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1 && accept1(parser, PM_TOKEN_KEYWORD_NIL)) { param = (pm_node_t *) pm_no_block_parameter_node_create(parser, &operator, &parser->previous); } else { pm_token_t name = {0}; diff --git a/test/prism/errors/3.3-4.0/noblock.txt b/test/prism/errors/3.3-4.0/noblock.txt new file mode 100644 index 0000000000..07939041bb --- /dev/null +++ b/test/prism/errors/3.3-4.0/noblock.txt @@ -0,0 +1,6 @@ +def foo(&nil) + ^~~ unexpected 'nil'; expected a `)` to close the parameters + ^ unexpected ')', expecting end-of-input + ^ unexpected ')', ignoring it +end + diff --git a/test/prism/errors/4.1/multiple_blocks.txt b/test/prism/errors/4.1/multiple_blocks.txt new file mode 100644 index 0000000000..7e8433cf82 --- /dev/null +++ b/test/prism/errors/4.1/multiple_blocks.txt @@ -0,0 +1,12 @@ +def foo(&nil, &nil); end + ^ unexpected parameter order + ^~~~ multiple block parameters; only one block is allowed + +def foo(&foo, &nil); end + ^ unexpected parameter order + ^~~~ multiple block parameters; only one block is allowed + +def foo(&nil, &foo); end + ^ unexpected parameter order + ^~~~ multiple block parameters; only one block is allowed + diff --git a/test/prism/fixtures/4.1/noblock.txt b/test/prism/fixtures/4.1/noblock.txt new file mode 100644 index 0000000000..2395393e22 --- /dev/null +++ b/test/prism/fixtures/4.1/noblock.txt @@ -0,0 +1,4 @@ +def foo(&nil) +end + +-> (&nil) {} diff --git a/test/prism/locals_test.rb b/test/prism/locals_test.rb index 4844901804..bcb964aff6 100644 --- a/test/prism/locals_test.rb +++ b/test/prism/locals_test.rb @@ -30,7 +30,7 @@ class LocalsTest < TestCase "command_method_call_2.txt", # https://bugs.ruby-lang.org/issues/21669 - "4.1/void_value.txt" + "4.1/void_value.txt", ] Fixture.each_for_current_ruby(except: except) do |fixture| @@ -207,7 +207,7 @@ def prism_locals(source) end end - if params.block + if params.block.is_a?(BlockParameterNode) sorted << (params.block.name || :&) end diff --git a/test/prism/ruby/ripper_test.rb b/test/prism/ruby/ripper_test.rb index 39cb9395ab..00cf470e0e 100644 --- a/test/prism/ruby/ripper_test.rb +++ b/test/prism/ruby/ripper_test.rb @@ -40,6 +40,9 @@ class RipperTest < TestCase # https://bugs.ruby-lang.org/issues/21669 incorrect << "4.1/void_value.txt" + # https://bugs.ruby-lang.org/issues/19979 + incorrect << "4.1/noblock.txt" + # Skip these tests that we haven't implemented yet. omitted_sexp_raw = [ "bom_leading_space.txt",