Skip to content

Commit

Permalink
Support parsing for **nil args (#3412)
Browse files Browse the repository at this point in the history
* ruby27: Parse `**nil` arguments

This commit tracks upstream commit ruby/ruby@6a9ce1f.

Signed-off-by: Alexandre Terrasa <alexandre.terrasa@shopify.com>

* Skip **nil args when desugaring

Signed-off-by: Alexandre Terrasa <alexandre.terrasa@shopify.com>
  • Loading branch information
Morriar committed Sep 10, 2020
1 parent cce4349 commit b41bc21
Show file tree
Hide file tree
Showing 14 changed files with 196 additions and 0 deletions.
2 changes: 2 additions & 0 deletions ast/desugar/Desugar.cc
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ pair<MethodDef::ARGS_store, InsSeq::STATS_store> desugarArgs(DesugarContext dctx
unique_ptr<parser::Node> destructure =
make_unique<parser::Masgn>(arg->loc, std::move(arg), std::move(lvarNode));
destructures.emplace_back(node2TreeImpl(dctx, std::move(destructure)));
} else if (auto *lhs = parser::cast_node<parser::Kwnilarg>(arg.get())) {
// TODO implement logic for `**nil` args
} else {
args.emplace_back(node2TreeImpl(dctx, std::move(arg)));
}
Expand Down
10 changes: 10 additions & 0 deletions parser/Builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,10 @@ class Builder::Impl {
std::move(value));
}

unique_ptr<Node> kwnilarg(const token *dstar, const token *nil) {
return make_unique<Kwnilarg>(tokLoc(dstar).join(tokLoc(nil)));
}

