copies of the old code to start the new layer
This commit is contained in:
parent
9b39a3a816
commit
e41bb8027d
10
lib/ast/all.rb
Normal file
10
lib/ast/all.rb
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
require "ast/expression"
|
||||||
|
require_relative "basic_expressions"
|
||||||
|
require_relative "call_site_expression"
|
||||||
|
require_relative "compound_expressions"
|
||||||
|
require_relative "if_expression"
|
||||||
|
require_relative "function_expression"
|
||||||
|
require_relative "module_expression"
|
||||||
|
require_relative "operator_expressions"
|
||||||
|
require_relative "return_expression"
|
||||||
|
require_relative "while_expression"
|
42
lib/ast/basic_expressions.rb
Normal file
42
lib/ast/basic_expressions.rb
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
# collection of the simple ones, int and strings and such
|
||||||
|
|
||||||
|
module Ast
|
||||||
|
|
||||||
|
class IntegerExpression < Expression
|
||||||
|
# attr_reader :value
|
||||||
|
def compile context
|
||||||
|
Vm::IntegerConstant.new value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class NameExpression < Expression
|
||||||
|
# attr_reader :name
|
||||||
|
|
||||||
|
# compiling a variable resolves it. if it wasn't defined, raise an exception
|
||||||
|
def compile context
|
||||||
|
raise "Undefined variable #{name}, defined locals #{context.locals.keys.join('-')}" unless context.locals.has_key?(name)
|
||||||
|
context.locals[name]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class ModuleName < NameExpression
|
||||||
|
|
||||||
|
def compile context
|
||||||
|
clazz = context.object_space.get_or_create_class name
|
||||||
|
raise "uups #{clazz}.#{name}" unless clazz
|
||||||
|
#class qualifier, means call from metaclass
|
||||||
|
clazz = clazz.meta_class
|
||||||
|
puts "CLAZZ #{clazz}"
|
||||||
|
clazz
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class StringExpression < Expression
|
||||||
|
# attr_reader :string
|
||||||
|
def compile context
|
||||||
|
value = Vm::StringConstant.new(string)
|
||||||
|
context.object_space.add_object value
|
||||||
|
value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
59
lib/ast/call_site_expression.rb
Normal file
59
lib/ast/call_site_expression.rb
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
module Ast
|
||||||
|
# assignment, like operators are really function calls
|
||||||
|
|
||||||
|
class CallSiteExpression < Expression
|
||||||
|
# attr_reader :name, :args , :receiver
|
||||||
|
@@counter = 0
|
||||||
|
def compile context
|
||||||
|
into = context.function
|
||||||
|
params = args.collect{ |a| a.compile(context) }
|
||||||
|
puts "compiling receiver #{receiver} (call #{name})"
|
||||||
|
if receiver.is_a? ModuleName
|
||||||
|
clazz = context.object_space.get_or_create_class receiver.name
|
||||||
|
value_receiver = clazz.meta_class
|
||||||
|
function = value_receiver.resolve_function name
|
||||||
|
elsif receiver.is_a?(StringExpression) or receiver.is_a?(IntegerExpression)
|
||||||
|
#TODO obviously the class is wrong, but you gotta start somewhere
|
||||||
|
clazz = context.object_space.get_or_create_class :Object
|
||||||
|
function = clazz.resolve_function name
|
||||||
|
value_receiver = receiver.compile(context)
|
||||||
|
elsif receiver.is_a?(NameExpression)
|
||||||
|
if(receiver.name == :self)
|
||||||
|
function = context.current_class.resolve_function(name)
|
||||||
|
value_receiver = Vm::Integer.new(Vm::RegisterMachine.instance.receiver_register)
|
||||||
|
else
|
||||||
|
value_receiver = receiver.compile(context)
|
||||||
|
# TODO HACK warning: should determine class dynamically
|
||||||
|
function = context.current_class.resolve_function(name)
|
||||||
|
end
|
||||||
|
elsif receiver.is_a? VariableExpression
|
||||||
|
value_receiver = receiver.compile(context)
|
||||||
|
function = context.current_class.resolve_function(name)
|
||||||
|
else
|
||||||
|
#This , how does one say nowadays, smells. Smells of unused polymorphism actually
|
||||||
|
raise "Not sure this is possible, but never good to leave elses open #{receiver} #{receiver.class}"
|
||||||
|
end
|
||||||
|
raise "No such method error #{inspect}" if (function.nil?)
|
||||||
|
raise "No receiver error #{inspect}:#{receiver}" if (value_receiver.nil?)
|
||||||
|
call = Vm::CallSite.new( name , value_receiver , params , function)
|
||||||
|
current_function = context.function
|
||||||
|
into.push([]) unless current_function.nil?
|
||||||
|
call.load_args into
|
||||||
|
call.do_call into
|
||||||
|
|
||||||
|
after = into.new_block("#{name}#{@@counter+=1}")
|
||||||
|
into.insert_at after
|
||||||
|
into.pop([]) unless current_function.nil?
|
||||||
|
function.return_type
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class VariableExpression < CallSiteExpression
|
||||||
|
# super( :_get_instance_variable , [StringExpression.new(name)] )
|
||||||
|
def make_setter
|
||||||
|
@name = :_set_instance_variable
|
||||||
|
@args << StringExpression.new("value")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
20
lib/ast/compound_expressions.rb
Normal file
20
lib/ast/compound_expressions.rb
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
module Ast
|
||||||
|
|
||||||
|
class ArrayExpression < Expression
|
||||||
|
# attr_reader :values
|
||||||
|
def compile context
|
||||||
|
to.do
|
||||||
|
end
|
||||||
|
end
|
||||||
|
class AssociationExpression < Expression
|
||||||
|
# attr_reader :key , :value
|
||||||
|
def compile context
|
||||||
|
to.do
|
||||||
|
end
|
||||||
|
end
|
||||||
|
class HashExpression < ArrayExpression
|
||||||
|
def compile context
|
||||||
|
to.do
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
51
lib/ast/function_expression.rb
Normal file
51
lib/ast/function_expression.rb
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
module Ast
|
||||||
|
class FunctionExpression < Expression
|
||||||
|
# attr_reader :name, :params, :body , :receiver
|
||||||
|
def compile context
|
||||||
|
args = []
|
||||||
|
locals = {}
|
||||||
|
params.each_with_index do |param , index|
|
||||||
|
arg = param.name
|
||||||
|
register = Vm::RegisterReference.new(Vm::RegisterMachine.instance.receiver_register).next_reg_use(index + 1)
|
||||||
|
arg_value = Vm::Integer.new(register)
|
||||||
|
locals[arg] = arg_value
|
||||||
|
args << arg_value
|
||||||
|
end
|
||||||
|
# class depends on receiver
|
||||||
|
me = Vm::Integer.new( Vm::RegisterMachine.instance.receiver_register )
|
||||||
|
if receiver.nil?
|
||||||
|
clazz = context.current_class
|
||||||
|
else
|
||||||
|
c = context.object_space.get_or_create_class receiver.name.to_sym
|
||||||
|
clazz = c.meta_class
|
||||||
|
end
|
||||||
|
|
||||||
|
function = Vm::Function.new(name , me , args )
|
||||||
|
clazz.add_function function
|
||||||
|
|
||||||
|
parent_locals = context.locals
|
||||||
|
parent_function = context.function
|
||||||
|
context.locals = locals
|
||||||
|
context.function = function
|
||||||
|
|
||||||
|
last_compiled = nil
|
||||||
|
body.each do |b|
|
||||||
|
puts "compiling in function #{b}"
|
||||||
|
last_compiled = b.compile(context)
|
||||||
|
raise "alarm #{last_compiled} \n #{b}" unless last_compiled.is_a? Vm::Word
|
||||||
|
end
|
||||||
|
|
||||||
|
return_reg = Vm::Integer.new(Vm::RegisterMachine.instance.return_register)
|
||||||
|
if last_compiled.is_a?(Vm::IntegerConstant) or last_compiled.is_a?(Vm::ObjectConstant)
|
||||||
|
return_reg.load function , last_compiled if last_compiled.register_symbol != return_reg.register_symbol
|
||||||
|
else
|
||||||
|
return_reg.move( function, last_compiled ) if last_compiled.register_symbol != return_reg.register_symbol
|
||||||
|
end
|
||||||
|
function.set_return return_reg
|
||||||
|
|
||||||
|
context.locals = parent_locals
|
||||||
|
context.function = parent_function
|
||||||
|
function
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
41
lib/ast/if_expression.rb
Normal file
41
lib/ast/if_expression.rb
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
module Ast
|
||||||
|
class IfExpression < Expression
|
||||||
|
# attr_reader :cond, :if_true, :if_false
|
||||||
|
def compile context
|
||||||
|
f = context.function
|
||||||
|
# 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
|
||||||
|
merge_block = f.new_block "if_merge"
|
||||||
|
true_block = f.new_block "if_true"
|
||||||
|
false_block = f.new_block "if_false"
|
||||||
|
|
||||||
|
puts "compiling if condition #{cond}"
|
||||||
|
cond_val = cond.compile(context)
|
||||||
|
unless cond_val.is_a? Vm::BranchCondition
|
||||||
|
cond_val = cond_val.is_true? f
|
||||||
|
end
|
||||||
|
f.b true_block , condition_code: cond_val.operator
|
||||||
|
f.insertion_point.branch = true_block
|
||||||
|
|
||||||
|
f.insert_at false_block
|
||||||
|
if_false.each do |part|
|
||||||
|
puts "compiling in if false #{part}"
|
||||||
|
last = part.compile(context )
|
||||||
|
end
|
||||||
|
f.b merge_block
|
||||||
|
f.insertion_point.branch = false_block
|
||||||
|
|
||||||
|
f.insert_at true_block
|
||||||
|
last = nil
|
||||||
|
if_true.each do |part|
|
||||||
|
puts "compiling in if true #{part}"
|
||||||
|
last = part.compile(context )
|
||||||
|
end
|
||||||
|
|
||||||
|
puts "compiled if: end"
|
||||||
|
f.insert_at merge_block
|
||||||
|
|
||||||
|
return last
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
24
lib/ast/module_expression.rb
Normal file
24
lib/ast/module_expression.rb
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
module Ast
|
||||||
|
class ModuleExpression < Expression
|
||||||
|
# attr_reader :name ,:expressions
|
||||||
|
def compile context
|
||||||
|
clazz = context.object_space.get_or_create_class name
|
||||||
|
puts "Created class #{clazz.name.inspect}"
|
||||||
|
context.current_class = clazz
|
||||||
|
expressions.each do |expression|
|
||||||
|
# check if it's a function definition and add
|
||||||
|
# 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
|
||||||
|
puts "compiling expression #{expression}"
|
||||||
|
expression_value = expression.compile(context )
|
||||||
|
#puts "compiled expression #{expression_value.inspect}"
|
||||||
|
end
|
||||||
|
|
||||||
|
return clazz
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class ClassExpression < ModuleExpression
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
56
lib/ast/operator_expressions.rb
Normal file
56
lib/ast/operator_expressions.rb
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
module Ast
|
||||||
|
class OperatorExpression < Expression
|
||||||
|
# attr_reader :operator, :left, :right
|
||||||
|
def compile context
|
||||||
|
into = context.function
|
||||||
|
puts "compiling operator #{to_s}"
|
||||||
|
r_val = right.compile(context)
|
||||||
|
#puts "compiled right #{r_val.inspect}"
|
||||||
|
if operator == "=" # assignment, value based
|
||||||
|
if(left.is_a? VariableExpression)
|
||||||
|
left.make_setter
|
||||||
|
l_val = left.compile(context)
|
||||||
|
elsif left.is_a?(NameExpression)
|
||||||
|
puts context.inspect unless context.locals
|
||||||
|
l_val = context.locals[left.name]
|
||||||
|
if( l_val ) #variable existed, move data there
|
||||||
|
l_val = l_val.move( into , r_val)
|
||||||
|
else
|
||||||
|
l_val = context.function.new_local.move( into , r_val )
|
||||||
|
end
|
||||||
|
context.locals[left.name] = l_val
|
||||||
|
else
|
||||||
|
raise "Can only assign variables, not #{left}"
|
||||||
|
end
|
||||||
|
return l_val
|
||||||
|
end
|
||||||
|
|
||||||
|
l_val = left.compile(context)
|
||||||
|
case operator
|
||||||
|
when ">"
|
||||||
|
code = l_val.greater_than into , r_val
|
||||||
|
when "<"
|
||||||
|
code = l_val.less_than into , r_val
|
||||||
|
when ">="
|
||||||
|
code = l_val.greater_or_equal into , r_val
|
||||||
|
when "<="
|
||||||
|
code = l_val.less_or_equal into , r_val
|
||||||
|
when "=="
|
||||||
|
code = l_val.equals into , r_val
|
||||||
|
when "+"
|
||||||
|
res = context.function.new_local
|
||||||
|
into.add res , l_val , r_val
|
||||||
|
code = res
|
||||||
|
when "-"
|
||||||
|
res = context.function.new_local
|
||||||
|
code = res.minus into , l_val , r_val
|
||||||
|
when "<<"
|
||||||
|
res = context.function.new_local
|
||||||
|
code = res.left_shift into , l_val , r_val
|
||||||
|
else
|
||||||
|
raise "unimplemented operator #{operator} #{self}"
|
||||||
|
end
|
||||||
|
code
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
22
lib/ast/return_expression.rb
Normal file
22
lib/ast/return_expression.rb
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
module Ast
|
||||||
|
class ReturnExpression < Expression
|
||||||
|
# attr_reader :expression
|
||||||
|
def compile context
|
||||||
|
into = context.function
|
||||||
|
puts "compiling return expression #{expression}, now return in return_regsiter"
|
||||||
|
expression_value = expression.compile(context)
|
||||||
|
# copied from function expression: TODO make function
|
||||||
|
|
||||||
|
return_reg = Vm::Integer.new(Vm::RegisterMachine.instance.return_register)
|
||||||
|
if expression_value.is_a?(Vm::IntegerConstant) or expression_value.is_a?(Vm::ObjectConstant)
|
||||||
|
return_reg.load into , expression_value
|
||||||
|
else
|
||||||
|
return_reg.move( into, expression_value ) if expression_value.register_symbol != return_reg.register_symbol
|
||||||
|
end
|
||||||
|
#function.set_return return_reg
|
||||||
|
return return_reg
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
31
lib/ast/while_expression.rb
Normal file
31
lib/ast/while_expression.rb
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
module Ast
|
||||||
|
class WhileExpression < Expression
|
||||||
|
# attr_reader :condition, :body
|
||||||
|
def compile context
|
||||||
|
into = context.function
|
||||||
|
ret = into.new_block "while_end"
|
||||||
|
while_block = into.new_block "while_start"
|
||||||
|
into.insert_at while_block
|
||||||
|
|
||||||
|
puts "compiling while condition #{condition}"
|
||||||
|
cond_val = condition.compile(context)
|
||||||
|
into.b ret , condition_code: cond_val.not_operator
|
||||||
|
into.insertion_point.branch = ret
|
||||||
|
|
||||||
|
last = nil
|
||||||
|
|
||||||
|
body.each do |part|
|
||||||
|
puts "compiling in while #{part}"
|
||||||
|
last = part.compile(context)
|
||||||
|
end
|
||||||
|
into.b while_block
|
||||||
|
into.insertion_point.branch = while_block
|
||||||
|
|
||||||
|
puts "compile while end"
|
||||||
|
into.insert_at ret
|
||||||
|
return last
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
62
lib/neumann/constants.rb
Normal file
62
lib/neumann/constants.rb
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
module Vm
|
||||||
|
|
||||||
|
# constants are the stuff that you embedd in the program as numbers or strings.
|
||||||
|
# Another way to think about them is as Operands, they have no seperate "identity"
|
||||||
|
# and usually end up embedded in the instructions. ie your basic foo + 4 will encode
|
||||||
|
# the 4 in the instruction opcode. The 4 is not accessible anywhere else.
|
||||||
|
# When it should be usable in other forms, the constant must become a Value first
|
||||||
|
class Constant < Code
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
# another abstract "marker" class (so we can check for it)
|
||||||
|
# derived classes are Boot/Meta Clas and StringConstant
|
||||||
|
class ObjectConstant < Constant
|
||||||
|
end
|
||||||
|
|
||||||
|
class IntegerConstant < Constant
|
||||||
|
def initialize int
|
||||||
|
@integer = int
|
||||||
|
end
|
||||||
|
attr_reader :integer
|
||||||
|
def value
|
||||||
|
@integer
|
||||||
|
end
|
||||||
|
def to_asm
|
||||||
|
@integer.to_s
|
||||||
|
end
|
||||||
|
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 StringConstant < ObjectConstant
|
||||||
|
attr_reader :string
|
||||||
|
# currently aligned to 4 (ie padded with 0) and off course 0 at the end
|
||||||
|
def initialize str
|
||||||
|
str = str.to_s if str.is_a? Symbol
|
||||||
|
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 + " " * pad
|
||||||
|
end
|
||||||
|
|
||||||
|
def result= value
|
||||||
|
class_for(MoveInstruction).new(value , self , :opcode => :mov)
|
||||||
|
end
|
||||||
|
|
||||||
|
# the strings length plus padding
|
||||||
|
def length
|
||||||
|
string.length
|
||||||
|
end
|
||||||
|
|
||||||
|
# just writing the string
|
||||||
|
def assemble(io)
|
||||||
|
io << string
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
51
lib/neumann/integer.rb
Normal file
51
lib/neumann/integer.rb
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
module Vm
|
||||||
|
class Integer < Word
|
||||||
|
# needs to be here as Word's constructor is private (to make it abstract)
|
||||||
|
def initialize reg
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
|
def less_or_equal block , right
|
||||||
|
block.cmp( self , right )
|
||||||
|
Vm::BranchCondition.new :le
|
||||||
|
end
|
||||||
|
def greater_or_equal block , right
|
||||||
|
block.cmp( self , right )
|
||||||
|
Vm::BranchCondition.new :ge
|
||||||
|
end
|
||||||
|
def greater_than block , right
|
||||||
|
block.cmp( self , right )
|
||||||
|
Vm::BranchCondition.new :gt
|
||||||
|
end
|
||||||
|
def less_than block , right
|
||||||
|
block.cmp( self , right )
|
||||||
|
Vm::BranchCondition.new :lt
|
||||||
|
end
|
||||||
|
def plus block , first , right
|
||||||
|
block.add( self , left , right )
|
||||||
|
self
|
||||||
|
end
|
||||||
|
def minus block , left , right
|
||||||
|
block.sub( self , left , right )
|
||||||
|
self
|
||||||
|
end
|
||||||
|
def left_shift block , left , right
|
||||||
|
block.mov( self , left , shift_lsr: right )
|
||||||
|
self
|
||||||
|
end
|
||||||
|
def equals block , right
|
||||||
|
block.cmp( self , right )
|
||||||
|
Vm::BranchCondition.new :eq
|
||||||
|
end
|
||||||
|
|
||||||
|
def is_true? function
|
||||||
|
function.cmp( self , 0 )
|
||||||
|
Vm::BranchCondition.new :ne
|
||||||
|
end
|
||||||
|
|
||||||
|
def move block , right
|
||||||
|
block.mov( self , right )
|
||||||
|
self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
8
lib/neumann/mystery.rb
Normal file
8
lib/neumann/mystery.rb
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
module Vm
|
||||||
|
class Mystery < Word
|
||||||
|
# needs to be here as Word's constructor is private (to make it abstract)
|
||||||
|
def initilize reg
|
||||||
|
super
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
30
lib/neumann/reference.rb
Normal file
30
lib/neumann/reference.rb
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
module Vm
|
||||||
|
class Reference < Word
|
||||||
|
# needs to be here as Word's constructor is private (to make it abstract)
|
||||||
|
def initialize reg , clazz = nil
|
||||||
|
super(reg)
|
||||||
|
@clazz = clazz
|
||||||
|
end
|
||||||
|
attr_accessor :clazz
|
||||||
|
|
||||||
|
def load block , right
|
||||||
|
if(right.is_a? IntegerConstant)
|
||||||
|
block.mov( self , right ) #move the value
|
||||||
|
elsif right.is_a? StringConstant
|
||||||
|
block.add( self , right , nil) #move the address, by "adding" to pc, ie pc relative
|
||||||
|
block.mov( Integer.new(self.register.next_reg_use) , right.length ) #and the length HACK TODO
|
||||||
|
elsif right.is_a?(Boot::BootClass) or right.is_a?(Boot::MetaClass)
|
||||||
|
block.add( self , right , nil) #move the address, by "adding" to pc, ie pc relative
|
||||||
|
else
|
||||||
|
raise "unknown #{right.inspect}"
|
||||||
|
end
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
def at_index block , left , right
|
||||||
|
block.ldr( self , left , right )
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
36
lib/neumann/word.rb
Normal file
36
lib/neumann/word.rb
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
module Vm
|
||||||
|
# Word is an abstract base class for the obvious values, ie those that fit into a register
|
||||||
|
# Marked as abstract by private constructor
|
||||||
|
#
|
||||||
|
# Integer and (Object) References are the main derived classes, but float will come and ...
|
||||||
|
# The Mystery Value has unknown type and has only casting methods. So it must be cast to be useful.
|
||||||
|
# Types are stored at runtime when needed in TYPE_REGISTER (r1 on arm), which is mostly before calls,
|
||||||
|
# so that the called function can do casts / branching correctly
|
||||||
|
class Word < Value
|
||||||
|
attr_accessor :register
|
||||||
|
def register_symbol
|
||||||
|
@register.symbol
|
||||||
|
end
|
||||||
|
def inspect
|
||||||
|
"#{self.class.name} (#{register_symbol})"
|
||||||
|
end
|
||||||
|
def to_s
|
||||||
|
inspect
|
||||||
|
end
|
||||||
|
def length
|
||||||
|
4
|
||||||
|
end
|
||||||
|
# aka to string
|
||||||
|
def to_asm
|
||||||
|
"#{register_symbol}"
|
||||||
|
end
|
||||||
|
private
|
||||||
|
def initialize reg
|
||||||
|
if reg.is_a? RegisterReference
|
||||||
|
@register = reg
|
||||||
|
else
|
||||||
|
@register = RegisterReference.new(reg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
10
lib/vm/instruction.rb
Normal file
10
lib/vm/instruction.rb
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
module Vm
|
||||||
|
|
||||||
|
# Instruction is an abstract for all the code of the object-machine. Derived classe make up the actual functionality
|
||||||
|
# of the machine.
|
||||||
|
# All functions on the machine are captured as instances of instructions
|
||||||
|
#
|
||||||
|
class Instruction
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
Loading…
x
Reference in New Issue
Block a user