From 46e57a27468bfdf88cc33c1fa1f598b7e2d799c4 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Thu, 31 Mar 2016 16:14:02 -0300 Subject: [PATCH] Added `Path#resolve` macro method. Related to #2388 --- docs/macros.cr | 11 ++++++++--- spec/compiler/codegen/macro_spec.cr | 12 ++++++++++++ src/compiler/crystal/macros/macros.cr | 13 ++++++++----- src/compiler/crystal/macros/methods.cr | 9 +++++++++ 4 files changed, 37 insertions(+), 8 deletions(-) diff --git a/docs/macros.cr b/docs/macros.cr index 58076a5d446b..b3f876b49916 100644 --- a/docs/macros.cr +++ b/docs/macros.cr @@ -785,9 +785,14 @@ module Macros # class ImplicitObj < ASTNode # end - # A Path to a constant, like `Foo` or `Foo::Bar::Baz`. - # class Path < ASTNode - # end + # A Path to a constant or type, like `Foo` or `Foo::Bar::Baz`. + class Path < ASTNode + # Resolves this path to a `TypeNode` if it denotes a type, to + # the value of a constant if it denotes a constant, or otherwise + # gives a compile-time error. + def resolve : ASTNode + end + end # A class definition. # class ClassDef < ASTNode diff --git a/spec/compiler/codegen/macro_spec.cr b/spec/compiler/codegen/macro_spec.cr index 9ddbcc74366e..e1c439635b36 100644 --- a/spec/compiler/codegen/macro_spec.cr +++ b/spec/compiler/codegen/macro_spec.cr @@ -1257,4 +1257,16 @@ describe "Code gen: macro" do x.foo )).to_i.should eq(1) end + + it "expands Path with resolve method" do + run(%( + A = 1 + + macro id(path) + {{path.resolve}} + end + + id(A) + )).to_i.should eq(1) + end end diff --git a/src/compiler/crystal/macros/macros.cr b/src/compiler/crystal/macros/macros.cr index 53ffb4db9b3d..123f2113291d 100644 --- a/src/compiler/crystal/macros/macros.cr +++ b/src/compiler/crystal/macros/macros.cr @@ -490,6 +490,11 @@ module Crystal end def visit(node : Path) + @last = resolve(node) + false + end + + def resolve(node : Path) if node.names.size == 1 && (match = @free_vars.try &.[node.names.first]) matched_type = match else @@ -502,16 +507,14 @@ module Crystal case matched_type when Const - @last = matched_type.value + matched_type.value when Type - @last = TypeNode.new(matched_type) + TypeNode.new(matched_type) when ASTNode - @last = matched_type + matched_type else node.raise "can't interpret #{node}" end - - false end def visit(node : Splat) diff --git a/src/compiler/crystal/macros/methods.cr b/src/compiler/crystal/macros/methods.cr index d295761eb016..55ed525ccb01 100644 --- a/src/compiler/crystal/macros/methods.cr +++ b/src/compiler/crystal/macros/methods.cr @@ -1016,6 +1016,15 @@ module Crystal end class Path + def interpret(method, args, block, interpreter) + case method + when "resolve" + interpret_argless_method(method, args) { interpreter.resolve(self) } + else + super + end + end + def to_macro_id @names.join "::" end