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
|
class Constant
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class BlockConstant < Constant
|
||||||
|
attr_reader :block
|
||||||
|
def initialize(bl)
|
||||||
|
@block = bl
|
||||||
|
end
|
||||||
|
def to_parfait(compiler)
|
||||||
|
@block
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
class IntegerConstant < Constant
|
class IntegerConstant < Constant
|
||||||
attr_reader :value
|
attr_reader :value
|
||||||
def initialize(value)
|
def initialize(value)
|
||||||
|
@ -43,7 +43,7 @@ module Parfait
|
|||||||
|
|
||||||
def add_block(bl)
|
def add_block(bl)
|
||||||
block = self.blocks
|
block = self.blocks
|
||||||
bl.next = block if(block)
|
bl.set_next(block) if(block)
|
||||||
@blocks = bl
|
@blocks = bl
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ require_relative "risc/parfait_adapter"
|
|||||||
require_relative "risc/parfait_boot"
|
require_relative "risc/parfait_boot"
|
||||||
require_relative "risc/linker"
|
require_relative "risc/linker"
|
||||||
require_relative "risc/method_compiler"
|
require_relative "risc/method_compiler"
|
||||||
|
require_relative "risc/block_compiler"
|
||||||
require_relative "risc/assembler"
|
require_relative "risc/assembler"
|
||||||
|
|
||||||
class Fixnum
|
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")
|
@risc_instructions << Risc.label( name, "unreachable")
|
||||||
@current = @risc_instructions
|
@current = @risc_instructions
|
||||||
@constants = []
|
@constants = []
|
||||||
|
@block_compilers = []
|
||||||
end
|
end
|
||||||
attr_reader :method , :risc_instructions , :constants
|
attr_reader :method , :risc_instructions , :constants
|
||||||
|
|
||||||
# helper method for builtin mainly
|
# helper method for builtin mainly
|
||||||
# the class_name is a symbol, which is resolved to the instance_type of that class
|
# 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 )
|
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
|
raise "create_method #{class_name}.#{class_name.class}" unless class_name.is_a? Symbol
|
||||||
clazz = Parfait.object_space.get_class_by_name! class_name
|
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
|
end
|
||||||
|
|
||||||
# create a method for the given type ( Parfait type object)
|
# create a method for the given type ( Parfait type object)
|
||||||
@ -38,7 +39,7 @@ module Risc
|
|||||||
# args a hash that will be converted to a type
|
# args a hash that will be converted to a type
|
||||||
# the created method is set as the current and the given type too
|
# the created method is set as the current and the given type too
|
||||||
# return the compiler
|
# 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 "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 "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
|
raise "create_method #{method_name}.#{method_name.class}" unless method_name.is_a? Symbol
|
||||||
@ -46,6 +47,10 @@ module Risc
|
|||||||
self.new(method)
|
self.new(method)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def add_block_compiler(compiler)
|
||||||
|
@block_compilers << compiler
|
||||||
|
end
|
||||||
|
|
||||||
# convert the given mom instruction to_risc and then add it (see add_code)
|
# convert the given mom instruction to_risc and then add it (see add_code)
|
||||||
# continue down the instruction chain unti depleted
|
# continue down the instruction chain unti depleted
|
||||||
# (adding moves the insertion point so the whole mom chain is added as a risc chain)
|
# (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
|
# This means we do the compiler here (rather than to_mom, which is in
|
||||||
# fact never called)
|
# fact never called)
|
||||||
def slot_definition(compiler)
|
def slot_definition(compiler)
|
||||||
@parfait_block = to_parfait(compiler)
|
return Mom::SlotDefinition.new(Mom::BlockConstant.new(parfait_block(compiler)) , [])
|
||||||
return Mom::SlotDefinition.new(Mom::IntegerConstant.new(1) , [])
|
|
||||||
end
|
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 )
|
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
|
end
|
||||||
|
|
||||||
def each(&block)
|
def each(&block)
|
||||||
@ -31,10 +38,14 @@ module Vool
|
|||||||
BlockStatement.new( @args , @body.normalize)
|
BlockStatement.new( @args , @body.normalize)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
# create the parfait block (parfait representation of the block, a Callable similar
|
||||||
def to_parfait(compiler)
|
# to CallableMethod)
|
||||||
compiler.method.create_block( make_arg_type , make_frame)
|
def parfait_block(compiler)
|
||||||
|
return @parfait_block if @parfait_block
|
||||||
|
@parfait_block = compiler.method.create_block( make_arg_type , make_frame)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
def make_arg_type( )
|
def make_arg_type( )
|
||||||
type_hash = {}
|
type_hash = {}
|
||||||
@args.each {|arg| type_hash[arg] = :Object }
|
@args.each {|arg| type_hash[arg] = :Object }
|
||||||
|
@ -11,7 +11,11 @@ module Vool
|
|||||||
def to_mom(clazz)
|
def to_mom(clazz)
|
||||||
@clazz = clazz || raise( "no class in #{self}")
|
@clazz = clazz || raise( "no class in #{self}")
|
||||||
method = @clazz.add_method_for(name , make_arg_type , make_frame , body )
|
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
|
end
|
||||||
|
|
||||||
def each(&block)
|
def each(&block)
|
||||||
|
@ -37,7 +37,10 @@ module MomCompile
|
|||||||
assert_equal Risc::MethodCompiler , compiler.class
|
assert_equal Risc::MethodCompiler , compiler.class
|
||||||
@method.source.to_mom( compiler )
|
@method.source.to_mom( compiler )
|
||||||
end
|
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)
|
def compile_mom(input)
|
||||||
Risc.boot!
|
Risc.boot!
|
||||||
RubyX::RubyXCompiler.new(input).ruby_to_mom
|
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…
x
Reference in New Issue
Block a user