Skip to content

Commit

Permalink
Added @def inside macros that takes the value of the current method.
Browse files Browse the repository at this point in the history
…Fixes #1582
  • Loading branch information
asterite committed Nov 17, 2016
1 parent f2854ea commit df20bdc
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 11 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* Added support for AArch64 (thanks @ysbaddaden)
* Added support for LLVM 3.9 (thanks @ysbaddaden)
* Added `__END_LINE__` magic constant in method default arguments: will be the last line of a call (if the call has a block, it will be the last line of that block)
* Added `@def` inside macros that takes the value of the current method
* API docs have a nicer style now (thanks @samueleaton)
* Slight improvement to debugging support (thanks @ggiraldez)
* Added iteration times to `Benchmark.ips` (thanks @RX14)
Expand Down
24 changes: 24 additions & 0 deletions spec/compiler/codegen/macro_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -1466,4 +1466,28 @@ describe "Code gen: macro" do
Foo.x
), inject_primitives: false).to_i.should eq(1)
end

it "expands @def in inline macro" do
run(%(
def foo
{{@def.name.stringify}}
end
foo
)).to_string.should eq("foo")
end

it "expands @def in macro" do
run(%(
macro foo
{{@def.name.stringify}}
end
def bar
foo
end
bar
)).to_string.should eq("bar")
end
end
12 changes: 7 additions & 5 deletions src/compiler/crystal/macros/interpreter.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module Crystal
getter last : ASTNode
property free_vars : Hash(String, TypeVar)?

def self.new(program, scope : Type, path_lookup : Type, a_macro : Macro, call)
def self.new(program, scope : Type, path_lookup : Type, a_macro : Macro, call, a_def : Def? = nil)
vars = {} of String => ASTNode
splat_index = a_macro.splat_index
double_splat = a_macro.double_splat
Expand Down Expand Up @@ -68,14 +68,14 @@ module Crystal
vars[macro_block_arg.name] = call_block || Nop.new
end

new(program, scope, path_lookup, a_macro.location, vars, call.block)
new(program, scope, path_lookup, a_macro.location, vars, call.block, a_def)
end

record MacroVarKey, name : String, exps : Array(ASTNode)?

def initialize(@program : Program,
@scope : Type, @path_lookup : Type, @location : Location?,
@vars = {} of String => ASTNode, @block : Block? = nil)
@vars = {} of String => ASTNode, @block : Block? = nil, @def : Def? = nil)
@str = MemoryIO.new(512) # Can't be String::Builder because of `{{debug()}}
@last = Nop.new
end
Expand Down Expand Up @@ -397,8 +397,8 @@ module Crystal
produce_tuple = node.names.first == "T"
when GenericInstanceType
produce_tuple = ((splat_index = path_lookup.splat_index) &&
path_lookup.type_vars.keys.index(node.names.first) == splat_index) ||
(path_lookup.double_variadic? && path_lookup.type_vars.first_key == node.names.first)
path_lookup.type_vars.keys.index(node.names.first) == splat_index) ||
(path_lookup.double_variadic? && path_lookup.type_vars.first_key == node.names.first)
else
produce_tuple = false
end
Expand Down Expand Up @@ -444,6 +444,8 @@ module Crystal
when "@type"
target = @scope == @program.class_type ? @scope : @scope.instance_type
return @last = TypeNode.new(target)
when "@def"
return @last = @def || NilLiteral.new
end

node.raise "unknown macro instance var: '#{node.name}'"
Expand Down
8 changes: 4 additions & 4 deletions src/compiler/crystal/macros/macros.cr
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@ class Crystal::Program
filename
end

def expand_macro(a_macro : Macro, call : Call, scope : Type, path_lookup : Type? = nil)
interpreter = MacroInterpreter.new self, scope, path_lookup || scope, a_macro, call
def expand_macro(a_macro : Macro, call : Call, scope : Type, path_lookup : Type? = nil, a_def : Def? = nil)
interpreter = MacroInterpreter.new self, scope, path_lookup || scope, a_macro, call, a_def
a_macro.body.accept interpreter
interpreter.to_s
end

def expand_macro(node : ASTNode, scope : Type, path_lookup : Type? = nil, free_vars = nil)
interpreter = MacroInterpreter.new self, scope, path_lookup || scope, node.location
def expand_macro(node : ASTNode, scope : Type, path_lookup : Type? = nil, free_vars = nil, a_def : Def? = nil)
interpreter = MacroInterpreter.new self, scope, path_lookup || scope, node.location, def: a_def
interpreter.free_vars = free_vars
node.accept interpreter
interpreter.to_s
Expand Down
5 changes: 3 additions & 2 deletions src/compiler/crystal/semantic/semantic_visitor.cr
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ abstract class Crystal::SemanticVisitor < Crystal::Visitor

@free_vars : Hash(String, TypeVar)?
@path_lookup : Type?
@untyped_def : Def?
@typed_def : Def?
@block : Block?

Expand Down Expand Up @@ -263,7 +264,7 @@ abstract class Crystal::SemanticVisitor < Crystal::Visitor
generated_nodes = expand_macro(the_macro, node) do
old_args = node.args
node.args = args
expanded = @program.expand_macro the_macro, node, expansion_scope, @path_lookup
expanded = @program.expand_macro the_macro, node, expansion_scope, @path_lookup, @untyped_def
node.args = old_args
expanded
end
Expand Down Expand Up @@ -363,7 +364,7 @@ abstract class Crystal::SemanticVisitor < Crystal::Visitor
the_macro = Macro.new("macro_#{node.object_id}", [] of Arg, node).at(node.location)

generated_nodes = expand_macro(the_macro, node, mode: mode) do
@program.expand_macro node, (@scope || current_type), @path_lookup, @free_vars
@program.expand_macro node, (@scope || current_type), @path_lookup, @free_vars, @untyped_def
end

node.expanded = generated_nodes
Expand Down

0 comments on commit df20bdc

Please sign in to comment.