starting on mom to risc
some docs too
This commit is contained in:
parent
82c9f1d97f
commit
5994cd3276
@ -34,6 +34,12 @@ module Mom
|
|||||||
@constants << const
|
@constants << const
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# translate to Risc, ie a Risc level CallableCompiler
|
||||||
|
# abstract functon that needs to be implemented by Method/BlockCompiler
|
||||||
|
def to_risc
|
||||||
|
raise "abstract in #{self.class}"
|
||||||
|
end
|
||||||
|
|
||||||
# add a risc instruction after the current (insertion point)
|
# add a risc instruction after the current (insertion point)
|
||||||
# the added instruction will become the new insertion point
|
# the added instruction will become the new insertion point
|
||||||
def add_code( instruction )
|
def add_code( instruction )
|
||||||
|
@ -37,49 +37,26 @@ module Mom
|
|||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
# Translate code to whatever cpu is specified.
|
def to_risc( )
|
||||||
# Currently only :arm and :interpret
|
riscs = []
|
||||||
#
|
# to_risc all compilers
|
||||||
# Translating means translating the initial jump
|
# for each suffling constnts and fist label, then all instructions (see below)
|
||||||
# and then translating all methods
|
# then create risc collection
|
||||||
def translate( platform_sym )
|
Risc::RiscCollection.new(riscs)
|
||||||
platform_sym = platform_sym.to_s.capitalize
|
|
||||||
platform = Risc::Platform.for(platform_sym)
|
|
||||||
assemblers = translate_methods( platform.translator )
|
|
||||||
Risc::Linker.new(platform , assemblers , constants)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# go through all methods and translate them to cpu, given the translator
|
# convert the given mom instruction to_risc and then add it (see add_code)
|
||||||
def translate_methods(translator)
|
# continue down the instruction chain unti depleted
|
||||||
compilers.collect do |compiler|
|
# (adding moves the insertion point so the whole mom chain is added as a risc chain)
|
||||||
#log.debug "Translate method #{compiler.method.name}"
|
def add_mom( instruction )
|
||||||
translate_method(compiler , translator)
|
while( instruction )
|
||||||
end.flatten
|
raise "whats this a #{instruction}" unless instruction.is_a?(Mom::Instruction)
|
||||||
end
|
#puts "adding mom #{instruction.to_s}:#{instruction.next.to_s}"
|
||||||
|
instruction.to_risc( self )
|
||||||
# translate one method, which means the method itself and all blocks inside it
|
reset_regs
|
||||||
# returns an array of assemblers
|
#puts "adding risc #{risc.to_s}:#{risc.next.to_s}"
|
||||||
def translate_method( method_compiler , translator)
|
instruction = instruction.next
|
||||||
all = []
|
|
||||||
all << translate_cpu( method_compiler , translator )
|
|
||||||
method_compiler.block_compilers.each do |block_compiler|
|
|
||||||
all << translate_cpu(block_compiler , translator)
|
|
||||||
end
|
end
|
||||||
all
|
|
||||||
end
|
|
||||||
|
|
||||||
# compile the callable (method or block) to cpu
|
|
||||||
# return an Assembler that will then translate to binary
|
|
||||||
def translate_cpu(compiler , translator)
|
|
||||||
risc = compiler.risc_instructions
|
|
||||||
cpu_instructions = risc.to_cpu(translator)
|
|
||||||
nekst = risc.next
|
|
||||||
while(nekst)
|
|
||||||
cpu = nekst.to_cpu(translator) # returning nil means no replace
|
|
||||||
cpu_instructions << cpu if cpu
|
|
||||||
nekst = nekst.next
|
|
||||||
end
|
|
||||||
Risc::Assembler.new(compiler.callable , cpu_instructions )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -35,6 +35,7 @@ require_relative "risc/callable_compiler"
|
|||||||
require_relative "risc/method_compiler"
|
require_relative "risc/method_compiler"
|
||||||
require_relative "risc/block_compiler"
|
require_relative "risc/block_compiler"
|
||||||
require_relative "risc/assembler"
|
require_relative "risc/assembler"
|
||||||
|
require_relative "risc/risc_collection"
|
||||||
|
|
||||||
class Integer
|
class Integer
|
||||||
def fits_u8?
|
def fits_u8?
|
||||||
|
@ -4,23 +4,21 @@ module Risc
|
|||||||
# class shared by BlockCompiler and MethodCompiler
|
# class shared by BlockCompiler and MethodCompiler
|
||||||
|
|
||||||
# - risc_instructions: The sequence of risc level instructions that mom was compiled to
|
# - risc_instructions: The sequence of risc level instructions that mom was compiled to
|
||||||
# - cpu_instructions: The sequence of cpu specific instructions that the
|
|
||||||
# risc_instructions was compiled to
|
|
||||||
# Instructions derive from class Instruction and form a linked list
|
# Instructions derive from class Instruction and form a linked list
|
||||||
|
# - constants is an array of Parfait objects that need to be available
|
||||||
|
# - callable is a Method of Block
|
||||||
|
# - current instruction is where addidion happens
|
||||||
|
#
|
||||||
class CallableCompiler
|
class CallableCompiler
|
||||||
|
|
||||||
def initialize( callable )
|
# Must pass the callable (method/block) and the constants that were parsed
|
||||||
|
# Also start instuction, usually a label is mandatory
|
||||||
|
def initialize( callable , constants , start)
|
||||||
@callable = callable
|
@callable = callable
|
||||||
@regs = []
|
@regs = []
|
||||||
@constants = []
|
@constants = constants
|
||||||
@block_compilers = []
|
@block_compilers = []
|
||||||
@risc_instructions = Risc.label(source_name, source_name)
|
@current = @risc_instructions = start
|
||||||
@current = start = @risc_instructions
|
|
||||||
add_code Risc.label( source_name, "return_label")
|
|
||||||
Mom::ReturnSequence.new.to_risc(self)
|
|
||||||
add_code Risc.label( source_name, "unreachable")
|
|
||||||
@current = start
|
|
||||||
reset_regs
|
reset_regs
|
||||||
end
|
end
|
||||||
attr_reader :risc_instructions , :constants , :block_compilers , :callable , :current
|
attr_reader :risc_instructions , :constants , :block_compilers , :callable , :current
|
||||||
@ -32,19 +30,6 @@ module Risc
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# convert the given mom instruction to_risc and then add it (see add_code)
|
|
||||||
# continue down the instruction chain unti depleted
|
|
||||||
# (adding moves the insertion point so the whole mom chain is added as a risc chain)
|
|
||||||
def add_mom( instruction )
|
|
||||||
while( instruction )
|
|
||||||
raise "whats this a #{instruction}" unless instruction.is_a?(Mom::Instruction)
|
|
||||||
#puts "adding mom #{instruction.to_s}:#{instruction.next.to_s}"
|
|
||||||
instruction.to_risc( self )
|
|
||||||
reset_regs
|
|
||||||
#puts "adding risc #{risc.to_s}:#{risc.next.to_s}"
|
|
||||||
instruction = instruction.next
|
|
||||||
end
|
|
||||||
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)
|
||||||
|
@ -1,16 +1,8 @@
|
|||||||
module Mom
|
module Risc
|
||||||
# The Compiler for the Mom level is a collection of Risc level Method compilers,
|
# The Collection for the Risc level is a collection of Risc level Method compilers,
|
||||||
# plus functions to translate from the risc to cpu specific code.
|
# plus functions to translate from the risc to cpu specific code.
|
||||||
#
|
#
|
||||||
# Builtin functions are created here, lazily, when translate is called.
|
class RiscCollection
|
||||||
# Instantiating builtin functions results in a MethodCompiler for that function, and
|
|
||||||
# to avoid confusion, these should be instantiated only once.
|
|
||||||
#
|
|
||||||
# As RubyCompiler pools source at the vool level, when several classes are compiled
|
|
||||||
# from vool to mom, several MomCompilers get instantiated. They must be merged before
|
|
||||||
# proceeding with translate. Thus we have a append method.
|
|
||||||
#
|
|
||||||
class MomCompiler
|
|
||||||
attr_reader :method_compilers
|
attr_reader :method_compilers
|
||||||
|
|
||||||
# Initialize with an array of risc MethodCompilers
|
# Initialize with an array of risc MethodCompilers
|
@ -63,7 +63,7 @@ module RubyX
|
|||||||
# to generate binaries
|
# to generate binaries
|
||||||
def to_risc(platform)
|
def to_risc(platform)
|
||||||
mom = to_mom
|
mom = to_mom
|
||||||
mom.translate(platform)
|
mom.to_risc(platform)
|
||||||
end
|
end
|
||||||
|
|
||||||
# ruby_to_mom does exactly that, it transform the incoming ruby source (string)
|
# ruby_to_mom does exactly that, it transform the incoming ruby source (string)
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
module Vool
|
module Vool
|
||||||
|
# This represents a class at the vool level. Vool is a syntax tree,
|
||||||
|
# so here the only child (or children) is a body.
|
||||||
|
# Body may either be a MethodStatement, or Statements (either empty or
|
||||||
|
# containing MethodStatement)
|
||||||
|
#
|
||||||
|
# We store the class name and the parfait class
|
||||||
|
#
|
||||||
|
# The Parfait class gets created lazily on the way down to mom, ie the clazz
|
||||||
|
# attribute will only be set after to_mom, or a direct call to create_class
|
||||||
class ClassStatement < Statement
|
class ClassStatement < Statement
|
||||||
attr_reader :name, :super_class_name , :body
|
attr_reader :name, :super_class_name , :body
|
||||||
attr_reader :clazz
|
attr_reader :clazz
|
||||||
@ -17,6 +26,10 @@ module Vool
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# This create the Parfait class, and then transforms every method
|
||||||
|
#
|
||||||
|
# As there is no class equivalnet in code, a MomCollection is returned,
|
||||||
|
# which is just a list of Mom::MethodCompilers
|
||||||
def to_mom( _ )
|
def to_mom( _ )
|
||||||
create_class_object
|
create_class_object
|
||||||
method_compilers = body.statements.collect do |node|
|
method_compilers = body.statements.collect do |node|
|
||||||
@ -37,6 +50,10 @@ module Vool
|
|||||||
@body.each(&block) if @body
|
@body.each(&block) if @body
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# This creates the Parfait class. But doesn not hadle reopening yet, so only new classes
|
||||||
|
# Creating the class involves creating the instance_type (or an initial version)
|
||||||
|
# which means knowing all used names. So we go through the code looking for
|
||||||
|
# InstanceVariables or InstanceVariable Assignments, to do that.
|
||||||
def create_class_object
|
def create_class_object
|
||||||
@clazz = Parfait.object_space.get_class_by_name(@name )
|
@clazz = Parfait.object_space.get_class_by_name(@name )
|
||||||
if(@clazz)
|
if(@clazz)
|
||||||
@ -53,6 +70,7 @@ module Vool
|
|||||||
ivar_hash[node.name] = :Object
|
ivar_hash[node.name] = :Object
|
||||||
end
|
end
|
||||||
@clazz.set_instance_type( Parfait::Type.for_hash( @clazz , ivar_hash ) )
|
@clazz.set_instance_type( Parfait::Type.for_hash( @clazz , ivar_hash ) )
|
||||||
|
@clazz
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ module Vool
|
|||||||
|
|
||||||
def to_mom(clazz)
|
def to_mom(clazz)
|
||||||
raise( "no class in #{self}") unless clazz
|
raise( "no class in #{self}") unless clazz
|
||||||
method = clazz.add_method_for(name , make_arg_type , make_frame , body )
|
method = make_method(clazz)
|
||||||
compiler = method.compiler_for(clazz.instance_type)
|
compiler = method.compiler_for(clazz.instance_type)
|
||||||
each do |node| ## TODO: must account for nested blocks (someday)
|
each do |node| ## TODO: must account for nested blocks (someday)
|
||||||
next unless node.is_a?(BlockStatement)
|
next unless node.is_a?(BlockStatement)
|
||||||
@ -18,6 +18,15 @@ module Vool
|
|||||||
compiler
|
compiler
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Class to be passed in is a Parfait class
|
||||||
|
# return VoolMethod
|
||||||
|
#
|
||||||
|
# extracted call to create the VoolMethod as this is the place
|
||||||
|
# where we have all the info. Used in testing.
|
||||||
|
def make_method(clazz)
|
||||||
|
clazz.add_method_for(name , make_arg_type , make_frame , body )
|
||||||
|
end
|
||||||
|
|
||||||
def each(&block)
|
def each(&block)
|
||||||
block.call(self)
|
block.call(self)
|
||||||
@body.each(&block)
|
@body.each(&block)
|
||||||
|
37
test/risc/test_callable_compiler.rb
Normal file
37
test/risc/test_callable_compiler.rb
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
require_relative "helper"
|
||||||
|
module Risc
|
||||||
|
class FakeCallable
|
||||||
|
end
|
||||||
|
class FakeCallableCompiler < CallableCompiler
|
||||||
|
def initialize(a,b,c)
|
||||||
|
super(a,b,c)
|
||||||
|
end
|
||||||
|
def source_name
|
||||||
|
"luke"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
class TestCallableCompiler < MiniTest::Test
|
||||||
|
|
||||||
|
def setup
|
||||||
|
Parfait.boot!({})
|
||||||
|
label = Risc.label("hi","ho")
|
||||||
|
@compiler = FakeCallableCompiler.new(FakeCallable.new , [] , label)
|
||||||
|
end
|
||||||
|
def test_ok
|
||||||
|
assert @compiler
|
||||||
|
end
|
||||||
|
def test_current
|
||||||
|
assert @compiler.current
|
||||||
|
end
|
||||||
|
def test_current_label
|
||||||
|
assert_equal Label , @compiler.current.class
|
||||||
|
assert_equal "ho" , @compiler.current.name
|
||||||
|
end
|
||||||
|
def test_mom
|
||||||
|
assert @compiler.risc_instructions
|
||||||
|
end
|
||||||
|
def test_const
|
||||||
|
assert_equal Array , @compiler.constants.class
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue
Block a user