2014-05-03 14:13:44 +02:00
|
|
|
require_relative "block"
|
|
|
|
|
|
|
|
module Vm
|
|
|
|
|
|
|
|
# Functions are similar to Blocks. Where Blocks can be jumped to, Functions can be called.
|
|
|
|
|
|
|
|
# Functions also have arguments, though they are handled differently (in register allocation)
|
|
|
|
|
|
|
|
# Functions have a minimum of two blocks, entry and exit, which are created for you
|
|
|
|
# but there is no branch created between them, this must be done by the programmer.
|
|
|
|
|
|
|
|
|
2014-05-05 08:35:40 +02:00
|
|
|
class Function < Block
|
2014-05-03 14:13:44 +02:00
|
|
|
|
|
|
|
def initialize(name , args = [])
|
2014-05-05 08:35:40 +02:00
|
|
|
super(name)
|
2014-05-03 14:13:44 +02:00
|
|
|
@args = args
|
|
|
|
@entry = Block.new("entry_#{name}")
|
|
|
|
@exit = Block.new("exit_#{name}")
|
|
|
|
end
|
2014-05-05 08:35:40 +02:00
|
|
|
attr_reader :args , :entry , :exit
|
2014-05-03 14:13:44 +02:00
|
|
|
|
|
|
|
def arity
|
|
|
|
@args.length
|
|
|
|
end
|
|
|
|
|
2014-05-05 23:12:04 +02:00
|
|
|
def link_at address , context
|
|
|
|
# function = context.program.get_function(name)
|
|
|
|
# unless function
|
|
|
|
# function = Vm::Kernel.send(name)
|
|
|
|
# context.program.get_or_create_function( name , function , arity )
|
|
|
|
# end
|
|
|
|
|
|
|
|
@entry.link_at address , context
|
|
|
|
address += @entry.length
|
|
|
|
super(address , context)
|
|
|
|
address += @entry.length
|
|
|
|
@exit.link_at(address,context)
|
|
|
|
end
|
|
|
|
|
2014-05-05 08:35:40 +02:00
|
|
|
def length
|
|
|
|
@entry.length + @exit.length + super
|
|
|
|
end
|
|
|
|
|
2014-05-05 23:12:04 +02:00
|
|
|
def assemble io
|
|
|
|
@entry.assemble io
|
|
|
|
super(io)
|
|
|
|
@exit.assemble(io)
|
2014-05-03 14:13:44 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
def add_arg value
|
|
|
|
# TODO check
|
|
|
|
@args << value
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|