start with block_compiler
as a copy of method_compiler re-merge later, when we know what's needed
This commit is contained in:
parent
7231f301ba
commit
dd544214b3
@ -5,6 +5,16 @@ module Mom
|
||||
class Constant
|
||||
end
|
||||
|
||||
class BlockConstant < Constant
|
||||
attr_reader :block
|
||||
def initialize(bl)
|
||||
@block = bl
|
||||
end
|
||||
def to_parfait(compiler)
|
||||
@block
|
||||
end
|
||||
end
|
||||
|
||||
class IntegerConstant < Constant
|
||||
attr_reader :value
|
||||
def initialize(value)
|
||||
|
@ -43,7 +43,7 @@ module Parfait
|
||||
|
||||
def add_block(bl)
|
||||
block = self.blocks
|
||||
bl.next = block if(block)
|
||||
bl.set_next(block) if(block)
|
||||
@blocks = bl
|
||||
end
|
||||
|
||||
|
@ -27,6 +27,7 @@ require_relative "risc/parfait_adapter"
|
||||
require_relative "risc/parfait_boot"
|
||||
require_relative "risc/linker"
|
||||
require_relative "risc/method_compiler"
|
||||
require_relative "risc/block_compiler"
|
||||
require_relative "risc/assembler"
|
||||
|
||||
class Fixnum
|
||||
|
21
lib/risc/block_compiler.rb
Normal file
21
lib/risc/block_compiler.rb
Normal file
@ -0,0 +1,21 @@
|
||||
module Risc
|
||||
|
||||
# A BlockCompiler is much like a Mehtodcompiler, exept for blocks
|
||||
#
|
||||
class BlockCompiler
|
||||
|
||||
attr_reader :block , :risc_instructions , :constants
|
||||
|
||||
def initialize( block , method)
|
||||
@method = method
|
||||
@regs = []
|
||||
@block = block
|
||||
name = "#{method.self_type.name}.init"
|
||||
@risc_instructions = Risc.label(name, name)
|
||||
@risc_instructions << Risc.label( name, "unreachable")
|
||||
@current = @risc_instructions
|
||||
@constants = []
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -19,18 +19,19 @@ module Risc
|
||||
@risc_instructions << Risc.label( name, "unreachable")
|
||||
@current = @risc_instructions
|
||||
@constants = []
|
||||
@block_compilers = []
|
||||
end
|
||||
attr_reader :method , :risc_instructions , :constants
|
||||
|
||||
# helper method for builtin mainly
|
||||
# the class_name is a symbol, which is resolved to the instance_type of that class
|
||||
#
|
||||
# return compiler_self_type with the resolved type
|
||||
# return compiler_for_type with the resolved type
|
||||
#
|
||||
def self.compiler_for_class( class_name , method_name , args , frame )
|
||||
raise "create_method #{class_name}.#{class_name.class}" unless class_name.is_a? Symbol
|
||||
clazz = Parfait.object_space.get_class_by_name! class_name
|
||||
compiler_self_type( clazz.instance_type , method_name , args , frame)
|
||||
compiler_for_type( clazz.instance_type , method_name , args , frame)
|
||||
end
|
||||
|
||||
# create a method for the given type ( Parfait type object)
|
||||
@ -38,14 +39,18 @@ module Risc
|
||||
# args a hash that will be converted to a type
|
||||
# the created method is set as the current and the given type too
|
||||
# return the compiler
|
||||
def self.compiler_self_type( type , method_name , args , frame)
|
||||
def self.compiler_for_type( type , method_name , args , frame)
|
||||
raise "create_method #{type.inspect} is not a Type" unless type.is_a? Parfait::Type
|
||||
raise "Args must be Type #{args}" unless args.is_a?(Parfait::Type)
|
||||
raise "create_method #{method_name}.#{method_name.class}" unless method_name.is_a? Symbol
|
||||
method = type.create_method( method_name , args , frame)
|
||||
self.new(method)
|
||||
end
|
||||
|
||||
|
||||
def add_block_compiler(compiler)
|
||||
@block_compilers << compiler
|
||||
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)
|
||||
|
@ -14,12 +14,19 @@ module Vool
|
||||
# This means we do the compiler here (rather than to_mom, which is in
|
||||
# fact never called)
|
||||
def slot_definition(compiler)
|
||||
@parfait_block = to_parfait(compiler)
|
||||
return Mom::SlotDefinition.new(Mom::IntegerConstant.new(1) , [])
|
||||
return Mom::SlotDefinition.new(Mom::BlockConstant.new(parfait_block(compiler)) , [])
|
||||
end
|
||||
|
||||
# create a block, a compiler for it, comile the bock and add the compiler(code)
|
||||
# to the method compiler for further processing
|
||||
def to_mom( compiler )
|
||||
# raise "should not be called "
|
||||
parfait_block = self.parfait_block(compiler)
|
||||
block_compiler = Risc::BlockCompiler.new( parfait_block , compiler.method )
|
||||
compiler.add_block_compiler(block_compiler)
|
||||
puts "BODY #{body}"
|
||||
head = body.to_mom( block_compiler )
|
||||
block_compiler.add_mom(head)
|
||||
block_compiler
|
||||
end
|
||||
|
||||
def each(&block)
|
||||
@ -31,10 +38,14 @@ module Vool
|
||||
BlockStatement.new( @args , @body.normalize)
|
||||
end
|
||||
|
||||
private
|
||||
def to_parfait(compiler)
|
||||
compiler.method.create_block( make_arg_type , make_frame)
|
||||
# create the parfait block (parfait representation of the block, a Callable similar
|
||||
# to CallableMethod)
|
||||
def parfait_block(compiler)
|
||||
return @parfait_block if @parfait_block
|
||||
@parfait_block = compiler.method.create_block( make_arg_type , make_frame)
|
||||
end
|
||||
|
||||
private
|
||||
def make_arg_type( )
|
||||
type_hash = {}
|
||||
@args.each {|arg| type_hash[arg] = :Object }
|
||||
|
@ -11,7 +11,11 @@ module Vool
|
||||
def to_mom(clazz)
|
||||
@clazz = clazz || raise( "no class in #{self}")
|
||||
method = @clazz.add_method_for(name , make_arg_type , make_frame , body )
|
||||
method.compiler_for(clazz.instance_type)
|
||||
compiler = method.compiler_for(clazz.instance_type)
|
||||
each do |node| ## TODO: must account for nested blocks (someday)
|
||||
node.to_mom(compiler) if node.is_a?(BlockStatement)
|
||||
end
|
||||
compiler
|
||||
end
|
||||
|
||||
def each(&block)
|
||||
|
@ -37,7 +37,10 @@ module MomCompile
|
||||
assert_equal Risc::MethodCompiler , compiler.class
|
||||
@method.source.to_mom( compiler )
|
||||
end
|
||||
|
||||
def compile_first_block( block_input )
|
||||
mom = compile_first_method( "main_local = 5 ; self.main{|val| #{block_input}}")
|
||||
mom.next(4) # ignore local assign (1) and call (3)
|
||||
end
|
||||
def compile_mom(input)
|
||||
Risc.boot!
|
||||
RubyX::RubyXCompiler.new(input).ruby_to_mom
|
||||
|
0
test/vool/blocks/helper.rb
Normal file
0
test/vool/blocks/helper.rb
Normal file
91
test/vool/blocks/test_assign.rb
Normal file
91
test/vool/blocks/test_assign.rb
Normal file
@ -0,0 +1,91 @@
|
||||
require_relative "../helper"
|
||||
|
||||
module VoolBlocks
|
||||
class TestAssignMom < MiniTest::Test
|
||||
include MomCompile
|
||||
|
||||
def setup
|
||||
Parfait.boot!
|
||||
Risc::Builtin.boot_functions
|
||||
@ins = compile_first_block( "local = 5")
|
||||
end
|
||||
|
||||
def test_class_compiles
|
||||
assert_equal Mom::SlotLoad , @ins.class , @ins
|
||||
end
|
||||
def pest_slot_is_set
|
||||
assert @ins.left
|
||||
end
|
||||
def pest_slot_starts_at_message
|
||||
assert_equal :message , @ins.left.known_object
|
||||
end
|
||||
def pest_slot_gets_self
|
||||
assert_equal :frame , @ins.left.slots[0]
|
||||
end
|
||||
def pest_slot_assigns_to_local
|
||||
assert_equal :main_local , @ins.left.slots[-1]
|
||||
end
|
||||
def pest_slot_assigns_something
|
||||
assert @ins.right
|
||||
end
|
||||
def pest_slot_assigns_int
|
||||
assert_equal Mom::IntegerConstant , @ins.right.known_object.class
|
||||
end
|
||||
end
|
||||
|
||||
#otherwise as above, but assigning instance, so should get a SlotLoad
|
||||
class TestAssignMomInstanceToLocal < MiniTest::Test
|
||||
include MomCompile
|
||||
def setup
|
||||
Parfait.boot!
|
||||
@ins = compile_first_method( "@a = 5 ; local = @a")
|
||||
end
|
||||
def pest_class_compiles
|
||||
assert_equal Mom::SlotLoad , @ins.next.class , @ins
|
||||
end
|
||||
end
|
||||
|
||||
#compiling to an argument should result in different second parameter in the slot array
|
||||
class TestAssignToArg < MiniTest::Test
|
||||
include MomCompile
|
||||
|
||||
def setup
|
||||
Parfait.boot!
|
||||
@ins = compile_first_method( "arg = 5")
|
||||
end
|
||||
|
||||
def pest_class_compiles
|
||||
assert_equal Mom::SlotLoad , @ins.class , @ins
|
||||
end
|
||||
def pest_slot_is_set
|
||||
assert @ins.left
|
||||
end
|
||||
def pest_slot_starts_at_message
|
||||
assert_equal :message , @ins.left.known_object
|
||||
end
|
||||
def pest_slot_gets_self
|
||||
assert_equal :arguments , @ins.left.slots[0]
|
||||
end
|
||||
def pest_slot_assigns_to_local
|
||||
assert_equal :arg , @ins.left.slots[-1]
|
||||
end
|
||||
end
|
||||
|
||||
class TestAssignMomToInstance < MiniTest::Test
|
||||
include MomCompile
|
||||
def setup
|
||||
Parfait.boot!
|
||||
end
|
||||
def pest_assigns_const
|
||||
@ins = compile_first_method( "@a = 5")
|
||||
assert_equal Mom::SlotLoad , @ins.class , @ins
|
||||
assert_equal Mom::IntegerConstant , @ins.right.known_object.class , @ins
|
||||
end
|
||||
def pest_assigns_move
|
||||
@ins = compile_first_method( "@a = arg")
|
||||
assert_equal Mom::SlotLoad , @ins.class , @ins
|
||||
assert_equal Mom::SlotDefinition , @ins.right.class , @ins
|
||||
end
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in New Issue
Block a user