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
|
||||
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)
|
||||
# the added instruction will become the new insertion point
|
||||
def add_code( instruction )
|
||||
|
@ -37,49 +37,26 @@ module Mom
|
||||
self
|
||||
end
|
||||
|
||||
# Translate code to whatever cpu is specified.
|
||||
# Currently only :arm and :interpret
|
||||
#
|
||||
# Translating means translating the initial jump
|
||||
# and then translating all methods
|
||||
def translate( platform_sym )
|
||||
platform_sym = platform_sym.to_s.capitalize
|
||||
platform = Risc::Platform.for(platform_sym)
|
||||
assemblers = translate_methods( platform.translator )
|
||||
Risc::Linker.new(platform , assemblers , constants)
|
||||
def to_risc( )
|
||||
riscs = []
|
||||
# to_risc all compilers
|
||||
# for each suffling constnts and fist label, then all instructions (see below)
|
||||
# then create risc collection
|
||||
Risc::RiscCollection.new(riscs)
|
||||
end
|
||||
|
||||
# go through all methods and translate them to cpu, given the translator
|
||||
def translate_methods(translator)
|
||||
compilers.collect do |compiler|
|
||||
#log.debug "Translate method #{compiler.method.name}"
|
||||
translate_method(compiler , translator)
|
||||
end.flatten
|
||||
end
|
||||
|
||||
# translate one method, which means the method itself and all blocks inside it
|
||||
# returns an array of assemblers
|
||||
def translate_method( method_compiler , translator)
|
||||
all = []
|
||||
all << translate_cpu( method_compiler , translator )
|
||||
method_compiler.block_compilers.each do |block_compiler|
|
||||
all << translate_cpu(block_compiler , translator)
|
||||
# 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
|
||||
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
|
||||
|
@ -35,6 +35,7 @@ require_relative "risc/callable_compiler"
|
||||
require_relative "risc/method_compiler"
|
||||
require_relative "risc/block_compiler"
|
||||
require_relative "risc/assembler"
|
||||
require_relative "risc/risc_collection"
|
||||
|
||||
class Integer
|
||||
def fits_u8?
|
||||
|
@ -4,23 +4,21 @@ module Risc
|
||||
# class shared by BlockCompiler and MethodCompiler
|
||||
|
||||
# - 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
|
||||
|
||||
# - 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
|
||||
|
||||
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
|
||||
@regs = []
|
||||
@constants = []
|
||||
@constants = constants
|
||||
@block_compilers = []
|
||||
@risc_instructions = Risc.label(source_name, source_name)
|
||||
@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
|
||||
@current = @risc_instructions = start
|
||||
reset_regs
|
||||
end
|
||||
attr_reader :risc_instructions , :constants , :block_compilers , :callable , :current
|
||||
@ -32,19 +30,6 @@ module Risc
|
||||
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)
|
||||
def add_constant(const)
|
||||
|
@ -1,16 +1,8 @@
|
||||
module Mom
|
||||
# The Compiler for the Mom level is a collection of Risc level Method compilers,
|
||||
module Risc
|
||||
# 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.
|
||||
#
|
||||
# Builtin functions are created here, lazily, when translate is called.
|
||||
# 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
|
||||
class RiscCollection
|
||||
attr_reader :method_compilers
|
||||
|
||||
# Initialize with an array of risc MethodCompilers
|
@ -63,7 +63,7 @@ module RubyX
|
||||
# to generate binaries
|
||||
def to_risc(platform)
|
||||
mom = to_mom
|
||||
mom.translate(platform)
|
||||
mom.to_risc(platform)
|
||||
end
|
||||
|
||||
# ruby_to_mom does exactly that, it transform the incoming ruby source (string)
|
||||
|
@ -1,4 +1,13 @@
|
||||
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
|
||||
attr_reader :name, :super_class_name , :body
|
||||
attr_reader :clazz
|
||||
@ -17,6 +26,10 @@ module Vool
|
||||
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( _ )
|
||||
create_class_object
|
||||
method_compilers = body.statements.collect do |node|
|
||||
@ -37,6 +50,10 @@ module Vool
|
||||
@body.each(&block) if @body
|
||||
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
|
||||
@clazz = Parfait.object_space.get_class_by_name(@name )
|
||||
if(@clazz)
|
||||
@ -53,6 +70,7 @@ module Vool
|
||||
ivar_hash[node.name] = :Object
|
||||
end
|
||||
@clazz.set_instance_type( Parfait::Type.for_hash( @clazz , ivar_hash ) )
|
||||
@clazz
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -9,7 +9,7 @@ module Vool
|
||||
|
||||
def to_mom(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)
|
||||
each do |node| ## TODO: must account for nested blocks (someday)
|
||||
next unless node.is_a?(BlockStatement)
|
||||
@ -18,6 +18,15 @@ module Vool
|
||||
compiler
|
||||
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)
|
||||
block.call(self)
|
||||
@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