Skip to content

Macros: try call for unknown var #4927

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 5, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions src/compiler/crystal/macros.cr
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ module Crystal::Macros
end

# Outputs the current macro's buffer to the standard output. Useful for debugging
# a macro to see what's being generated. Use it like `{{debug()}}`, the parenthesis
# are mandatory.
# a macro to see what's being generated.
#
# By default, the output is tried to be formatted using Crystal's
# formatter, but you can disable this by passing `false` to this method.
Expand Down Expand Up @@ -107,7 +106,7 @@ module Crystal::Macros
#
# ```
# # sth_for_osx.cr
# {% skip() unless flag?(:darwin) %}
# {% skip unless flag?(:darwin) %}
#
# # Class FooForMac will only be defined if we're compiling on OS X
# class FooForMac
Expand Down
21 changes: 18 additions & 3 deletions src/compiler/crystal/macros/interpreter.cr
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,25 @@ module Crystal
def visit(node : Var)
var = @vars[node.name]?
if var
@last = var
else
node.raise "undefined macro variable '#{node.name}'"
return @last = var
end

# Try to consider the var as a top-level macro call.
#
# Note: this should really be done at the parser level. However,
# currently macro calls with blocks are possible, for example:
#
# some_macro_call do |arg|
# {{arg}}
# end
#
# and in this case the parser has no idea about this, so the only
# solution is to do it now.
if value = interpret_top_level_call?(Call.new(nil, node.name))
return @last = value
end

node.raise "undefined macro variable '#{node.name}'"
end

def visit(node : StringInterpolation)
Expand Down
7 changes: 6 additions & 1 deletion src/compiler/crystal/macros/methods.cr
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ require "semantic_version"
module Crystal
class MacroInterpreter
def interpret_top_level_call(node)
interpret_top_level_call?(node) ||
node.raise("undefined macro method: '#{node.name}'")
end

def interpret_top_level_call?(node)
# Please order method names in lexicographical order, because OCD
case node.name
when "compare_versions"
Expand All @@ -28,7 +33,7 @@ module Crystal
when "run"
interpret_run(node)
else
node.raise "undefined macro method: '#{node.name}'"
nil
end
end

Expand Down