removing builtin as a concept (wip)
the "old" way of generating compilers is now obsolete we can use ruby code with mom macros to achieve the same Three step wip remove old builtin fix tests (including adding necessary methods) fixup and inclusion of builtin code to parfait
This commit is contained in:
parent
616dd3487c
commit
dced6b12e6
@ -28,12 +28,6 @@ module Mom
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Only for init, as init has no return
|
|
||||||
def _reset_for_init
|
|
||||||
@mom_instructions = Label.new(source_name, source_name)
|
|
||||||
@current = @mom_instructions
|
|
||||||
end
|
|
||||||
|
|
||||||
# add a constant (which get created during compilation and need to be linked)
|
# add a constant (which get created during compilation and need to be linked)
|
||||||
def add_constant(const)
|
def add_constant(const)
|
||||||
raise "Must be Parfait #{const}" unless const.is_a?(Parfait::Object)
|
raise "Must be Parfait #{const}" unless const.is_a?(Parfait::Object)
|
||||||
|
@ -65,7 +65,7 @@ module Mom
|
|||||||
# temporary, need to raise really.
|
# temporary, need to raise really.
|
||||||
factory! << Parfait.object_space.get_factory_for(:Integer)
|
factory! << Parfait.object_space.get_factory_for(:Integer)
|
||||||
integer_tmp! << factory[:reserve]
|
integer_tmp! << factory[:reserve]
|
||||||
Mom::Builtin.emit_syscall( builder , :died ) #uses integer_tmp
|
Mom::Macro.emit_syscall( builder , :died ) #uses integer_tmp
|
||||||
|
|
||||||
add_code ok_label
|
add_code ok_label
|
||||||
cache_entry[:cached_method] << callable_method
|
cache_entry[:cached_method] << callable_method
|
||||||
|
@ -1,77 +0,0 @@
|
|||||||
module Mom
|
|
||||||
module Builtin
|
|
||||||
module CompileHelper
|
|
||||||
|
|
||||||
def compiler_for( clazz_name , method_name , arguments , locals = {})
|
|
||||||
frame = Parfait::NamedList.type_for( locals )
|
|
||||||
args = Parfait::NamedList.type_for( arguments )
|
|
||||||
Mom::MethodCompiler.compiler_for_class(clazz_name , method_name , args, frame )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
class Macro < Instruction
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
require_relative "macro/space"
|
|
||||||
require_relative "macro/integer"
|
|
||||||
require_relative "macro/object"
|
|
||||||
require_relative "macro/word"
|
|
||||||
|
|
||||||
module Mom
|
|
||||||
module Builtin
|
|
||||||
# classes have booted, now create a minimal set of functions
|
|
||||||
# minimal means only that which can not be coded in ruby
|
|
||||||
# Methods are grabbed from respective modules by sending the method name.
|
|
||||||
# This should return the implementation of the method (ie a method compiler),
|
|
||||||
# not actually try to implement it(as that's impossible in ruby)
|
|
||||||
#
|
|
||||||
# We create an empty main for init to jump to, if no code is compiled, that just returns
|
|
||||||
# See Builtin directory readme and module
|
|
||||||
def self.boot_functions( options = nil)
|
|
||||||
space = Parfait.object_space
|
|
||||||
space_type = space.get_class.instance_type
|
|
||||||
|
|
||||||
if @compilers and options == nil
|
|
||||||
if(space_type.methods.nil?)
|
|
||||||
@compilers << compiler_for( space_type , Space , :main)
|
|
||||||
end
|
|
||||||
return @compilers
|
|
||||||
end
|
|
||||||
# TODO go through the virtual parfait layer and adjust function names
|
|
||||||
# to what they really are
|
|
||||||
@compilers = []
|
|
||||||
|
|
||||||
obj_type = space.get_type_by_class_name(:Object)
|
|
||||||
[ :__init__ , :exit , :_method_missing, :get_internal_word ,
|
|
||||||
:set_internal_word ].each do |f|
|
|
||||||
@compilers << compiler_for( obj_type , Object , f)
|
|
||||||
end
|
|
||||||
|
|
||||||
word_type = space.get_type_by_class_name(:Word)
|
|
||||||
[:putstring , :get_internal_byte , :set_internal_byte ].each do |f|
|
|
||||||
@compilers << compiler_for( word_type , Word , f)
|
|
||||||
end
|
|
||||||
|
|
||||||
int_type = space.get_type_by_class_name(:Integer)
|
|
||||||
Risc.operators.each do |op|
|
|
||||||
@compilers << operator_compiler( int_type , op)
|
|
||||||
end
|
|
||||||
[ :div4, :<,:<= , :>=, :> , :div10 ].each do |f| #div4 is just a forward declaration
|
|
||||||
@compilers << compiler_for( int_type , Integer , f)
|
|
||||||
end
|
|
||||||
return @compilers
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.compiler_for( type , mod , name)
|
|
||||||
compiler = mod.send(name , nil)
|
|
||||||
compiler.add_method_to(type)
|
|
||||||
compiler
|
|
||||||
end
|
|
||||||
def self.operator_compiler(int_type , op)
|
|
||||||
compiler = Integer.operator_method(op)
|
|
||||||
compiler.add_method_to(int_type)
|
|
||||||
compiler
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,34 +1,4 @@
|
|||||||
module Mom
|
module Mom
|
||||||
module Builtin
|
|
||||||
class Comparison < ::Mom::Instruction
|
|
||||||
attr_reader :operator
|
|
||||||
def initialize(name , operator)
|
|
||||||
super(name)
|
|
||||||
@operator = operator
|
|
||||||
end
|
|
||||||
def to_risc(compiler)
|
|
||||||
builder = compiler.builder(compiler.source)
|
|
||||||
operator = @operator # make accessible in block
|
|
||||||
builder.build do
|
|
||||||
integer! << message[:receiver]
|
|
||||||
integer.reduce_int
|
|
||||||
integer_reg! << message[:arg1] #"other"
|
|
||||||
integer_reg.reduce_int
|
|
||||||
swap_names(:integer , :integer_reg) if(operator.to_s.start_with?('<') )
|
|
||||||
integer.op :- , integer_reg
|
|
||||||
if_minus false_label
|
|
||||||
if_zero( false_label ) if operator.to_s.length == 1
|
|
||||||
object! << Parfait.object_space.true_object
|
|
||||||
branch merge_label
|
|
||||||
add_code false_label
|
|
||||||
object << Parfait.object_space.false_object
|
|
||||||
add_code merge_label
|
|
||||||
message[:return_value] << object
|
|
||||||
end
|
|
||||||
return compiler
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
class Comparison < Macro
|
class Comparison < Macro
|
||||||
attr_reader :operator
|
attr_reader :operator
|
||||||
def initialize(name , operator)
|
def initialize(name , operator)
|
||||||
|
@ -1,67 +1,4 @@
|
|||||||
module Mom
|
module Mom
|
||||||
module Builtin
|
|
||||||
class Div10 < ::Mom::Instruction
|
|
||||||
def to_risc(compiler)
|
|
||||||
s = "div_10 "
|
|
||||||
builder = compiler.builder(compiler.source)
|
|
||||||
integer_tmp = builder.allocate_int
|
|
||||||
builder.build do
|
|
||||||
integer_self! << message[:receiver]
|
|
||||||
integer_self.reduce_int
|
|
||||||
integer_1! << integer_self
|
|
||||||
integer_reg! << integer_self
|
|
||||||
|
|
||||||
integer_const! << 1
|
|
||||||
integer_1.op :>> , integer_const
|
|
||||||
|
|
||||||
integer_const << 2
|
|
||||||
integer_reg.op :>> , integer_const
|
|
||||||
integer_reg.op :+ , integer_1
|
|
||||||
|
|
||||||
integer_const << 4
|
|
||||||
integer_1 << integer_reg
|
|
||||||
integer_reg.op :>> , integer_1
|
|
||||||
|
|
||||||
integer_reg.op :+ , integer_1
|
|
||||||
|
|
||||||
integer_const << 8
|
|
||||||
integer_1 << integer_reg
|
|
||||||
integer_1.op :>> , integer_const
|
|
||||||
|
|
||||||
integer_reg.op :+ , integer_1
|
|
||||||
|
|
||||||
integer_const << 16
|
|
||||||
integer_1 << integer_reg
|
|
||||||
integer_1.op :>> , integer_const
|
|
||||||
|
|
||||||
integer_reg.op :+ , integer_1
|
|
||||||
|
|
||||||
integer_const << 3
|
|
||||||
integer_reg.op :>> , integer_const
|
|
||||||
|
|
||||||
integer_const << 10
|
|
||||||
integer_1 << integer_reg
|
|
||||||
integer_1.op :* , integer_const
|
|
||||||
|
|
||||||
integer_self.op :- , integer_1
|
|
||||||
integer_1 << integer_self
|
|
||||||
|
|
||||||
integer_const << 6
|
|
||||||
integer_1.op :+ , integer_const
|
|
||||||
|
|
||||||
integer_const << 4
|
|
||||||
integer_1.op :>> , integer_const
|
|
||||||
|
|
||||||
integer_reg.op :+ , integer_1
|
|
||||||
|
|
||||||
integer_tmp[Parfait::Integer.integer_index] << integer_reg
|
|
||||||
message[:return_value] << integer_tmp
|
|
||||||
|
|
||||||
end
|
|
||||||
return compiler
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
class Div10 < Macro
|
class Div10 < Macro
|
||||||
def to_risc(compiler)
|
def to_risc(compiler)
|
||||||
s = "div_10 "
|
s = "div_10 "
|
||||||
|
@ -1,21 +1,4 @@
|
|||||||
module Mom
|
module Mom
|
||||||
module Builtin
|
|
||||||
class Div4 < ::Mom::Instruction
|
|
||||||
def to_risc(compiler)
|
|
||||||
builder = compiler.builder(compiler.source)
|
|
||||||
integer_tmp = builder.allocate_int
|
|
||||||
builder.build do
|
|
||||||
integer_self! << message[:receiver]
|
|
||||||
integer_self.reduce_int
|
|
||||||
integer_1! << 2
|
|
||||||
integer_self.op :>> , integer_1
|
|
||||||
integer_tmp[Parfait::Integer.integer_index] << integer_self
|
|
||||||
message[:return_value] << integer_tmp
|
|
||||||
end
|
|
||||||
return compiler
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
class Div4 < Macro
|
class Div4 < Macro
|
||||||
def to_risc(compiler)
|
def to_risc(compiler)
|
||||||
builder = compiler.builder(compiler.source)
|
builder = compiler.builder(compiler.source)
|
||||||
|
@ -1,14 +1,4 @@
|
|||||||
module Mom
|
module Mom
|
||||||
module Builtin
|
|
||||||
class Exit < ::Mom::Instruction
|
|
||||||
def to_risc(compiler)
|
|
||||||
builder = compiler.builder(compiler.source)
|
|
||||||
builder.prepare_int_return # makes integer_tmp variable as return
|
|
||||||
Builtin.exit_sequence(builder)
|
|
||||||
return compiler
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
class Exit < Macro
|
class Exit < Macro
|
||||||
def to_risc(compiler)
|
def to_risc(compiler)
|
||||||
builder = compiler.builder(compiler.source)
|
builder = compiler.builder(compiler.source)
|
||||||
|
@ -1,21 +1,4 @@
|
|||||||
module Mom
|
module Mom
|
||||||
module Builtin
|
|
||||||
class GetInternalByte < ::Mom::Instruction
|
|
||||||
def to_risc(compiler)
|
|
||||||
builder = compiler.builder(compiler.source)
|
|
||||||
integer_tmp = builder.allocate_int
|
|
||||||
builder.build do
|
|
||||||
object! << message[:receiver]
|
|
||||||
integer! << message[:arg1] #"at"
|
|
||||||
integer.reduce_int
|
|
||||||
object <= object[integer]
|
|
||||||
integer_tmp[Parfait::Integer.integer_index] << object
|
|
||||||
message[:return_value] << integer_tmp
|
|
||||||
end
|
|
||||||
return compiler
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
class GetInternalByte < Macro
|
class GetInternalByte < Macro
|
||||||
def to_risc(compiler)
|
def to_risc(compiler)
|
||||||
builder = compiler.builder(compiler.source)
|
builder = compiler.builder(compiler.source)
|
||||||
|
@ -1,17 +1,4 @@
|
|||||||
module Mom
|
module Mom
|
||||||
module Builtin
|
|
||||||
class GetInternalWord < ::Mom::Instruction
|
|
||||||
def to_risc(compiler)
|
|
||||||
compiler.builder(compiler.source).build do
|
|
||||||
object! << message[:receiver]
|
|
||||||
integer! << message[:arg1] #"at" is at index 0
|
|
||||||
integer.reduce_int
|
|
||||||
object << object[integer]
|
|
||||||
message[:return_value] << object
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
class GetInternalWord < Macro
|
class GetInternalWord < Macro
|
||||||
def to_risc(compiler)
|
def to_risc(compiler)
|
||||||
compiler.builder(compiler.source).build do
|
compiler.builder(compiler.source).build do
|
||||||
|
@ -1,37 +1,4 @@
|
|||||||
module Mom
|
module Mom
|
||||||
module Builtin
|
|
||||||
class Init < ::Mom::Instruction
|
|
||||||
def to_risc(compiler)
|
|
||||||
builder = compiler.builder(compiler.source)
|
|
||||||
builder.build do
|
|
||||||
factory! << Parfait.object_space.get_factory_for(:Message)
|
|
||||||
message << factory[:next_object]
|
|
||||||
next_message! << message[:next_message]
|
|
||||||
factory[:next_object] << next_message
|
|
||||||
end
|
|
||||||
builder.reset_names
|
|
||||||
Mom::MessageSetup.new(Parfait.object_space.get_main).build_with( builder )
|
|
||||||
|
|
||||||
builder.build do
|
|
||||||
message << message[:next_message]
|
|
||||||
space? << Parfait.object_space
|
|
||||||
message[:receiver] << space
|
|
||||||
end
|
|
||||||
|
|
||||||
exit_label = Risc.label(compiler.source , "#{compiler.receiver_type.object_class.name}.#{compiler.source.name}" )
|
|
||||||
ret_tmp = compiler.use_reg(:Label).set_builder(builder)
|
|
||||||
builder.build do
|
|
||||||
ret_tmp << exit_label
|
|
||||||
message[:return_address] << ret_tmp
|
|
||||||
add_code Risc.function_call( "__init__ issue call" , Parfait.object_space.get_main)
|
|
||||||
add_code exit_label
|
|
||||||
end
|
|
||||||
compiler.reset_regs
|
|
||||||
Builtin.exit_sequence(builder)
|
|
||||||
return compiler
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
class Init < Macro
|
class Init < Macro
|
||||||
def to_risc(compiler)
|
def to_risc(compiler)
|
||||||
builder = compiler.builder(compiler.source)
|
builder = compiler.builder(compiler.source)
|
||||||
@ -59,7 +26,7 @@ module Mom
|
|||||||
add_code exit_label
|
add_code exit_label
|
||||||
end
|
end
|
||||||
compiler.reset_regs
|
compiler.reset_regs
|
||||||
Builtin.exit_sequence(builder)
|
Macro.exit_sequence(builder)
|
||||||
return compiler
|
return compiler
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,85 +0,0 @@
|
|||||||
require_relative "div4"
|
|
||||||
require_relative "div10"
|
|
||||||
require_relative "operator"
|
|
||||||
require_relative "comparison"
|
|
||||||
|
|
||||||
module Mom
|
|
||||||
module Builtin
|
|
||||||
# integer related kernel functions
|
|
||||||
# all these functions (return the function they implement) assume interger input
|
|
||||||
# Also the returned integer object has to be passed in to avoid having to allocate it.
|
|
||||||
#
|
|
||||||
# This means the methods will have to be renamed at some point and wrapped
|
|
||||||
module Integer
|
|
||||||
module ClassMethods
|
|
||||||
include CompileHelper
|
|
||||||
|
|
||||||
# div by 4, ie shift right by 2
|
|
||||||
# Mostly created for testing at this point, as it is short
|
|
||||||
# return new int with result
|
|
||||||
def div4(context)
|
|
||||||
compiler = compiler_for(:Integer,:div4 ,{})
|
|
||||||
compiler.add_code Div4.new("div4")
|
|
||||||
return compiler
|
|
||||||
end
|
|
||||||
|
|
||||||
# implemented by the comparison
|
|
||||||
def >( context )
|
|
||||||
comparison( :> )
|
|
||||||
end
|
|
||||||
# implemented by the comparison
|
|
||||||
def <( context )
|
|
||||||
comparison( :< )
|
|
||||||
end
|
|
||||||
# implemented by the comparison
|
|
||||||
def <=( context )
|
|
||||||
comparison( :<= )
|
|
||||||
end
|
|
||||||
# implemented by the comparison
|
|
||||||
def >=( context )
|
|
||||||
comparison( :>= )
|
|
||||||
end
|
|
||||||
|
|
||||||
# all (four) comparison operation are quite similar and implemented here
|
|
||||||
# - reduce the ints (assume int as input)
|
|
||||||
# - subtract the fixnums
|
|
||||||
# - check for minus ( < and > )
|
|
||||||
# - also check for zero (<= and >=)
|
|
||||||
# - load true or false object into return, depending on check
|
|
||||||
# - return
|
|
||||||
def comparison( operator )
|
|
||||||
compiler = compiler_for(:Integer, operator ,{other: :Integer })
|
|
||||||
compiler.add_code Comparison.new("comparison" , operator)
|
|
||||||
return compiler
|
|
||||||
end
|
|
||||||
|
|
||||||
# implemented all known binary operators that map straight to machine codes
|
|
||||||
# this function (similar to comparison):
|
|
||||||
# - unpacks the intergers to fixnum
|
|
||||||
# - applies the operator (at a risc level)
|
|
||||||
# - gets a new integer and stores the result
|
|
||||||
# - returns the new int
|
|
||||||
def operator_method( op_sym )
|
|
||||||
compiler = compiler_for(:Integer, op_sym ,{other: :Integer })
|
|
||||||
compiler.add_code Operator.new( "op:#{op_sym}" , op_sym)
|
|
||||||
return compiler
|
|
||||||
end
|
|
||||||
|
|
||||||
# as the name suggests, this devides the integer (self) by ten
|
|
||||||
#
|
|
||||||
# This version is lifted from some arm assembler tricks and is _much_
|
|
||||||
# faster than the general div versions. I think it was about three
|
|
||||||
# times less instructions. Useful for itos
|
|
||||||
#
|
|
||||||
# In fact it is possible to generate specific div function for any given
|
|
||||||
# integer and some are even more faster (as eg div4).
|
|
||||||
def div10( context )
|
|
||||||
compiler = compiler_for(:Integer,:div10 ,{})
|
|
||||||
compiler.add_code Div10.new("div10")
|
|
||||||
return compiler
|
|
||||||
end
|
|
||||||
end
|
|
||||||
extend ClassMethods
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
63
lib/mom/macro/macro.rb
Normal file
63
lib/mom/macro/macro.rb
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
module Mom
|
||||||
|
class Macro < Instruction
|
||||||
|
|
||||||
|
# emit the syscall with given name
|
||||||
|
# there is a Syscall instruction, but the message has to be saved and restored
|
||||||
|
def self.emit_syscall( builder , name )
|
||||||
|
save_message( builder )
|
||||||
|
builder.add_code Risc::Syscall.new("emit_syscall(#{name})", name )
|
||||||
|
restore_message(builder)
|
||||||
|
return unless (@clazz and @method)
|
||||||
|
builder.add_code Risc.label( "#{@clazz.name}.#{@message.name}" , "return_syscall" )
|
||||||
|
end
|
||||||
|
|
||||||
|
# a sort of inline version of exit method.
|
||||||
|
# Used by exit and __init__ (so it doesn't have to call it)
|
||||||
|
# Assumes int return value and extracts the fixnum for process exit code
|
||||||
|
def self.exit_sequence(builder)
|
||||||
|
save_message( builder )
|
||||||
|
builder.build do
|
||||||
|
message << message[:return_value]
|
||||||
|
message.reduce_int
|
||||||
|
add_code Risc::Syscall.new("emit_syscall(exit)", :exit )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# save the current message, as the syscall destroys all context
|
||||||
|
#
|
||||||
|
# This relies on linux to save and restore all registers
|
||||||
|
#
|
||||||
|
def self.save_message(builder)
|
||||||
|
r8 = Risc::RegisterValue.new( :r8 , :Message).set_builder(builder)
|
||||||
|
builder.build {r8 << message}
|
||||||
|
end
|
||||||
|
|
||||||
|
# restore the message that we save in r8
|
||||||
|
# before th restore, the syscall return, a fixnum, is saved
|
||||||
|
# The caller of this method is assumed to caal prepare_int_return
|
||||||
|
# so that the return value already has an integer instance
|
||||||
|
# This instance is filled with os return value
|
||||||
|
def self.restore_message(builder)
|
||||||
|
r8 = Risc::RegisterValue.new( :r8 , :Message)
|
||||||
|
builder.build do
|
||||||
|
integer_reg! << message
|
||||||
|
message << r8
|
||||||
|
integer_2! << message[:return_value]
|
||||||
|
integer_2[Parfait::Integer.integer_index] << integer_reg
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
require_relative "comparison"
|
||||||
|
require_relative "exit"
|
||||||
|
require_relative "init"
|
||||||
|
require_relative "putstring"
|
||||||
|
require_relative "set_internal_word"
|
||||||
|
require_relative "div10"
|
||||||
|
require_relative "get_internal_byte"
|
||||||
|
require_relative "method_missing"
|
||||||
|
require_relative "div4"
|
||||||
|
require_relative "get_internal_word"
|
||||||
|
require_relative "operator"
|
||||||
|
require_relative "set_internal_byte"
|
@ -1,14 +1,4 @@
|
|||||||
module Mom
|
module Mom
|
||||||
module Builtin
|
|
||||||
class MethodMissing < ::Mom::Instruction
|
|
||||||
def to_risc(compiler)
|
|
||||||
builder = compiler.builder(compiler.source)
|
|
||||||
builder.prepare_int_return # makes integer_tmp variable as return
|
|
||||||
Builtin.emit_syscall( builder , :exit )
|
|
||||||
return compiler
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
class MethodMissing < Macro
|
class MethodMissing < Macro
|
||||||
def to_risc(compiler)
|
def to_risc(compiler)
|
||||||
builder = compiler.builder(compiler.source)
|
builder = compiler.builder(compiler.source)
|
||||||
|
@ -1,107 +1,3 @@
|
|||||||
require_relative "get_internal_word"
|
|
||||||
require_relative "set_internal_word"
|
|
||||||
require_relative "method_missing"
|
|
||||||
require_relative "init"
|
|
||||||
require_relative "exit"
|
|
||||||
|
|
||||||
module Mom
|
module Mom
|
||||||
module Builtin
|
|
||||||
class Object
|
|
||||||
module ClassMethods
|
|
||||||
include CompileHelper
|
|
||||||
|
|
||||||
# self[index] basically. Index is the first arg
|
|
||||||
# return is stored in return_value
|
|
||||||
def get_internal_word( context )
|
|
||||||
compiler = compiler_for(:Object , :get_internal_word ,{at: :Integer})
|
|
||||||
compiler.add_code GetInternalWord.new("get_internal_word")
|
|
||||||
return compiler
|
|
||||||
end
|
|
||||||
# self[index] = val basically. Index is the first arg , value the second
|
|
||||||
# return the value passed in
|
|
||||||
def set_internal_word( context )
|
|
||||||
compiler = compiler_for(:Object , :set_internal_word , {at: :Integer, value: :Object} )
|
|
||||||
compiler.add_code SetInternalWord.new("set_internal_word")
|
|
||||||
return compiler
|
|
||||||
end
|
|
||||||
|
|
||||||
# every object needs a method missing.
|
|
||||||
# Even if it's just this one, sys_exit (later raise)
|
|
||||||
def _method_missing( context )
|
|
||||||
compiler = compiler_for(:Object,:method_missing ,{})
|
|
||||||
compiler.add_code MethodMissing.new("missing")
|
|
||||||
return compiler
|
|
||||||
end
|
|
||||||
|
|
||||||
# this is the really really first place the machine starts (apart from the jump here)
|
|
||||||
# it isn't really a function, ie it is jumped to (not called), exits and may not return
|
|
||||||
# so it is responsible for initial setup:
|
|
||||||
# - load fist message, set up Space as receiver
|
|
||||||
# - call main, ie set up message for that etc
|
|
||||||
# - exit (exit_sequence) which passes a machine int out to c
|
|
||||||
def __init__( context )
|
|
||||||
compiler = compiler_for(:Object,:__init__ ,{})
|
|
||||||
compiler._reset_for_init # no return, just for init
|
|
||||||
compiler.add_code Init.new("missing")
|
|
||||||
return compiler
|
|
||||||
end
|
|
||||||
|
|
||||||
# the exit function
|
|
||||||
# mainly calls exit_sequence
|
|
||||||
def exit( context )
|
|
||||||
compiler = compiler_for(:Object,:exit ,{})
|
|
||||||
compiler.add_code Exit.new("exit")
|
|
||||||
return compiler
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
extend ClassMethods
|
|
||||||
end
|
|
||||||
|
|
||||||
# emit the syscall with given name
|
|
||||||
# there is a Syscall instruction, but the message has to be saved and restored
|
|
||||||
def self.emit_syscall( builder , name )
|
|
||||||
save_message( builder )
|
|
||||||
builder.add_code Risc::Syscall.new("emit_syscall(#{name})", name )
|
|
||||||
restore_message(builder)
|
|
||||||
return unless (@clazz and @method)
|
|
||||||
builder.add_code Risc.label( "#{@clazz.name}.#{@message.name}" , "return_syscall" )
|
|
||||||
end
|
|
||||||
|
|
||||||
# a sort of inline version of exit method.
|
|
||||||
# Used by exit and __init__ (so it doesn't have to call it)
|
|
||||||
# Assumes int return value and extracts the fixnum for process exit code
|
|
||||||
def self.exit_sequence(builder)
|
|
||||||
save_message( builder )
|
|
||||||
builder.build do
|
|
||||||
message << message[:return_value]
|
|
||||||
message.reduce_int
|
|
||||||
add_code Risc::Syscall.new("emit_syscall(exit)", :exit )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# save the current message, as the syscall destroys all context
|
|
||||||
#
|
|
||||||
# This relies on linux to save and restore all registers
|
|
||||||
#
|
|
||||||
def self.save_message(builder)
|
|
||||||
r8 = Risc::RegisterValue.new( :r8 , :Message).set_builder(builder)
|
|
||||||
builder.build {r8 << message}
|
|
||||||
end
|
|
||||||
|
|
||||||
# restore the message that we save in r8
|
|
||||||
# before th restore, the syscall return, a fixnum, is saved
|
|
||||||
# The caller of this method is assumed to caal prepare_int_return
|
|
||||||
# so that the return value already has an integer instance
|
|
||||||
# This instance is filled with os return value
|
|
||||||
def self.restore_message(builder)
|
|
||||||
r8 = Risc::RegisterValue.new( :r8 , :Message)
|
|
||||||
builder.build do
|
|
||||||
integer_reg! << message
|
|
||||||
message << r8
|
|
||||||
integer_2! << message[:return_value]
|
|
||||||
integer_2[Parfait::Integer.integer_index] << integer_reg
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
@ -1,29 +1,4 @@
|
|||||||
module Mom
|
module Mom
|
||||||
module Builtin
|
|
||||||
class Operator < Instruction
|
|
||||||
attr_reader :operator
|
|
||||||
def initialize(name , operator)
|
|
||||||
super(name)
|
|
||||||
@operator = operator
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_risc(compiler)
|
|
||||||
builder = compiler.builder(compiler.source)
|
|
||||||
integer_tmp = builder.allocate_int
|
|
||||||
operator = @operator # make accessible in block
|
|
||||||
builder.build do
|
|
||||||
integer! << message[:receiver]
|
|
||||||
integer.reduce_int
|
|
||||||
integer_reg! << message[:arg1] #"other"
|
|
||||||
integer_reg.reduce_int
|
|
||||||
integer.op operator , integer_reg
|
|
||||||
integer_tmp[Parfait::Integer.integer_index] << integer
|
|
||||||
message[:return_value] << integer_tmp
|
|
||||||
end
|
|
||||||
return compiler
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
class IntOperator < Macro
|
class IntOperator < Macro
|
||||||
attr_reader :operator
|
attr_reader :operator
|
||||||
def initialize(name , operator)
|
def initialize(name , operator)
|
||||||
|
@ -1,18 +1,4 @@
|
|||||||
module Mom
|
module Mom
|
||||||
module Builtin
|
|
||||||
class Putstring < ::Mom::Instruction
|
|
||||||
def to_risc(compiler)
|
|
||||||
builder = compiler.builder(compiler.source)
|
|
||||||
builder.prepare_int_return # makes integer_tmp variable as return
|
|
||||||
builder.build do
|
|
||||||
word! << message[:receiver]
|
|
||||||
integer! << word[Parfait::Word.get_length_index]
|
|
||||||
end
|
|
||||||
Mom::Builtin.emit_syscall( builder , :putstring )
|
|
||||||
compiler
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
class Putstring < Macro
|
class Putstring < Macro
|
||||||
def to_risc(compiler)
|
def to_risc(compiler)
|
||||||
builder = compiler.builder(compiler.source)
|
builder = compiler.builder(compiler.source)
|
||||||
|
@ -1,20 +1,4 @@
|
|||||||
module Mom
|
module Mom
|
||||||
module Builtin
|
|
||||||
class SetInternalByte < ::Mom::Instruction
|
|
||||||
def to_risc(compiler)
|
|
||||||
compiler.builder(compiler.source).build do
|
|
||||||
word! << message[:receiver]
|
|
||||||
integer_reg! << message[:arg2] #VALUE
|
|
||||||
message[:return_value] << integer_reg
|
|
||||||
integer! << message[:arg1] #"index"
|
|
||||||
integer.reduce_int
|
|
||||||
integer_reg.reduce_int
|
|
||||||
word[integer] <= integer_reg
|
|
||||||
end
|
|
||||||
return compiler
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
class SetInternalByte < Macro
|
class SetInternalByte < Macro
|
||||||
def to_risc(compiler)
|
def to_risc(compiler)
|
||||||
compiler.builder(compiler.source).build do
|
compiler.builder(compiler.source).build do
|
||||||
|
@ -1,19 +1,4 @@
|
|||||||
module Mom
|
module Mom
|
||||||
module Builtin
|
|
||||||
class SetInternalWord < ::Mom::Instruction
|
|
||||||
def to_risc(compiler)
|
|
||||||
compiler.builder(compiler.source).build do
|
|
||||||
object! << message[:receiver]
|
|
||||||
integer! << message[:arg1] # "index"
|
|
||||||
object_reg! << message[:arg2]#"value"
|
|
||||||
integer.reduce_int
|
|
||||||
object[integer] << object_reg
|
|
||||||
message[:return_value] << object_reg
|
|
||||||
end
|
|
||||||
return compiler
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
class SetInternalWord < Macro
|
class SetInternalWord < Macro
|
||||||
def to_risc(compiler)
|
def to_risc(compiler)
|
||||||
compiler.builder(compiler.source).build do
|
compiler.builder(compiler.source).build do
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
module Mom
|
|
||||||
module Builtin
|
|
||||||
class Space
|
|
||||||
module ClassMethods
|
|
||||||
include CompileHelper
|
|
||||||
|
|
||||||
# main entry point, ie __init__ calls this
|
|
||||||
# defined here as empty, to be redefined
|
|
||||||
def main(context)
|
|
||||||
compiler = compiler_for(:Space , :main ,{args: :Integer})
|
|
||||||
return compiler
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
extend ClassMethods
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,43 +0,0 @@
|
|||||||
require_relative "get_internal_byte"
|
|
||||||
require_relative "set_internal_byte"
|
|
||||||
require_relative "putstring"
|
|
||||||
|
|
||||||
module Mom
|
|
||||||
module Builtin
|
|
||||||
module Word
|
|
||||||
module ClassMethods
|
|
||||||
include CompileHelper
|
|
||||||
|
|
||||||
# wrapper for the syscall
|
|
||||||
# io/file currently hardcoded to stdout
|
|
||||||
# set up registers for syscall, ie
|
|
||||||
# - pointer in r1
|
|
||||||
# - length in r2
|
|
||||||
# - emit_syscall (which does the return of an integer, see there)
|
|
||||||
def putstring( context)
|
|
||||||
compiler = compiler_for(:Word , :putstring ,{})
|
|
||||||
compiler.add_code Putstring.new("putstring")
|
|
||||||
return compiler
|
|
||||||
end
|
|
||||||
# self[index] basically. Index is the first arg > 0
|
|
||||||
# return a word sized new int, in return_value
|
|
||||||
#
|
|
||||||
# Note: no index (or type) checking. Method should be internal and check before.
|
|
||||||
# Which means the returned integer could be passed in, instead of allocated.
|
|
||||||
def get_internal_byte( context)
|
|
||||||
compiler = compiler_for(:Word , :get_internal_byte , {at: :Integer})
|
|
||||||
compiler.add_code GetInternalByte.new("get_internal_byte")
|
|
||||||
return compiler
|
|
||||||
end
|
|
||||||
# self[index] = val basically. Index is the first arg ( >0 , unchecked),
|
|
||||||
# value the second, which is also returned
|
|
||||||
def set_internal_byte( context )
|
|
||||||
compiler = compiler_for(:Word, :set_internal_byte , {at: :Integer , value: :Integer} )
|
|
||||||
compiler.add_code SetInternalByte.new("set_internal_byte")
|
|
||||||
return compiler
|
|
||||||
end
|
|
||||||
end
|
|
||||||
extend ClassMethods
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -87,5 +87,12 @@ module Mom
|
|||||||
ret
|
ret
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Only for init, as init has no return
|
||||||
|
# kind of private
|
||||||
|
def _reset_for_init
|
||||||
|
@mom_instructions = Label.new(source_name, source_name)
|
||||||
|
@current = @mom_instructions
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -11,16 +11,9 @@
|
|||||||
# No send or call, just objects and jump.
|
# No send or call, just objects and jump.
|
||||||
# Machine capabilities (instructions) for basic operations. Use of macros for higher level.
|
# Machine capabilities (instructions) for basic operations. Use of macros for higher level.
|
||||||
|
|
||||||
module Mom
|
|
||||||
# boot bubiltin function (subject to change)
|
|
||||||
def self.boot!(options = {})
|
|
||||||
Builtin.boot_functions(options)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
require_relative "instruction.rb"
|
require_relative "instruction.rb"
|
||||||
require_relative "mom_collection"
|
require_relative "mom_collection"
|
||||||
require_relative "callable_compiler"
|
require_relative "callable_compiler"
|
||||||
require_relative "method_compiler"
|
require_relative "method_compiler"
|
||||||
require_relative "block_compiler"
|
require_relative "block_compiler"
|
||||||
require_relative "macro"
|
require_relative "macro/macro"
|
||||||
|
@ -14,16 +14,15 @@ module Mom
|
|||||||
@method_compilers = compilers
|
@method_compilers = compilers
|
||||||
end
|
end
|
||||||
|
|
||||||
# lazily instantiate the compilers for boot functions
|
# lazily instantiate the compiler for init function
|
||||||
# (in the hope of only booting the functions once)
|
def init_compiler
|
||||||
def boot_compilers
|
@init_compilers ||= create_init_compiler
|
||||||
@boot_compilers ||= Mom::Builtin.boot_functions
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Return all compilers, namely the MethodCompilers passed in, plus the
|
# Return all compilers, namely the MethodCompilers passed in, plus the
|
||||||
# boot_function's compilers (boot_compilers)
|
# boot_function's compilers (boot_compilers)
|
||||||
def compilers
|
def compilers
|
||||||
@method_compilers + boot_compilers
|
@method_compilers << init_compiler
|
||||||
end
|
end
|
||||||
|
|
||||||
# Append another MomCompilers method_compilers to this one.
|
# Append another MomCompilers method_compilers to this one.
|
||||||
@ -42,5 +41,23 @@ module Mom
|
|||||||
Risc::RiscCollection.new(riscs)
|
Risc::RiscCollection.new(riscs)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# this is the really really first place the machine starts (apart from the jump here)
|
||||||
|
# it isn't really a function, ie it is jumped to (not called), exits and may not return
|
||||||
|
# so it is responsible for initial setup:
|
||||||
|
# - load fist message, set up Space as receiver
|
||||||
|
# - call main, ie set up message for that etc
|
||||||
|
# - exit (exit_sequence) which passes a machine int out to c
|
||||||
|
def create_init_compiler
|
||||||
|
compiler = self.class.compiler_for(:Object,:__init__ ,{})
|
||||||
|
compiler._reset_for_init # no return, just for init
|
||||||
|
compiler.add_code Init.new("missing")
|
||||||
|
return compiler
|
||||||
|
end
|
||||||
|
def self.compiler_for( clazz_name , method_name , arguments , locals = {})
|
||||||
|
frame = Parfait::NamedList.type_for( locals )
|
||||||
|
args = Parfait::NamedList.type_for( arguments )
|
||||||
|
MethodCompiler.compiler_for_class(clazz_name , method_name , args, frame )
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -31,7 +31,6 @@ module RubyX
|
|||||||
def initialize(options)
|
def initialize(options)
|
||||||
@options = options
|
@options = options
|
||||||
Parfait.boot!(options[:parfait] || {})
|
Parfait.boot!(options[:parfait] || {})
|
||||||
Mom.boot!(options[:mom] || {})
|
|
||||||
Risc.boot!(options[:risc] || {})
|
Risc.boot!(options[:risc] || {})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user