renaming mom builtin to macro
This commit is contained in:
19
lib/mom/macro/README.md
Normal file
19
lib/mom/macro/README.md
Normal file
@ -0,0 +1,19 @@
|
||||
## Builtin module
|
||||
|
||||
The Builtin module contains functions that can not be coded in ruby.
|
||||
It is the other side of the parfait coin, part of the runtime.
|
||||
|
||||
The functions are organised by their respective classes and get loaded in boot_classes! ,
|
||||
right at the start. (see register/boot.rb)
|
||||
|
||||
These functions return their code, ie a Parfait::CallableMethod with a MethodSource object,
|
||||
which can then be called by ruby code as if it were a "normal" function.
|
||||
|
||||
A normal ruby function is one that is parsed and transformed to code. But not all
|
||||
functionality can be written in ruby, one of those chicken and egg things.
|
||||
C uses Assembler in this situation, we use Builtin functions.
|
||||
|
||||
Slightly more here : http://ruby-x.org/2014/06/10/more-clarity.html (then still called Kernel)
|
||||
|
||||
The Builtin module is scattered into several files, but that is just so the file
|
||||
doesn't get too long.
|
60
lib/mom/macro/comparison.rb
Normal file
60
lib/mom/macro/comparison.rb
Normal file
@ -0,0 +1,60 @@
|
||||
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
|
||||
attr_reader :operator
|
||||
def initialize(name , operator)
|
||||
super(name)
|
||||
@operator = operator.value
|
||||
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
|
126
lib/mom/macro/div10.rb
Normal file
126
lib/mom/macro/div10.rb
Normal file
@ -0,0 +1,126 @@
|
||||
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
|
||||
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
|
34
lib/mom/macro/div4.rb
Normal file
34
lib/mom/macro/div4.rb
Normal file
@ -0,0 +1,34 @@
|
||||
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
|
||||
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
|
20
lib/mom/macro/exit.rb
Normal file
20
lib/mom/macro/exit.rb
Normal file
@ -0,0 +1,20 @@
|
||||
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
|
||||
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
|
34
lib/mom/macro/get_internal_byte.rb
Normal file
34
lib/mom/macro/get_internal_byte.rb
Normal file
@ -0,0 +1,34 @@
|
||||
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
|
||||
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
|
26
lib/mom/macro/get_internal_word.rb
Normal file
26
lib/mom/macro/get_internal_word.rb
Normal file
@ -0,0 +1,26 @@
|
||||
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
|
||||
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
|
66
lib/mom/macro/init.rb
Normal file
66
lib/mom/macro/init.rb
Normal file
@ -0,0 +1,66 @@
|
||||
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
|
||||
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
|
85
lib/mom/macro/integer.rb
Normal file
85
lib/mom/macro/integer.rb
Normal file
@ -0,0 +1,85 @@
|
||||
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
|
20
lib/mom/macro/method_missing.rb
Normal file
20
lib/mom/macro/method_missing.rb
Normal file
@ -0,0 +1,20 @@
|
||||
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
|
||||
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
|
107
lib/mom/macro/object.rb
Normal file
107
lib/mom/macro/object.rb
Normal file
@ -0,0 +1,107 @@
|
||||
require_relative "get_internal_word"
|
||||
require_relative "set_internal_word"
|
||||
require_relative "method_missing"
|
||||
require_relative "init"
|
||||
require_relative "exit"
|
||||
|
||||
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
|
50
lib/mom/macro/operator.rb
Normal file
50
lib/mom/macro/operator.rb
Normal file
@ -0,0 +1,50 @@
|
||||
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
|
||||
attr_reader :operator
|
||||
def initialize(name , operator)
|
||||
super(name)
|
||||
@operator = operator.value
|
||||
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
|
28
lib/mom/macro/putstring.rb
Normal file
28
lib/mom/macro/putstring.rb
Normal file
@ -0,0 +1,28 @@
|
||||
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
|
||||
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
|
32
lib/mom/macro/set_internal_byte.rb
Normal file
32
lib/mom/macro/set_internal_byte.rb
Normal file
@ -0,0 +1,32 @@
|
||||
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
|
||||
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
|
30
lib/mom/macro/set_internal_word.rb
Normal file
30
lib/mom/macro/set_internal_word.rb
Normal file
@ -0,0 +1,30 @@
|
||||
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
|
||||
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
|
18
lib/mom/macro/space.rb
Normal file
18
lib/mom/macro/space.rb
Normal file
@ -0,0 +1,18 @@
|
||||
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
|
43
lib/mom/macro/word.rb
Normal file
43
lib/mom/macro/word.rb
Normal file
@ -0,0 +1,43 @@
|
||||
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
|
Reference in New Issue
Block a user