Skip to content

Commit

Permalink
Compiler: let method_missing work with named arguments. Fixes #3654
Browse files Browse the repository at this point in the history
  • Loading branch information
asterite committed Dec 8, 2016
1 parent 8320e5e commit 8295d8c
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 1 deletion.
27 changes: 27 additions & 0 deletions spec/compiler/codegen/method_missing_spec.cr
Expand Up @@ -381,4 +381,31 @@ describe "Code gen: method_missing" do
Foo.new.bar
)).to_string.should eq("bar")
end

it "works with named arguments, using names (#3654)" do
run(%(
class A
macro method_missing(call)
x + y
end
end
a = A.new
a.b(x: 1, y: 2)
)).to_i.should eq(3)
end

it "works with named arguments, named args in call (#3654)" do
run(%(
class A
macro method_missing(call)
{{call.named_args[0].name}} +
{{call.named_args[1].name}}
end
end
a = A.new
a.b(x: 1, y: 2)
)).to_i.should eq(3)
end
end
15 changes: 14 additions & 1 deletion src/compiler/crystal/semantic/method_missing.cr
Expand Up @@ -38,12 +38,21 @@ module Crystal
def define_method_from_method_missing(method_missing, signature, original_call)
name_node = StringLiteral.new(signature.name)
args_nodes = [] of ASTNode
named_args_nodes = nil
args_nodes_names = Set(String).new
signature.arg_types.each_index do |index|
arg_node_name = "_arg#{index}"
args_nodes << MacroId.new(arg_node_name)
args_nodes_names << arg_node_name
end
if named_args = signature.named_args
args_nodes_names << ""
named_args.try &.each do |named_arg|
named_args_nodes ||= [] of NamedArgument
named_args_nodes << NamedArgument.new(named_arg.name, MacroId.new(named_arg.name))
args_nodes_names << named_arg.name
end
end
args_node = ArrayLiteral.new(args_nodes)
if block = signature.block
block_vars = block.args.map_with_index do |var, index|
Expand All @@ -57,8 +66,12 @@ module Crystal
end

a_def = Def.new(signature.name, args_nodes_names.map { |name| Arg.new(name) })
a_def.splat_index = signature.arg_types.size if signature.named_args

call = Call.new(nil, signature.name, args: args_nodes, block: block_node.is_a?(Block) ? block_node : nil)
call = Call.new(nil, signature.name,
args: args_nodes,
named_args: named_args_nodes,
block: block_node.is_a?(Block) ? block_node : nil)
fake_call = Call.new(nil, "method_missing", [call] of ASTNode)

expanded_macro = program.expand_macro method_missing, fake_call, self, self
Expand Down

0 comments on commit 8295d8c

Please sign in to comment.