Skip to content
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
23 changes: 23 additions & 0 deletions spec/compiler/interpreter/lib_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,27 @@ describe Crystal::Repl::Interpreter do
CRYSTAL
end
end

context "proc pointer" do
it "calls extern fun" do
interpret(<<-CRYSTAL).should eq 6
@[Link(ldflags: #{ldflags_with_backtick.inspect})]
lib LibSum
fun simple_sum_int(a : Int32, b : Int32) : Int32
end

class Foo
def initialize(@method : Proc(Int32, Int32, Int32))
end

def call(a, b)
@method.call(a, b)
end
end

foo = Foo.new(->LibSum.simple_sum_int)
foo.call(1, 5)
CRYSTAL
end
end
end
22 changes: 22 additions & 0 deletions src/compiler/crystal/interpreter/compiler.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2925,6 +2925,28 @@ class Crystal::Repl::Compiler < Crystal::Visitor
false
end

def visit(node : ProcPointer)
target_def = node.call.target_def

unless target_def.owner.is_a?(LibType)
# LLVM codegen supports more cases like closure data and obj/self
# target, but I can't trigger them — does LiteralExpander expand
# these cases into ProcLiteral?
raise "BUG: missing interpret for ProcPointer to non Lib fun"
end

# find or build a compiled_def
proc_type = node.type.as(ProcInstanceType)
symbol = @context.c_function(target_def.as(External).real_name)
compiled_def = @context.extern_proc_wrapper(proc_type, symbol)

# push compiled_def to stack + no closure data (null pointer)
put_i64 compiled_def.object_id.to_i64!, node: node
put_i64 0, node: node

false
end

def visit(node : Break)
exp = node.exp

Expand Down