move the code insertion functionality up to function. makes more sense. block still carries code though
This commit is contained in:
parent
e9fc8ac6aa
commit
e9519d4f05
@ -25,74 +25,72 @@ module Arm
|
|||||||
end
|
end
|
||||||
|
|
||||||
def integer_equals block , left , right
|
def integer_equals block , left , right
|
||||||
block << cmp( left , right )
|
block.add_code cmp( left , right )
|
||||||
Vm::BranchCondition.new :eq
|
Vm::BranchCondition.new :eq
|
||||||
end
|
end
|
||||||
def integer_less_or_equal block , left , right
|
def integer_less_or_equal block , left , right
|
||||||
block << cmp( left , right )
|
block.add_code cmp( left , right )
|
||||||
Vm::BranchCondition.new :le
|
Vm::BranchCondition.new :le
|
||||||
end
|
end
|
||||||
def integer_greater_or_equal block , left , right
|
def integer_greater_or_equal block , left , right
|
||||||
block << cmp( left , right )
|
block.add_code cmp( left , right )
|
||||||
Vm::BranchCondition.new :ge
|
Vm::BranchCondition.new :ge
|
||||||
end
|
end
|
||||||
def integer_less_than block , left , right
|
def integer_less_than block , left , right
|
||||||
block << cmp( left , right )
|
block.add_code cmp( left , right )
|
||||||
Vm::BranchCondition.new :lt
|
Vm::BranchCondition.new :lt
|
||||||
end
|
end
|
||||||
def integer_greater_than block , left , right
|
def integer_greater_than block , left , right
|
||||||
block << cmp( left , right )
|
block.add_code cmp( left , right )
|
||||||
Vm::BranchCondition.new :gt
|
Vm::BranchCondition.new :gt
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO wrong type, should be object_reference. But that needs the actual typing to work
|
# TODO wrong type, should be object_reference. But that needs the actual typing to work
|
||||||
def integer_at_index block , result ,left , right
|
def integer_at_index block , result ,left , right
|
||||||
block << ldr( result , left , right )
|
block.add_code ldr( result , left , right )
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
def integer_plus block , result , left , right
|
def integer_plus block , result , left , right
|
||||||
block << add( result , left , right )
|
block.add_code add( result , left , right )
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
def integer_minus block , result , left , right
|
def integer_minus block , result , left , right
|
||||||
block << sub( result , left , right )
|
block.add_code sub( result , left , right )
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
def integer_left_shift block , result , left , right
|
def integer_left_shift block , result , left , right
|
||||||
block << mov( result , left , shift_lsr: right )
|
block.add_code mov( result , left , shift_lsr: right )
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
def function_call into , call
|
def function_call into , call
|
||||||
raise "Not CallSite #{call.inspect}" unless call.is_a? Vm::CallSite
|
raise "Not CallSite #{call.inspect}" unless call.is_a? Vm::CallSite
|
||||||
raise "Not linked #{call.inspect}" unless call.function
|
raise "Not linked #{call.inspect}" unless call.function
|
||||||
into << call( call.function )
|
into.add_code call( call.function )
|
||||||
raise "No return type for #{call.function.name}" unless call.function.return_type
|
raise "No return type for #{call.function.name}" unless call.function.return_type
|
||||||
call.function.return_type
|
call.function.return_type
|
||||||
end
|
end
|
||||||
|
|
||||||
def main_start entry
|
def main_start entry
|
||||||
entry << mov( :fp , 0 )
|
entry.do_add mov( :fp , 0 )
|
||||||
end
|
end
|
||||||
def main_exit exit
|
def main_exit exit
|
||||||
syscall(exit , 1)
|
syscall(exit , 1)
|
||||||
exit
|
exit
|
||||||
end
|
end
|
||||||
def function_entry block, f_name
|
def function_entry block, f_name
|
||||||
block << push( [:lr] )
|
block.do_add push( [:lr] )
|
||||||
end
|
end
|
||||||
def function_exit entry , f_name
|
def function_exit entry , f_name
|
||||||
entry << pop( [:pc] )
|
entry.do_add pop( [:pc] )
|
||||||
end
|
end
|
||||||
|
|
||||||
# assumes string in r0 and r1 and moves them along for the syscall
|
# assumes string in r0 and r1 and moves them along for the syscall
|
||||||
def write_stdout block
|
def write_stdout block
|
||||||
block.instance_eval do
|
# TODO save and restore r0
|
||||||
# TODO save and restore r0
|
block.do_add mov( :r0 , 1 ) # 1 == stdout
|
||||||
mov( :r0 , 1 ) # 1 == stdout
|
|
||||||
end
|
|
||||||
syscall( block , 4 )
|
syscall( block , 4 )
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -122,9 +120,9 @@ module Arm
|
|||||||
def syscall block , num
|
def syscall block , num
|
||||||
#small todo, is this actually correct for all (that they return int)
|
#small todo, is this actually correct for all (that they return int)
|
||||||
sys_and_ret = Vm::Integer.new( Vm::RegisterMachine.instance.return_register )
|
sys_and_ret = Vm::Integer.new( Vm::RegisterMachine.instance.return_register )
|
||||||
block << mov( sys_and_ret , num )
|
block.do_add mov( sys_and_ret , num )
|
||||||
block << swi( 0 )
|
block.do_add swi( 0 )
|
||||||
block << mov( sys_and_ret , return_register ) # syscall returns in r0, more to our return
|
block.do_add mov( sys_and_ret , return_register ) # syscall returns in r0, more to our return
|
||||||
#todo should write type into r0 according to syscall
|
#todo should write type into r0 according to syscall
|
||||||
sys_and_ret
|
sys_and_ret
|
||||||
end
|
end
|
||||||
|
@ -4,7 +4,7 @@ module Ast
|
|||||||
|
|
||||||
class IntegerExpression < Expression
|
class IntegerExpression < Expression
|
||||||
# attr_reader :value
|
# attr_reader :value
|
||||||
def compile context , into
|
def compile context
|
||||||
Vm::IntegerConstant.new value
|
Vm::IntegerConstant.new value
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -13,7 +13,7 @@ module Ast
|
|||||||
# attr_reader :name
|
# attr_reader :name
|
||||||
|
|
||||||
# compiling a variable resolves it. if it wasn't defined, raise an exception
|
# compiling a variable resolves it. if it wasn't defined, raise an exception
|
||||||
def compile context , into
|
def compile context
|
||||||
raise "Undefined variable #{name}, defined locals #{context.locals.keys.join('-')}" unless context.locals.has_key?(name)
|
raise "Undefined variable #{name}, defined locals #{context.locals.keys.join('-')}" unless context.locals.has_key?(name)
|
||||||
context.locals[name]
|
context.locals[name]
|
||||||
end
|
end
|
||||||
@ -21,7 +21,7 @@ module Ast
|
|||||||
|
|
||||||
class ModuleName < NameExpression
|
class ModuleName < NameExpression
|
||||||
|
|
||||||
def compile context , into
|
def compile context
|
||||||
clazz = context.object_space.get_or_create_class name
|
clazz = context.object_space.get_or_create_class name
|
||||||
raise "uups #{clazz}.#{name}" unless clazz
|
raise "uups #{clazz}.#{name}" unless clazz
|
||||||
#class qualifier, means call from metaclass
|
#class qualifier, means call from metaclass
|
||||||
@ -34,7 +34,7 @@ module Ast
|
|||||||
|
|
||||||
class StringExpression < Expression
|
class StringExpression < Expression
|
||||||
# attr_reader :string
|
# attr_reader :string
|
||||||
def compile context , into
|
def compile context
|
||||||
value = Vm::StringConstant.new(string)
|
value = Vm::StringConstant.new(string)
|
||||||
context.object_space.add_object value
|
context.object_space.add_object value
|
||||||
value
|
value
|
||||||
|
@ -4,14 +4,15 @@ module Ast
|
|||||||
class CallSiteExpression < Expression
|
class CallSiteExpression < Expression
|
||||||
# attr_reader :name, :args , :receiver
|
# attr_reader :name, :args , :receiver
|
||||||
@@counter = 0
|
@@counter = 0
|
||||||
def compile context , into
|
def compile context
|
||||||
params = args.collect{ |a| a.compile(context, into) }
|
into = context.function
|
||||||
|
params = args.collect{ |a| a.compile(context) }
|
||||||
|
|
||||||
if receiver.is_a?(NameExpression) and (receiver.name == :self)
|
if receiver.is_a?(NameExpression) and (receiver.name == :self)
|
||||||
function = context.current_class.get_or_create_function(name)
|
function = context.current_class.get_or_create_function(name)
|
||||||
value_receiver = Vm::Integer.new(Vm::RegisterMachine.instance.receiver_register)
|
value_receiver = Vm::Integer.new(Vm::RegisterMachine.instance.receiver_register)
|
||||||
else
|
else
|
||||||
value_receiver = receiver.compile(context , into)
|
value_receiver = receiver.compile(context)
|
||||||
function = context.current_class.get_or_create_function(name)
|
function = context.current_class.get_or_create_function(name)
|
||||||
end
|
end
|
||||||
# this lot below should go, since the compile should handle all
|
# this lot below should go, since the compile should handle all
|
||||||
@ -25,9 +26,10 @@ module Ast
|
|||||||
into.push([]) unless current_function.nil?
|
into.push([]) unless current_function.nil?
|
||||||
call.load_args into
|
call.load_args into
|
||||||
call.do_call into
|
call.do_call into
|
||||||
after = into.new_block("#{into.name}_call#{@@counter+=1}")
|
|
||||||
|
after = into.new_block("call#{@@counter+=1}")
|
||||||
into.insert_at after
|
into.insert_at after
|
||||||
after.pop([]) unless current_function.nil?
|
into.pop([]) unless current_function.nil?
|
||||||
puts "compile call #{function.return_type}"
|
puts "compile call #{function.return_type}"
|
||||||
function.return_type
|
function.return_type
|
||||||
end
|
end
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
module Ast
|
module Ast
|
||||||
class FunctionExpression < Expression
|
class FunctionExpression < Expression
|
||||||
# attr_reader :name, :params, :body , :receiver
|
# attr_reader :name, :params, :body , :receiver
|
||||||
def compile context , into
|
def compile context
|
||||||
raise "function does not compile into anything #{self}" if into
|
|
||||||
args = []
|
args = []
|
||||||
locals = {}
|
locals = {}
|
||||||
params.each_with_index do |param , index|
|
params.each_with_index do |param , index|
|
||||||
@ -33,7 +32,7 @@ module Ast
|
|||||||
last_compiled = nil
|
last_compiled = nil
|
||||||
body.each do |b|
|
body.each do |b|
|
||||||
puts "compiling in function #{b}"
|
puts "compiling in function #{b}"
|
||||||
last_compiled = b.compile(context , into)
|
last_compiled = b.compile(context)
|
||||||
raise "alarm #{last_compiled} \n #{b}" unless last_compiled.is_a? Vm::Word
|
raise "alarm #{last_compiled} \n #{b}" unless last_compiled.is_a? Vm::Word
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1,32 +1,36 @@
|
|||||||
module Ast
|
module Ast
|
||||||
class IfExpression < Expression
|
class IfExpression < Expression
|
||||||
# attr_reader :cond, :if_true, :if_false
|
# attr_reader :cond, :if_true, :if_false
|
||||||
def compile context , into
|
def compile context
|
||||||
|
f = context.function
|
||||||
# to execute the logic as the if states it, the blocks are the other way around
|
# to execute the logic as the if states it, the blocks are the other way around
|
||||||
# so we can the jump over the else if true ,and the else joins unconditionally after the true_block
|
# so we can the jump over the else if true ,and the else joins unconditionally after the true_block
|
||||||
false_block = into.new_block "#{into.name}_if_false"
|
false_block = f.new_block "if_false"
|
||||||
true_block = false_block.new_block "#{into.name}_if_true"
|
true_block = f.new_block "if_true"
|
||||||
merge_block = true_block.new_block "#{into.name}_if_merge"
|
merge_block = f.new_block "if_merge"
|
||||||
|
|
||||||
puts "compiling if condition #{cond}"
|
puts "compiling if condition #{cond}"
|
||||||
cond_val = cond.compile(context , into)
|
cond_val = cond.compile(context)
|
||||||
into.b true_block , condition_code: cond_val.operator
|
f.b true_block , condition_code: cond_val.operator
|
||||||
into.branch = true_block
|
f.insertion_point.branch = true_block
|
||||||
|
|
||||||
|
f.insert_at false_block
|
||||||
if_false.each do |part|
|
if_false.each do |part|
|
||||||
puts "compiling in if false #{part}"
|
puts "compiling in if false #{part}"
|
||||||
last = part.compile(context , false_block )
|
last = part.compile(context )
|
||||||
end
|
end
|
||||||
false_block.b merge_block
|
f.b merge_block
|
||||||
|
f.insertion_point.branch = false_block
|
||||||
|
|
||||||
|
f.insert_at true_block
|
||||||
last = nil
|
last = nil
|
||||||
if_true.each do |part|
|
if_true.each do |part|
|
||||||
puts "compiling in if true #{part}"
|
puts "compiling in if true #{part}"
|
||||||
last = part.compile(context , true_block )
|
last = part.compile(context )
|
||||||
end
|
end
|
||||||
|
|
||||||
puts "compiled if: end"
|
puts "compiled if: end"
|
||||||
into.insert_at merge_block
|
f.insert_at merge_block
|
||||||
|
|
||||||
return last
|
return last
|
||||||
end
|
end
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
module Ast
|
module Ast
|
||||||
class ModuleExpression < Expression
|
class ModuleExpression < Expression
|
||||||
# attr_reader :name ,:expressions
|
# attr_reader :name ,:expressions
|
||||||
def compile context , into
|
def compile context
|
||||||
clazz = context.object_space.get_or_create_class name
|
clazz = context.object_space.get_or_create_class name
|
||||||
puts "Created class #{clazz.name.inspect}"
|
puts "Created class #{clazz.name.inspect}"
|
||||||
context.current_class = clazz
|
context.current_class = clazz
|
||||||
@ -10,7 +10,7 @@ module Ast
|
|||||||
# if not, execute it, but that does means we should be in crystal (executable), not ruby. ie throw an error for now
|
# if not, execute it, but that does means we should be in crystal (executable), not ruby. ie throw an error for now
|
||||||
raise "only functions for now #{expression.inspect}" unless expression.is_a? Ast::FunctionExpression
|
raise "only functions for now #{expression.inspect}" unless expression.is_a? Ast::FunctionExpression
|
||||||
puts "compiling expression #{expression}"
|
puts "compiling expression #{expression}"
|
||||||
expression_value = expression.compile(context , nil )
|
expression_value = expression.compile(context )
|
||||||
#puts "compiled expression #{expression_value.inspect}"
|
#puts "compiled expression #{expression_value.inspect}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
module Ast
|
module Ast
|
||||||
class OperatorExpression < Expression
|
class OperatorExpression < Expression
|
||||||
# attr_reader :operator, :left, :right
|
# attr_reader :operator, :left, :right
|
||||||
def compile context , into
|
def compile context
|
||||||
|
into = context.function
|
||||||
puts "compiling operator #{to_s}"
|
puts "compiling operator #{to_s}"
|
||||||
r_val = right.compile(context , into)
|
r_val = right.compile(context)
|
||||||
#puts "compiled right #{r_val.inspect}"
|
#puts "compiled right #{r_val.inspect}"
|
||||||
if operator == "=" # assignment, value based
|
if operator == "=" # assignment, value based
|
||||||
raise "Can only assign variables, not #{left}" unless left.is_a?(NameExpression)
|
raise "Can only assign variables, not #{left}" unless left.is_a?(NameExpression)
|
||||||
@ -18,7 +19,7 @@ module Ast
|
|||||||
return l_val
|
return l_val
|
||||||
end
|
end
|
||||||
|
|
||||||
l_val = left.compile(context , into)
|
l_val = left.compile(context)
|
||||||
case operator
|
case operator
|
||||||
when ">"
|
when ">"
|
||||||
code = l_val.greater_than into , r_val
|
code = l_val.greater_than into , r_val
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
module Ast
|
module Ast
|
||||||
class ReturnExpression < Expression
|
class ReturnExpression < Expression
|
||||||
# attr_reader :expression
|
# attr_reader :expression
|
||||||
def compile context , into
|
def compile context
|
||||||
puts "compiling return expression #{expression}, now return in return_regsiter"
|
puts "compiling return expression #{expression}, now return in return_regsiter"
|
||||||
expression_value = expression.compile(context , into)
|
expression_value = expression.compile(context)
|
||||||
# copied from function expression: TODO make function
|
# copied from function expression: TODO make function
|
||||||
|
|
||||||
return_reg = Vm::Integer.new(Vm::RegisterMachine.instance.return_register)
|
return_reg = Vm::Integer.new(Vm::RegisterMachine.instance.return_register)
|
||||||
|
@ -1,18 +1,21 @@
|
|||||||
module Ast
|
module Ast
|
||||||
class WhileExpression < Expression
|
class WhileExpression < Expression
|
||||||
# attr_reader :condition, :body
|
# attr_reader :condition, :body
|
||||||
def compile context , into
|
def compile context
|
||||||
while_block = into.new_block "#{into.name}_while"
|
into = context.function
|
||||||
ret = while_block.new_block "#{into.name}_return"
|
while_block = into.new_block "while"
|
||||||
|
ret = while_block.new_block "return"
|
||||||
|
into.insert_at while_block
|
||||||
puts "compiling while condition #{condition}"
|
puts "compiling while condition #{condition}"
|
||||||
cond_val = condition.compile(context , while_block)
|
cond_val = condition.compile(context)
|
||||||
while_block.b ret , condition_code: cond_val.not_operator
|
while_block.b ret , condition_code: cond_val.not_operator
|
||||||
while_block.branch = ret
|
while_block.branch = ret
|
||||||
|
|
||||||
last = nil
|
last = nil
|
||||||
|
|
||||||
body.each do |part|
|
body.each do |part|
|
||||||
puts "compiling in while #{part}"
|
puts "compiling in while #{part}"
|
||||||
last = part.compile(context , while_block )
|
last = part.compile(context)
|
||||||
end
|
end
|
||||||
while_block.b while_block
|
while_block.b while_block
|
||||||
puts "compile while end"
|
puts "compile while end"
|
||||||
|
@ -23,13 +23,13 @@ module Boot
|
|||||||
var_name = get_function.args.first
|
var_name = get_function.args.first
|
||||||
return_to = get_function.return_type
|
return_to = get_function.return_type
|
||||||
index_function = context.object_space.get_or_create_class(:Object).get_or_create_function(:index_of)
|
index_function = context.object_space.get_or_create_class(:Object).get_or_create_function(:index_of)
|
||||||
body = get_function.body
|
get_function.push( [me] )
|
||||||
body.push( [me] )
|
get_function.call( index_function )
|
||||||
body.call( index_function )
|
after_body = get_function.new_block("#{get_function.insertion_point.name}_a")
|
||||||
after_body = body.new_block("#{body.name}_a")
|
|
||||||
body.insert_at after_body
|
get_function.insert_at after_body
|
||||||
after_body.pop([me])
|
get_function.pop([me])
|
||||||
return_to.at_index( after_body , me , return_to )
|
return_to.at_index( get_function , me , return_to )
|
||||||
get_function.set_return return_to
|
get_function.set_return return_to
|
||||||
return get_function
|
return get_function
|
||||||
end
|
end
|
||||||
|
@ -27,7 +27,6 @@ module Vm
|
|||||||
@next = next_block
|
@next = next_block
|
||||||
@branch = nil
|
@branch = nil
|
||||||
@codes = []
|
@codes = []
|
||||||
@insert_at = self
|
|
||||||
# keeping track of register usage, left (assigns) or right (uses)
|
# keeping track of register usage, left (assigns) or right (uses)
|
||||||
@assigns = []
|
@assigns = []
|
||||||
@uses = []
|
@uses = []
|
||||||
@ -43,60 +42,16 @@ module Vm
|
|||||||
ret
|
ret
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_code(kode)
|
|
||||||
raise "alarm #{kode}" if kode.is_a? Word
|
|
||||||
raise "alarm #{kode.class} #{kode}" unless kode.is_a? Code
|
|
||||||
@insert_at.do_add kode
|
|
||||||
self
|
|
||||||
end
|
|
||||||
def do_add kode
|
def do_add kode
|
||||||
kode.assigns.each { |a| (@assigns << a) unless @assigns.include?(a) }
|
kode.assigns.each { |a| (@assigns << a) unless @assigns.include?(a) }
|
||||||
kode.uses.each { |use| (@uses << use) unless (@assigns.include?(use) or @uses.include?(use)) }
|
kode.uses.each { |use| (@uses << use) unless (@assigns.include?(use) or @uses.include?(use)) }
|
||||||
#puts "IN ADD #{name}#{uses}"
|
#puts "IN ADD #{name}#{uses}"
|
||||||
@codes << kode
|
@codes << kode
|
||||||
end
|
end
|
||||||
alias :<< :add_code
|
|
||||||
|
|
||||||
# create a new linear block after this block. Linear means there is no brach needed from this one
|
|
||||||
# to the new one. Usually the new one just serves as jump address for a control statement
|
|
||||||
# In code generation (assembly) , new new_block is written after this one, ie zero runtime cost
|
|
||||||
def new_block new_name
|
|
||||||
new_b = Block.new( new_name , @function , @insert_at.next )
|
|
||||||
@insert_at.set_next new_b
|
|
||||||
return new_b
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_next next_b
|
def set_next next_b
|
||||||
@next = next_b
|
@next = next_b
|
||||||
end
|
end
|
||||||
# when control structures create new blocks (with new_block) control continues at some new block the
|
|
||||||
# the control structure creates.
|
|
||||||
# Example: while, needs 2 extra blocks
|
|
||||||
# 1 condition code, must be its own blockas we jump back to it
|
|
||||||
# - the body, can actually be after the condition as we don't need to jump there
|
|
||||||
# 2 after while block. Condition jumps here
|
|
||||||
# After block 2, the function is linear again and the calling code does not need to know what happened
|
|
||||||
|
|
||||||
# But subsequent statements are still using the original block (self) to add code to
|
|
||||||
# So the while expression creates the extra blocks, adds them and the code and then "moves" the insertion point along
|
|
||||||
def insert_at block
|
|
||||||
@insert_at = block
|
|
||||||
self
|
|
||||||
end
|
|
||||||
|
|
||||||
# sugar to create instructions easily.
|
|
||||||
# any method will be passed on to the RegisterMachine and the result added to the block
|
|
||||||
# With this trick we can write what looks like assembler,
|
|
||||||
# Example b.instance_eval
|
|
||||||
# mov( r1 , r2 )
|
|
||||||
# add( r1 , r2 , 4)
|
|
||||||
# end
|
|
||||||
# mov and add will be called on Machine and generate Inststuction that are then added
|
|
||||||
# to the block
|
|
||||||
# also symbols are supported and wrapped as register usages (for bare metal programming)
|
|
||||||
def method_missing(meth, *args, &block)
|
|
||||||
add_code RegisterMachine.instance.send(meth , *args)
|
|
||||||
end
|
|
||||||
|
|
||||||
# returns if this is a block that ends in a call (and thus needs local variable handling)
|
# returns if this is a block that ends in a call (and thus needs local variable handling)
|
||||||
def call_block?
|
def call_block?
|
||||||
|
@ -51,6 +51,7 @@ module Vm
|
|||||||
@exit = Core::Kernel::function_exit( Vm::Block.new("exit" , self , nil) , name )
|
@exit = Core::Kernel::function_exit( Vm::Block.new("exit" , self , nil) , name )
|
||||||
@return = Block.new("return", self , @exit)
|
@return = Block.new("return", self , @exit)
|
||||||
@body = Block.new("body", self , @return)
|
@body = Block.new("body", self , @return)
|
||||||
|
@insert_at = @body
|
||||||
@entry = Core::Kernel::function_entry( Vm::Block.new("entry" , self , @body) ,name )
|
@entry = Core::Kernel::function_entry( Vm::Block.new("entry" , self , @body) ,name )
|
||||||
@locals = []
|
@locals = []
|
||||||
@linked = false # incase link is called twice, we only calculate locals once
|
@linked = false # incase link is called twice, we only calculate locals once
|
||||||
@ -58,6 +59,9 @@ module Vm
|
|||||||
|
|
||||||
attr_reader :args , :entry , :exit , :body , :name , :return_type , :receiver
|
attr_reader :args , :entry , :exit , :body , :name , :return_type , :receiver
|
||||||
|
|
||||||
|
def insertion_point
|
||||||
|
@insert_at
|
||||||
|
end
|
||||||
def set_return type_or_value
|
def set_return type_or_value
|
||||||
@return_type = type_or_value || Vm::Integer
|
@return_type = type_or_value || Vm::Integer
|
||||||
if @return_type.is_a?(Value)
|
if @return_type.is_a?(Value)
|
||||||
@ -104,6 +108,55 @@ module Vm
|
|||||||
ret
|
ret
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# when control structures create new blocks (with new_block) control continues at some new block the
|
||||||
|
# the control structure creates.
|
||||||
|
# Example: while, needs 2 extra blocks
|
||||||
|
# 1 condition code, must be its own blockas we jump back to it
|
||||||
|
# - the body, can actually be after the condition as we don't need to jump there
|
||||||
|
# 2 after while block. Condition jumps here
|
||||||
|
# After block 2, the function is linear again and the calling code does not need to know what happened
|
||||||
|
|
||||||
|
# But subsequent statements are still using the original block (self) to add code to
|
||||||
|
# So the while expression creates the extra blocks, adds them and the code and then "moves" the insertion point along
|
||||||
|
def insert_at block
|
||||||
|
@insert_at = block
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
# create a new linear block after the current insertion block.
|
||||||
|
# Linear means there is no brach needed from that one to the new one.
|
||||||
|
# Usually the new one just serves as jump address for a control statement
|
||||||
|
# In code generation (assembly) , new new_block is written after this one, ie zero runtime cost
|
||||||
|
# This does _not_ change the insertion point, that has do be done with insert_at(block)
|
||||||
|
def new_block new_name
|
||||||
|
block_name = "#{@insert_at.name}_#{new_name}"
|
||||||
|
new_b = Block.new( block_name , @function , @insert_at.next )
|
||||||
|
@insert_at.set_next new_b
|
||||||
|
return new_b
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_code(kode)
|
||||||
|
raise "alarm #{kode}" if kode.is_a? Word
|
||||||
|
raise "alarm #{kode.class} #{kode}" unless kode.is_a? Code
|
||||||
|
@insert_at.do_add kode
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
# sugar to create instructions easily.
|
||||||
|
# any method will be passed on to the RegisterMachine and the result added to the insertion block
|
||||||
|
# With this trick we can write what looks like assembler,
|
||||||
|
# Example func.instance_eval
|
||||||
|
# mov( r1 , r2 )
|
||||||
|
# add( r1 , r2 , 4)
|
||||||
|
# end
|
||||||
|
# mov and add will be called on Machine and generate Inststuction that are then added
|
||||||
|
# to the current block
|
||||||
|
# also symbols are supported and wrapped as register usages (for bare metal programming)
|
||||||
|
def method_missing(meth, *args, &block)
|
||||||
|
puts "passing #{meth} , #{args.length} #{args}"
|
||||||
|
add_code RegisterMachine.instance.send(meth , *args)
|
||||||
|
end
|
||||||
|
|
||||||
# following id the Code interface
|
# following id the Code interface
|
||||||
|
|
||||||
# to link we link the entry and then any blocks. The entry links the straight line
|
# to link we link the entry and then any blocks. The entry links the straight line
|
||||||
|
@ -24,9 +24,9 @@ module Fragments
|
|||||||
# and the last is wrapped as a main
|
# and the last is wrapped as a main
|
||||||
parts.each_with_index do |part,index|
|
parts.each_with_index do |part,index|
|
||||||
if part.is_a? Ast::FunctionExpression
|
if part.is_a? Ast::FunctionExpression
|
||||||
expr = part.compile( @object_space.context , nil )
|
expr = part.compile( @object_space.context )
|
||||||
else
|
else
|
||||||
expr = part.compile( @object_space.context , @object_space.main )
|
expr = part.compile( @object_space.context )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -65,9 +65,9 @@ HERE
|
|||||||
# and the last is wrapped as a main
|
# and the last is wrapped as a main
|
||||||
parts.each_with_index do |part,index|
|
parts.each_with_index do |part,index|
|
||||||
if index == (parts.length - 1)
|
if index == (parts.length - 1)
|
||||||
expr = part.compile( @object_space.context , @object_space.main )
|
expr = part.compile( @object_space.context )
|
||||||
else
|
else
|
||||||
expr = part.compile( @object_space.context , nil )
|
expr = part.compile( @object_space.context )
|
||||||
raise "should be function definition for now, not #{part.inspect}#{expr.inspect}" unless expr.is_a? Vm::BootClass
|
raise "should be function definition for now, not #{part.inspect}#{expr.inspect}" unless expr.is_a? Vm::BootClass
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -28,9 +28,9 @@ class TestRunner < MiniTest::Test
|
|||||||
# and the last is wrapped as a main
|
# and the last is wrapped as a main
|
||||||
parts.each_with_index do |part,index|
|
parts.each_with_index do |part,index|
|
||||||
if index == (parts.length - 1)
|
if index == (parts.length - 1)
|
||||||
expr = part.compile( program.context , program.main )
|
expr = part.compile( program.context )
|
||||||
else
|
else
|
||||||
expr = part.compile( program.context , nil )
|
expr = part.compile( program.context )
|
||||||
raise "should be function definition for now" unless expr.is_a? Vm::Function
|
raise "should be function definition for now" unless expr.is_a? Vm::Function
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user