Skip to content

Commit

Permalink
Merge pull request #2392 from crystal-lang/feature/macro_args_expansion
Browse files Browse the repository at this point in the history
Expand macro expressions arguments before macro calls. Fixes #2388
  • Loading branch information
asterite committed Apr 1, 2016
2 parents 18749c3 + 956d5a1 commit cc9488d
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 3 deletions.
22 changes: 22 additions & 0 deletions spec/compiler/codegen/macro_spec.cr
Expand Up @@ -1269,4 +1269,26 @@ describe "Code gen: macro" do
id(A)
)).to_i.should eq(1)
end

it "solves macro expression arguments before macro expansion (type)" do
run(%(
macro name(x)
{{x.name.stringify}}
end
name({{String}})
)).to_string.should eq("String")
end

it "solves macro expression arguments before macro expansion (constant)" do
run(%(
CONST = 1
macro id(x)
{{x}}
end
id({{CONST}})
)).to_i.should eq(1)
end
end
41 changes: 38 additions & 3 deletions src/compiler/crystal/semantic/base_type_visitor.cr
Expand Up @@ -496,12 +496,18 @@ module Crystal
node.raise "macro '#{node.name}' must be defined before this point but is defined later"
end

@exp_nest -= 1
expansion_scope = (macro_scope || @scope || current_type)

args = expand_macro_arguments(node, expansion_scope)

@exp_nest -= 1
generated_nodes = expand_macro(the_macro, node) do
@mod.expand_macro the_macro, node, (macro_scope || @scope || current_type)
old_args = node.args
node.args = args
expanded = @mod.expand_macro the_macro, node, expansion_scope
node.args = old_args
expanded
end

@exp_nest += 1

node.expanded = generated_nodes
Expand Down Expand Up @@ -531,6 +537,35 @@ module Crystal
generated_nodes
end

def expand_macro_arguments(node, expansion_scope)
# If any argument is a MacroExpression, solve it first and
# replace Path with Const/TypeNode if it denotes such thing
args = node.args
if args.any? &.is_a?(MacroExpression)
@exp_nest -= 1
args = args.map do |arg|
if arg.is_a?(MacroExpression)
arg.accept self
expanded = arg.expanded.not_nil!
if expanded.is_a?(Path)
expanded_type = expansion_scope.lookup_type(expanded)
case expanded_type
when Const
expanded = expanded_type.value
when Type
expanded = TypeNode.new(expanded_type)
end
end
expanded
else
arg
end
end
@exp_nest += 1
end
args
end

def visit(node : MacroExpression)
expand_inline_macro node
end
Expand Down

0 comments on commit cc9488d

Please sign in to comment.