Change Mom to SlotMachine
rather large commit, but essentially a simple rename Rationale in docs and blogs
This commit is contained in:
19
lib/slot_machine/macro/README.md
Normal file
19
lib/slot_machine/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.
|
30
lib/slot_machine/macro/comparison.rb
Normal file
30
lib/slot_machine/macro/comparison.rb
Normal file
@ -0,0 +1,30 @@
|
||||
module Mom
|
||||
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
|
63
lib/slot_machine/macro/div10.rb
Normal file
63
lib/slot_machine/macro/div10.rb
Normal file
@ -0,0 +1,63 @@
|
||||
module Mom
|
||||
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
|
17
lib/slot_machine/macro/div4.rb
Normal file
17
lib/slot_machine/macro/div4.rb
Normal file
@ -0,0 +1,17 @@
|
||||
module Mom
|
||||
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
|
10
lib/slot_machine/macro/exit.rb
Normal file
10
lib/slot_machine/macro/exit.rb
Normal file
@ -0,0 +1,10 @@
|
||||
module Mom
|
||||
class Exit < Macro
|
||||
def to_risc(compiler)
|
||||
builder = compiler.builder(compiler.source)
|
||||
builder.prepare_int_return # makes integer_tmp variable as return
|
||||
Macro.exit_sequence(builder)
|
||||
return compiler
|
||||
end
|
||||
end
|
||||
end
|
17
lib/slot_machine/macro/get_internal_byte.rb
Normal file
17
lib/slot_machine/macro/get_internal_byte.rb
Normal file
@ -0,0 +1,17 @@
|
||||
module Mom
|
||||
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
|
13
lib/slot_machine/macro/get_internal_word.rb
Normal file
13
lib/slot_machine/macro/get_internal_word.rb
Normal file
@ -0,0 +1,13 @@
|
||||
module Mom
|
||||
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
|
43
lib/slot_machine/macro/init.rb
Normal file
43
lib/slot_machine/macro/init.rb
Normal file
@ -0,0 +1,43 @@
|
||||
module Mom
|
||||
# Init "method" is the first thing that happens in the machine
|
||||
# There is an inital jump to it, but that's it, no setup, no nothing
|
||||
#
|
||||
# The method is in quotes, because it is not really a method, it does not return!!
|
||||
# This is common to all double underscore "methods", but __init also does not
|
||||
# rely on the message. In fact it's job is to set up the first message
|
||||
# and to call the main (possibly later _init_ , single undescrore)
|
||||
#
|
||||
class Init < Macro
|
||||
def to_risc(compiler)
|
||||
builder = compiler.builder(compiler.source)
|
||||
main = Parfait.object_space.get_method!(:Space, :main)
|
||||
# Set up the first message, but advance one, so main has somewhere to return to
|
||||
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
|
||||
# Set up the call to main, with space as receiver
|
||||
Mom::MessageSetup.new(main).build_with( builder )
|
||||
builder.build do
|
||||
message << message[:next_message]
|
||||
space? << Parfait.object_space
|
||||
message[:receiver] << space
|
||||
end
|
||||
# set up return address and jump to main
|
||||
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" , main)
|
||||
add_code exit_label
|
||||
end
|
||||
compiler.reset_regs
|
||||
Macro.exit_sequence(builder) # exit will use mains return_value as exit_code
|
||||
return compiler
|
||||
end
|
||||
end
|
||||
end
|
67
lib/slot_machine/macro/macro.rb
Normal file
67
lib/slot_machine/macro/macro.rb
Normal file
@ -0,0 +1,67 @@
|
||||
module Mom
|
||||
class Macro < Instruction
|
||||
|
||||
def to_s
|
||||
self.class.name.split("::").last
|
||||
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
|
||||
|
||||
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"
|
21
lib/slot_machine/macro/method_missing.rb
Normal file
21
lib/slot_machine/macro/method_missing.rb
Normal file
@ -0,0 +1,21 @@
|
||||
module Mom
|
||||
class MethodMissing < Macro
|
||||
attr_reader :name
|
||||
|
||||
def initialize( source , name )
|
||||
super(source)
|
||||
name = name.value if name.is_a?(Vool::SymbolConstant)
|
||||
raise "No reg #{name.class}" unless name.class == Symbol
|
||||
@name = name
|
||||
end
|
||||
|
||||
def to_risc(compiler)
|
||||
builder = compiler.builder(compiler.source_name)
|
||||
from = Risc::RegisterValue.new(@name , :Word)
|
||||
to = Risc::RegisterValue.new(:r1 , :Word)
|
||||
builder.add_code Risc::Transfer.new(self , from , to)
|
||||
builder.add_code Risc::Syscall.new(self, :died )
|
||||
return compiler
|
||||
end
|
||||
end
|
||||
end
|
3
lib/slot_machine/macro/object.rb
Normal file
3
lib/slot_machine/macro/object.rb
Normal file
@ -0,0 +1,3 @@
|
||||
|
||||
module Mom
|
||||
end
|
25
lib/slot_machine/macro/operator.rb
Normal file
25
lib/slot_machine/macro/operator.rb
Normal file
@ -0,0 +1,25 @@
|
||||
module Mom
|
||||
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
|
14
lib/slot_machine/macro/putstring.rb
Normal file
14
lib/slot_machine/macro/putstring.rb
Normal file
@ -0,0 +1,14 @@
|
||||
module Mom
|
||||
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::Macro.emit_syscall( builder , :putstring )
|
||||
compiler
|
||||
end
|
||||
end
|
||||
end
|
16
lib/slot_machine/macro/set_internal_byte.rb
Normal file
16
lib/slot_machine/macro/set_internal_byte.rb
Normal file
@ -0,0 +1,16 @@
|
||||
module Mom
|
||||
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
|
15
lib/slot_machine/macro/set_internal_word.rb
Normal file
15
lib/slot_machine/macro/set_internal_word.rb
Normal file
@ -0,0 +1,15 @@
|
||||
module Mom
|
||||
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
|
Reference in New Issue
Block a user