crystal says Hello.
This commit is contained in:
@ -56,12 +56,12 @@ module Vm
|
||||
obj.assemble io
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# set the next executed block after self.
|
||||
# why is this useful? if it's unconditional, why not merge them:
|
||||
# So the second block can be used as a jump target. You standard loop needs a block to setup
|
||||
# and at least one to do the calculation
|
||||
def next block
|
||||
def set_next block
|
||||
@next = block
|
||||
end
|
||||
|
||||
|
@ -21,7 +21,6 @@ module Vm
|
||||
# in other words, during assembly the position _must_ be resolved into a pc relative address
|
||||
# and not used as is
|
||||
def position
|
||||
throw "Not set" unless @position
|
||||
@position
|
||||
end
|
||||
|
||||
|
@ -6,49 +6,67 @@ module Vm
|
||||
|
||||
# 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.
|
||||
|
||||
# Functions have a exactly three blocks, entry, exit and body, which are created for you
|
||||
# with straight branches between them.
|
||||
|
||||
class Function < Block
|
||||
# Also remember that if your den body exists of severa blocks, they must be wrapped in a
|
||||
# block as the function really only has the one, and blocks only assemble their codes,
|
||||
# not their next links
|
||||
# This comes at zero runtime cost though, as the wrapper is just the sum of it's codes
|
||||
|
||||
# If you change the body block to point elsewhere, remember to end up at exit
|
||||
|
||||
class Function < Code
|
||||
|
||||
def initialize(name , args = [])
|
||||
super(name)
|
||||
super()
|
||||
@name = name
|
||||
@args = args
|
||||
@entry = Core::Kernel::function_entry( name )
|
||||
@exit = Core::Kernel::function_exit( name )
|
||||
@body = Block.new("#{name}_body")
|
||||
branch_body
|
||||
end
|
||||
attr_reader :args , :entry , :exit
|
||||
|
||||
attr_reader :args , :entry , :exit , :body , :name
|
||||
|
||||
# this creates a branch from entry here and from here to exit
|
||||
# unless there is a link existing, in which you are resposible
|
||||
def set_body body
|
||||
@body = body
|
||||
branch_body
|
||||
end
|
||||
|
||||
def arity
|
||||
@args.length
|
||||
end
|
||||
|
||||
def link_at address , context
|
||||
# function = context.program.get_function(name)
|
||||
# unless function
|
||||
# function = Core::Kernel.send(name)
|
||||
# context.program.get_or_create_function( name , function , arity )
|
||||
# end
|
||||
|
||||
raise "undefined code #{inspect}" if @body.nil?
|
||||
super #just sets the position
|
||||
@entry.link_at address , context
|
||||
address += @entry.length
|
||||
super(address , context)
|
||||
@body.link_at(address , context)
|
||||
address += @entry.length
|
||||
@exit.link_at(address,context)
|
||||
end
|
||||
|
||||
def length
|
||||
@entry.length + @exit.length + super
|
||||
@entry.length + @exit.length + @body.length
|
||||
end
|
||||
|
||||
def assemble io
|
||||
@entry.assemble io
|
||||
super(io)
|
||||
@entry.assemble(io)
|
||||
@body.assemble(io)
|
||||
@exit.assemble(io)
|
||||
end
|
||||
|
||||
private
|
||||
private
|
||||
# set up the braches from entry to body and body to exit (unless that exists, see set_body)
|
||||
def branch_body
|
||||
@entry.set_next(@body)
|
||||
@body.set_next(@exit) if @body and !@body.next
|
||||
end
|
||||
|
||||
def add_arg value
|
||||
# TODO check
|
||||
@args << value
|
||||
|
@ -21,11 +21,12 @@ module Vm
|
||||
end
|
||||
def load_args
|
||||
args.each_with_index do |arg , index|
|
||||
arg.load index
|
||||
add_code arg.load(index)
|
||||
end
|
||||
end
|
||||
|
||||
def do_call
|
||||
Machine.instance.function_call self
|
||||
add_code Machine.instance.function_call self
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -49,6 +49,8 @@ module Vm
|
||||
fun = get_function name
|
||||
unless fun
|
||||
fun = Function.new(name)
|
||||
block = Core::Kernel.send(name)
|
||||
fun.set_body block
|
||||
@functions << fun
|
||||
end
|
||||
fun
|
||||
|
@ -1,30 +0,0 @@
|
||||
require "vm/code"
|
||||
|
||||
module Vm
|
||||
# The name really says it all.
|
||||
# The only interesting thing is storage.
|
||||
# Currently string are stored "inline" , ie in the code segment.
|
||||
# Mainly because that works an i aint no elf expert.
|
||||
|
||||
class StringLiteral < Vm::Code
|
||||
|
||||
# currently aligned to 4 (ie padded with 0) and off course 0 at the end
|
||||
def initialize(str)
|
||||
length = str.length
|
||||
# rounding up to the next 4 (always adding one for zero pad)
|
||||
pad = ((length / 4 ) + 1 ) * 4 - length
|
||||
raise "#{pad} #{self}" unless pad >= 1
|
||||
@string = str + "\x00" * pad
|
||||
end
|
||||
|
||||
# the strings length plus padding
|
||||
def length
|
||||
@string.length
|
||||
end
|
||||
|
||||
# just writing the string
|
||||
def assemble(io)
|
||||
io << @string
|
||||
end
|
||||
end
|
||||
end
|
@ -41,40 +41,36 @@ module Vm
|
||||
end
|
||||
end
|
||||
|
||||
class Float < Word
|
||||
end
|
||||
# The name really says it all.
|
||||
# The only interesting thing is storage.
|
||||
# Currently string are stored "inline" , ie in the code segment.
|
||||
# Mainly because that works an i aint no elf expert.
|
||||
|
||||
class Reference < Word
|
||||
end
|
||||
class StringValue < Value
|
||||
def initialize string
|
||||
@string = string
|
||||
end
|
||||
def length
|
||||
@string.length + 3
|
||||
class StringLiteral < Value
|
||||
|
||||
# currently aligned to 4 (ie padded with 0) and off course 0 at the end
|
||||
def initialize(str)
|
||||
super()
|
||||
length = str.length
|
||||
# rounding up to the next 4 (always adding one for zero pad)
|
||||
pad = ((length / 4 ) + 1 ) * 4 - length
|
||||
raise "#{pad} #{self}" unless pad >= 1
|
||||
@string = str + "\x00" * pad
|
||||
end
|
||||
attr_reader :string
|
||||
end
|
||||
|
||||
class MemoryReference < Reference
|
||||
end
|
||||
|
||||
class ObjectReference < Reference
|
||||
def initialize obj
|
||||
@object = obj
|
||||
def load reg_num
|
||||
Machine.instance.string_load self , reg_num
|
||||
end
|
||||
|
||||
# the strings length plus padding
|
||||
def length
|
||||
@string.length
|
||||
end
|
||||
attr_reader :object
|
||||
|
||||
def compiled context
|
||||
if object.is_a? StringValue
|
||||
context.program.add_object object
|
||||
else
|
||||
#TODO define object layout more generally and let objects lay themselves out
|
||||
# as it is the program does this (in the objectwriter/stringtable)
|
||||
un.done
|
||||
end
|
||||
# just writing the string
|
||||
def assemble(io)
|
||||
io << @string
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
require_relative "string_literal"
|
Reference in New Issue
Block a user