unique_ptr<Node> kwrestarg(const token *dstar, const token *name) {
core::LocOffsets loc = tokLoc(dstar);
core::NameRef nm;
Expand Down Expand Up @@ -1547,6 +1551,11 @@ ForeignPtr kwoptarg(SelfPtr builder, const token *name, ForeignPtr value) {
return build->toForeign(build->kwoptarg(name, build->cast_node(value)));
}

ForeignPtr kwnilarg(SelfPtr builder, const token *dstar, const token *nil) {
auto build = cast_builder(builder);
return build->toForeign(build->kwnilarg(dstar, nil));
}

ForeignPtr kwrestarg(SelfPtr builder, const token *dstar, const token *name) {
auto build = cast_builder(builder);
return build->toForeign(build->kwrestarg(dstar, name));
Expand Down Expand Up @@ -1879,6 +1888,7 @@ struct ruby_parser::builder Builder::interface = {
keywordZsuper,
kwarg,
kwoptarg,
kwnilarg,
kwrestarg,
kwsplat,
line_literal,
Expand Down
6 changes: 6 additions & 0 deletions parser/tools/generate_ast.cc
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,12 @@ NodeDef nodes[] = {
"kwarg",
vector<FieldDef>({{"name", FieldType::Name}}),
},
// Keyword nil argument
{
"Kwnilarg",
"kwnilarg",
vector<FieldDef>(),
},
// explicit `begin` keyword.
// `kwbegin` is emitted _only_ for post-while and post-until loops
// because they act differently
Expand Down
122 changes: 122 additions & 0 deletions test/testdata/parser/kwnil.parse-tree.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
Begin {
stmts = [
DefMethod {
name = <U f1>
args = Args {
args = [
Kwnilarg {
}
]
}
body = NULL
}
DefMethod {
name = <U f2>
args = Args {
args = [
Restarg {
name = <U args>
}
Kwnilarg {
}
]
}
body = NULL
}
DefMethod {
name = <U f3>
args = Args {
args = [
Arg {
name = <U a>
}
Arg {
name = <U b>
}
Arg {
name = <U c>
}
Kwnilarg {
}
]
}
body = NULL
}
DefMethod {
name = <U f4>
args = Args {
args = [
Arg {
name = <U a>
}
Arg {
name = <U b>
}
Restarg {
name = <U c>
}
Kwnilarg {
}
]
}
body = NULL
}
DefMethod {
name = <U f5>
args = Args {
args = [
Kwnilarg {
}
Blockarg {
name = <U blk>
}
]
}
body = NULL
}
DefMethod {
name = <U f6>
args = Args {
args = [
Arg {
name = <U a>
}
Arg {
name = <U b>
}
Arg {
name = <U c>
}
Kwnilarg {
}
Blockarg {
name = <U blk>
}
]
}
body = NULL
}
DefMethod {
name = <U f7>
args = Args {
args = [
Arg {
name = <U a>
}
Arg {
name = <U b>
}
Restarg {
name = <U c>
}
Kwnilarg {
}
Blockarg {
name = <U blk>
}
]
}
body = NULL
}
]
}
9 changes: 9 additions & 0 deletions test/testdata/parser/kwnil.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# typed: true

def f1(**nil); end
def f2(*args, **nil); end
def f3(a, b, c, **nil); end
def f4(a, b, *c, **nil); end
def f5(**nil, &blk); end
def f6(a, b, c, **nil, &blk); end
def f7(a, b, *c, **nil, &blk); end
7 changes: 7 additions & 0 deletions test/testdata/parser/kwnil_errors.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# typed: true

def f1(**nil, **nil); end # error: unexpected token "**"
def f2(*args, **kwargs, **nil); end # error: unexpected token "**"
def f3(*args, a:, **nil); end # error: unexpected token "nil"
def f4(a:, **nil); end # error: unexpected token "nil"
def f5(**nil: 10); end # error: unexpected token tLABEL
3 changes: 3 additions & 0 deletions test/whitequark/test_kwnilarg_0.parse-tree-whitequark.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
s(:def, :f,
s(:args,
s(:kwnilarg)), nil)
3 changes: 3 additions & 0 deletions test/whitequark/test_kwnilarg_0.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# typed: true

def f(**nil); end
4 changes: 4 additions & 0 deletions test/whitequark/test_kwnilarg_1.parse-tree-whitequark.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
s(:block,
s(:send, nil, :m),
s(:args,
s(:kwnilarg)), nil)
3 changes: 3 additions & 0 deletions test/whitequark/test_kwnilarg_1.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# typed: true

m { |**nil| }
5 changes: 5 additions & 0 deletions test/whitequark/test_kwnilarg_2.parse-tree-whitequark.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
s(:block,
s(:send,
s(:const, nil, :Kernel), :lambda),
s(:args,
s(:kwnilarg)), nil)
3 changes: 3 additions & 0 deletions test/whitequark/test_kwnilarg_2.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# typed: true

->(**nil) {}
18 changes: 18 additions & 0 deletions third_party/parser/cc/grammars/typedruby.ypp
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ using namespace std::string_literals;
f_marg_list
f_margs
f_optarg
f_no_kwarg
f_rest_arg
list_none
mlhs_basic
Expand Down Expand Up @@ -1784,6 +1785,12 @@ int yylex(parser::semantic_type *lval, ruby_parser::typedruby27 &driver) {
args->concat($2);
$$ = args;
}
| f_no_kwarg opt_f_block_arg
{
auto &args = $1;
args->concat($2);
$$ = args;
}
| f_block_arg
{
$$ = $1;
Expand Down Expand Up @@ -2605,6 +2612,12 @@ keyword_variable: kNIL
args->concat($2);
$$ = args;
}
| f_no_kwarg opt_f_block_arg
{
auto &args = $1;
args->concat($2);
$$ = args;
}
| f_block_arg
{
$$ = $1;
Expand Down Expand Up @@ -2835,6 +2848,11 @@ keyword_variable: kNIL

kwrest_mark: tPOW | tDSTAR

f_no_kwarg: kwrest_mark kNIL
{
$$ = driver.alloc.node_list(driver.build.kwnilarg(self, $1, $2));
}

f_kwrest: kwrest_mark tIDENTIFIER
{
auto ident = $2;
Expand Down
1 change: 1 addition & 0 deletions third_party/parser/include/ruby_parser/builder.hh
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ struct builder {
ForeignPtr(*keywordZsuper)(SelfPtr builder, const token* keyword);
ForeignPtr(*kwarg)(SelfPtr builder, const token* name);
ForeignPtr(*kwoptarg)(SelfPtr builder, const token* name, ForeignPtr value);
ForeignPtr(*kwnilarg)(SelfPtr builder, const token* dstar, const token* nil);
ForeignPtr(*kwrestarg)(SelfPtr builder, const token* dstar, const token* name);
ForeignPtr(*kwsplat)(SelfPtr builder, const token* dstar, ForeignPtr arg);
ForeignPtr(*line_literal)(SelfPtr builder, const token* tok);
Expand Down

0 comments on commit b41bc21

Please sign in to comment.