Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: crystal-lang/crystal
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 5c60ae236a13
Choose a base ref
...
head repository: crystal-lang/crystal
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 8bc0dbc76fea
Choose a head ref
  • 5 commits
  • 3 files changed
  • 2 contributors

Commits on Oct 29, 2017

  1. Copy the full SHA
    2739f90 View commit details

Commits on Oct 30, 2017

  1. Copy the full SHA
    792deb2 View commit details

Commits on Oct 31, 2017

  1. Copy the full SHA
    9b1a9e7 View commit details

Commits on Nov 1, 2017

  1. Add macro method to proc pointer

    Also add documentation to proc literal and proc notation macro methods
    willhbr committed Nov 1, 2017
    Copy the full SHA
    36c1f75 View commit details

Commits on Jan 3, 2018

  1. Copy the full SHA
    8bc0dbc View commit details
Showing with 128 additions and 6 deletions.
  1. +50 −0 spec/compiler/macro/macro_methods_spec.cr
  2. +39 −6 src/compiler/crystal/macros.cr
  3. +39 −0 src/compiler/crystal/macros/methods.cr
50 changes: 50 additions & 0 deletions spec/compiler/macro/macro_methods_spec.cr
Original file line number Diff line number Diff line change
@@ -1205,6 +1205,56 @@ describe "macro methods" do
end
end

describe "proc notation methods" do
it "gets single input" do
assert_macro "x", %({{x.inputs}}), [ProcNotation.new([Path.new("SomeType")] of ASTNode, Path.new("SomeResult"))] of ASTNode, "[SomeType]"
end

it "gets single output" do
assert_macro "x", %({{x.output}}), [ProcNotation.new([Path.new("SomeType")] of ASTNode, Path.new("SomeResult"))] of ASTNode, "SomeResult"
end

it "gets multiple inputs" do
assert_macro "x", %({{x.inputs}}), [ProcNotation.new([Path.new("SomeType"), Path.new("OtherType")] of ASTNode)] of ASTNode, "[SomeType, OtherType]"
end

it "gets empty output" do
assert_macro "x", %({{x.output}}), [ProcNotation.new([Path.new("SomeType")] of ASTNode)] of ASTNode, "nil"
end
end

describe "proc literal methods" do
it "executes body" do
assert_macro "x", %({{x.body}}), [ProcLiteral.new(Def.new("->", body: 1.int32))] of ASTNode, "1"
end

it "executes args" do
assert_macro "x", %({{x.args}}), [ProcLiteral.new(Def.new("->", args: [Arg.new("z")]))] of ASTNode, "[z]"
end
end

describe "proc pointer methods" do
it "executes obj when present" do
assert_macro "x", %({{x.obj}}), [ProcPointer.new(Var.new("some_object"), "method", [] of ASTNode)] of ASTNode, "some_object"
end

it "executes obj when absent" do
assert_macro "x", %({{x.obj}}), [ProcPointer.new(NilLiteral.new, "method", [] of ASTNode)] of ASTNode, "nil"
end

it "executes name" do
assert_macro "x", %({{x.name}}), [ProcPointer.new(Var.new("some_object"), "method", [] of ASTNode)] of ASTNode, "method"
end

it "executes args when empty" do
assert_macro "x", %({{x.args}}), [ProcPointer.new(Var.new("some_object"), "method", [] of ASTNode)] of ASTNode, "[]"
end

it "executes args when not empty" do
assert_macro "x", %({{x.args}}), [ProcPointer.new(Var.new("some_object"), "method", [Path.new("SomeType"), Path.new("OtherType")] of ASTNode)] of ASTNode, "[SomeType, OtherType]"
end
end

describe "def methods" do
it "executes name" do
assert_macro "x", %({{x.name}}), [Def.new("some_def")] of ASTNode, "some_def"
45 changes: 39 additions & 6 deletions src/compiler/crystal/macros.cr
Original file line number Diff line number Diff line change
@@ -965,8 +965,16 @@ module Crystal::Macros
end
end

# class ProcNotation < ASTNode
# end
# The type of a proc or block argument, like `String -> Int32`.
class ProcNotation < ASTNode
# Returns the argument types, or an empty list if no arguments.
def inputs : ArrayLiteral(ASTNode)
end

# Returns the output type, or nil if there is no return type.
def output : ASTNode | NilLiteral
end
end

# A method definition.
class Def < ASTNode
@@ -1236,11 +1244,36 @@ module Crystal::Macros
# class ExceptionHandler < ASTNode
# end

# class ProcLiteral < ASTNode
# end
# A proc method, written like:
# ```
# ->(arg : String) {
# puts arg
# }
# ```
class ProcLiteral < ASTNode
# Returns the arguments of this proc.
def args : ArrayLiteral(Arg)
end

# class ProcPointer < ASTNode
# end
# Returns the body of this proc.
def body : ASTNode
end
end

# A proc pointer, like `->my_var.some_method(String)`
class ProcPointer < ASTNode
# Returns the types of the arguments of the proc.
def args : ArrayLiteral(ASTNode)
end

# Returns the receiver of the proc, or nil if the proc is not attached to an object.
def obj : ASTNode | NilLiteral
end

# Returns the name of the method this proc points to.
def name : MacroId
end
end

# A type union, like `(Int32 | String)`.
class Union < ASTNode
39 changes: 39 additions & 0 deletions src/compiler/crystal/macros/methods.cr
Original file line number Diff line number Diff line change
@@ -1084,6 +1084,45 @@ module Crystal
end
end

class ProcNotation
def interpret(method, args, block, interpreter)
case method
when "inputs"
interpret_argless_method(method, args) { ArrayLiteral.new(@inputs || [] of ASTNode) }
when "output"
interpret_argless_method(method, args) { @output || NilLiteral.new }
else
super
end
end
end

class ProcLiteral
def interpret(method, args, block, interpreter)
case method
when "args", "body"
@def.interpret(method, args, block, interpreter)
else
super
end
end
end

class ProcPointer
def interpret(method, args, block, interpreter)
case method
when "obj"
interpret_argless_method(method, args) { @obj || NilLiteral.new }
when "name"
interpret_argless_method(method, args) { MacroId.new(@name) }
when "args"
interpret_argless_method(method, args) { ArrayLiteral.new(@args) }
else
super
end
end
end

class Expressions
def interpret(method, args, block, interpreter)
case method