crystal says Hello.

This commit is contained in:
Torsten Ruger
2014-05-06 21:36:28 +03:00
parent fa123e0354
commit 4135c4d2dc
14 changed files with 134 additions and 114 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"