starting to_risc descent
just fleshing it for now
This commit is contained in:
parent
b297650b78
commit
96800fd8fd
@ -16,6 +16,9 @@ module Mom
|
|||||||
def initialize(name)
|
def initialize(name)
|
||||||
@name = name
|
@name = name
|
||||||
end
|
end
|
||||||
|
def to_risc(compiler)
|
||||||
|
Risc::Label.new(self,name)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -16,6 +16,11 @@ module Mom
|
|||||||
def initialize(method)
|
def initialize(method)
|
||||||
@method = method
|
@method = method
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def to_risc(compiler)
|
||||||
|
Risc::Label.new(self,method.name)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,5 +12,9 @@ module Mom
|
|||||||
def initialize(left, right)
|
def initialize(left, right)
|
||||||
@left , @right = left , right
|
@left , @right = left , right
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def to_risc(compiler)
|
||||||
|
Risc::Label.new(self,"nosense")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -33,6 +33,11 @@ module Mom
|
|||||||
raise "left not SlotDefinition, #{left}" unless left.is_a? SlotDefinition
|
raise "left not SlotDefinition, #{left}" unless left.is_a? SlotDefinition
|
||||||
# raise "right not Mom, #{right.to_rxf}" unless right.class.name.include?("Mom")
|
# raise "right not Mom, #{right.to_rxf}" unless right.class.name.include?("Mom")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def to_risc(compiler)
|
||||||
|
Risc::Label.new(self,"nosense")
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# A SlotConstant moves a constant into a known Slot.
|
# A SlotConstant moves a constant into a known Slot.
|
||||||
@ -52,6 +57,9 @@ module Mom
|
|||||||
|
|
||||||
#SlotMove is a SlotLoad where the right side is a slot, just like the left.
|
#SlotMove is a SlotLoad where the right side is a slot, just like the left.
|
||||||
class SlotMove < SlotLoad
|
class SlotMove < SlotLoad
|
||||||
|
def to_risc(compiler)
|
||||||
|
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class SlotDefinition
|
class SlotDefinition
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
module Mom
|
module Mom
|
||||||
class Statement
|
class Statement
|
||||||
|
include Common::List
|
||||||
# flattening will change the structure from a tree to a linked list (and use
|
# flattening will change the structure from a tree to a linked list (and use
|
||||||
# nekst to do so)
|
# nekst to do so)
|
||||||
def flatten(options = {})
|
def flatten(options = {})
|
||||||
@ -18,6 +19,12 @@ module Mom
|
|||||||
flat
|
flat
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def initialize(arr)
|
||||||
|
super(arr)
|
||||||
|
arr.each {|s|
|
||||||
|
raise "Not a Statement #{s}" unless s.is_a?( Statement) or s.is_a?(Instruction)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -18,5 +18,10 @@ module Mom
|
|||||||
def initialize(condition)
|
def initialize(condition)
|
||||||
@condition = condition
|
@condition = condition
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def to_risc(compiler)
|
||||||
|
Risc::Label.new(self,"nosense")
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -11,13 +11,13 @@ module Mom
|
|||||||
end
|
end
|
||||||
|
|
||||||
def flatten(options = {})
|
def flatten(options = {})
|
||||||
cond_label = Label.new( "cond_label_#{object_id}")
|
|
||||||
head = cond_label
|
|
||||||
head.append hoisted.flatten
|
|
||||||
merge_label = Label.new( "merge_label_#{object_id}")
|
merge_label = Label.new( "merge_label_#{object_id}")
|
||||||
head.append condition.flatten( true_label: cond_label , false_label: merge_label)
|
cond_label = Label.new( "cond_label_#{object_id}")
|
||||||
head.append merge_label
|
@nekst = cond_label
|
||||||
head
|
@nekst.append(hoisted.flatten) if hoisted
|
||||||
|
@nekst.append condition.flatten( true_label: cond_label , false_label: merge_label)
|
||||||
|
@nekst.append merge_label
|
||||||
|
@nekst
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -18,7 +18,7 @@ module Risc
|
|||||||
@source = source
|
@source = source
|
||||||
@next = nekst
|
@next = nekst
|
||||||
return unless source
|
return unless source
|
||||||
raise "Source must be string or ast node, not #{source.class}" unless source.is_a?(String) or source.is_a?(Vm::Code)
|
raise "Source must be string or ast node, not #{source.class}" unless source.is_a?(String) or source.is_a?(Mom::Instruction)
|
||||||
end
|
end
|
||||||
attr_reader :source
|
attr_reader :source
|
||||||
|
|
||||||
|
@ -33,14 +33,10 @@ module Vool
|
|||||||
locals_type = make_locals
|
locals_type = make_locals
|
||||||
method = Parfait::VoolMethod.new(name , args_type , locals_type , body )
|
method = Parfait::VoolMethod.new(name , args_type , locals_type , body )
|
||||||
@clazz.add_method( method )
|
@clazz.add_method( method )
|
||||||
end
|
typed_method = method.create_parfait_method(clazz.instance_type)
|
||||||
|
compiler = Risc::MethodCompiler.new( typed_method ).init_method
|
||||||
def compile_methods(clazz , methods)
|
head = @body.to_mom( method ).flatten
|
||||||
methods.each do |method|
|
head.to_risc(compiler)
|
||||||
code = Passes::MethodCompiler.new(method).get_code
|
|
||||||
typed_method = method.create_parfait_method(clazz.instance_type)
|
|
||||||
Risc::MethodCompiler.new( typed_method ).init_method.process( code )
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
81
test/mom/to_risc/helper.rb
Normal file
81
test/mom/to_risc/helper.rb
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
require_relative '../helper'
|
||||||
|
|
||||||
|
module Risc
|
||||||
|
module SpaceHack
|
||||||
|
# test hack to in place change object type
|
||||||
|
def add_space_field(name,type)
|
||||||
|
class_type = Parfait.object_space.get_class_by_name(:Space).instance_type
|
||||||
|
class_type.send(:private_add_instance_variable, name , type)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
module ExpressionHelper
|
||||||
|
include SpaceHack
|
||||||
|
|
||||||
|
def check
|
||||||
|
Risc.machine.boot unless Risc.machine.booted
|
||||||
|
compiler = Vm::MethodCompiler.new Parfait.object_space.get_main
|
||||||
|
code = Vm.ast_to_code @input
|
||||||
|
assert code.to_s , @input
|
||||||
|
produced = compiler.process( code )
|
||||||
|
assert @output , "No output given"
|
||||||
|
assert_equal produced.class , @output , "Wrong class"
|
||||||
|
produced
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
module Statements
|
||||||
|
include AST::Sexp
|
||||||
|
include CleanCompile
|
||||||
|
include SpaceHack
|
||||||
|
|
||||||
|
def setup
|
||||||
|
Risc.machine.boot # force boot to reset main
|
||||||
|
end
|
||||||
|
|
||||||
|
def preamble
|
||||||
|
[Label, SlotToReg , LoadConstant, RegToSlot, LoadConstant,RegToSlot, LoadConstant, SlotToReg, SlotToReg ]
|
||||||
|
end
|
||||||
|
def postamble
|
||||||
|
[ Label, FunctionReturn]
|
||||||
|
end
|
||||||
|
def check_nil
|
||||||
|
assert @expect , "No output given"
|
||||||
|
|
||||||
|
Vool::VoolCompiler.ruby_to_vool "class Space; def main(arg);#{@input};end;end"
|
||||||
|
|
||||||
|
produced = Parfait.object_space.get_main.instructions
|
||||||
|
compare_instructions produced , @expect
|
||||||
|
end
|
||||||
|
def check_return
|
||||||
|
was = check_nil
|
||||||
|
raise was if was
|
||||||
|
Parfait.object_space.get_main.instructions
|
||||||
|
end
|
||||||
|
|
||||||
|
def compare_instructions( instruction , expect )
|
||||||
|
index = 0
|
||||||
|
all = instruction.to_arr
|
||||||
|
full_expect = preamble + expect + postamble
|
||||||
|
full_expect = expect
|
||||||
|
begin
|
||||||
|
should = full_expect[index]
|
||||||
|
return "No instruction at #{index}" unless should
|
||||||
|
return "Expected at #{index+1}\n#{should(all)}" unless instruction.class == should
|
||||||
|
index += 1
|
||||||
|
instruction = instruction.next
|
||||||
|
end while( instruction )
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
def should( all )
|
||||||
|
#preamble.each {all.shift}
|
||||||
|
#postamble.each {all.pop}
|
||||||
|
str = all.to_s.gsub("Risc::","")
|
||||||
|
ret = ""
|
||||||
|
str.split(",").each_slice(6).each do |line|
|
||||||
|
ret += " " + line.join(",") + " ,\n"
|
||||||
|
end
|
||||||
|
ret
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
112
test/mom/to_risc/test_assignment.rb
Normal file
112
test/mom/to_risc/test_assignment.rb
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
|
||||||
|
require_relative 'helper'
|
||||||
|
|
||||||
|
module Risc
|
||||||
|
class TestAssignStatement < MiniTest::Test
|
||||||
|
include Statements
|
||||||
|
|
||||||
|
def test_assign_op
|
||||||
|
Parfait.object_space.get_main.add_local(:r , :Integer)
|
||||||
|
|
||||||
|
@input = "r = 10.mod4"
|
||||||
|
|
||||||
|
@expect = [Label, LoadConstant, SlotToReg, RegToSlot, Label, FunctionReturn]
|
||||||
|
assert_nil msg = check_nil , msg
|
||||||
|
end
|
||||||
|
|
||||||
|
def pest_assign_ivar_notpresent
|
||||||
|
@input =s(:statements, s(:i_assignment, s(:ivar, :r), s(:int, 5)))
|
||||||
|
@expect = []
|
||||||
|
assert_raises{ check_nil }
|
||||||
|
end
|
||||||
|
|
||||||
|
def pest_assign_ivar
|
||||||
|
add_space_field(:r , :Integer)
|
||||||
|
|
||||||
|
@input =s(:statements, s(:i_assignment, s(:ivar, :r), s(:int, 5)))
|
||||||
|
|
||||||
|
@expect = [Label, LoadConstant, SlotToReg, RegToSlot, LoadConstant, SlotToReg ,
|
||||||
|
RegToSlot, Label, FunctionReturn]
|
||||||
|
assert_nil msg = check_nil , msg
|
||||||
|
end
|
||||||
|
|
||||||
|
def pest_assign_local_assign
|
||||||
|
Parfait.object_space.get_main.add_local(:r , :Integer)
|
||||||
|
|
||||||
|
@input = s(:statements, s(:l_assignment, s(:local, :r), s(:int, 5)))
|
||||||
|
|
||||||
|
@expect = [Label, LoadConstant, SlotToReg, RegToSlot, LoadConstant, SlotToReg ,
|
||||||
|
RegToSlot, Label, FunctionReturn]
|
||||||
|
assert_nil msg = check_nil , msg
|
||||||
|
end
|
||||||
|
|
||||||
|
def pest_assign_call
|
||||||
|
Parfait.object_space.get_main.add_local(:r , :Object)
|
||||||
|
@input = s(:statements, s(:l_assignment, s(:local, :r), s(:call, :main, s(:arguments))))
|
||||||
|
@expect = [Label, SlotToReg, SlotToReg, RegToSlot, LoadConstant, RegToSlot ,
|
||||||
|
LoadConstant, SlotToReg, RegToSlot, LoadConstant, RegToSlot, RiscTransfer ,
|
||||||
|
FunctionCall, Label, RiscTransfer, SlotToReg, SlotToReg, SlotToReg ,
|
||||||
|
RegToSlot, LoadConstant, SlotToReg, RegToSlot, Label, FunctionReturn]
|
||||||
|
assert_nil msg = check_nil , msg
|
||||||
|
end
|
||||||
|
|
||||||
|
def pest_named_list_get
|
||||||
|
Parfait.object_space.get_main.add_local(:r , :Integer)
|
||||||
|
@input = s(:statements, s(:l_assignment, s(:local, :r), s(:int, 5)), s(:return, s(:local, :r)))
|
||||||
|
@expect = [Label, LoadConstant, SlotToReg, RegToSlot, SlotToReg, SlotToReg ,
|
||||||
|
RegToSlot, LoadConstant, SlotToReg, RegToSlot, Label, FunctionReturn]
|
||||||
|
was = check_return
|
||||||
|
get = was.next(5)
|
||||||
|
assert_equal SlotToReg , get.class
|
||||||
|
assert_equal 1 + 1, get.index , "Get to named_list index must be offset, not #{get.index}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def pest_assign_local_int
|
||||||
|
Parfait.object_space.get_main.add_local(:r , :Integer)
|
||||||
|
@input = s(:statements, s(:l_assignment, s(:local, :r), s(:int, 5)) )
|
||||||
|
@expect = [Label, LoadConstant, SlotToReg, RegToSlot, LoadConstant, SlotToReg ,
|
||||||
|
RegToSlot, Label, FunctionReturn]
|
||||||
|
was = check_return
|
||||||
|
set = was.next(3)
|
||||||
|
assert_equal RegToSlot , set.class
|
||||||
|
assert_equal 1 + 1, set.index , "Set to named_list index must be offset, not #{set.index}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def pest_misassign_local
|
||||||
|
Parfait.object_space.get_main.add_local(:r , :Integer)
|
||||||
|
@input = s(:statements, s(:l_assignment, s(:local, :r), s(:string, "5")) )
|
||||||
|
@expect = [Label, LoadConstant, SlotToReg, RegToSlot, Label, FunctionReturn]
|
||||||
|
assert_raises {check }
|
||||||
|
end
|
||||||
|
|
||||||
|
def pest_assign_arg
|
||||||
|
Parfait.object_space.get_main.add_argument(:blar , :Integer)
|
||||||
|
@input = s(:statements, s(:a_assignment, s(:arg, :blar), s(:int, 5)))
|
||||||
|
@expect = [Label, LoadConstant, SlotToReg, RegToSlot, LoadConstant, SlotToReg ,
|
||||||
|
RegToSlot, Label, FunctionReturn]
|
||||||
|
was = check_return
|
||||||
|
set = was.next(3)
|
||||||
|
assert_equal RegToSlot , set.class
|
||||||
|
assert_equal 1 + 1, set.index , "Set to args index must be offset, not #{set.index}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def pest_misassign_arg
|
||||||
|
Parfait.object_space.get_main.add_argument(:blar , :Integer)
|
||||||
|
@input = s(:statements, s(:a_assignment, s(:arg, :blar), s(:string, "5")))
|
||||||
|
@expect = [Label, LoadConstant, SlotToReg, RegToSlot, Label, FunctionReturn]
|
||||||
|
assert_raises {check }
|
||||||
|
end
|
||||||
|
|
||||||
|
def pest_arg_get
|
||||||
|
# have to define bar externally, just because redefining main. Otherwise that would be automatic
|
||||||
|
Parfait.object_space.get_main.add_argument(:balr , :Integer)
|
||||||
|
@input = s(:statements, s(:return, s(:arg, :balr)))
|
||||||
|
@expect = [Label, SlotToReg, SlotToReg, RegToSlot, LoadConstant, SlotToReg ,
|
||||||
|
RegToSlot, Label, FunctionReturn]
|
||||||
|
was = check_return
|
||||||
|
get = was.next(2)
|
||||||
|
assert_equal SlotToReg , get.class
|
||||||
|
assert_equal 1 + 1, get.index , "Get to args index must be offset, not #{get.index}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -16,12 +16,12 @@ module Vool
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_compile_class_one
|
def test_compile_class_one
|
||||||
itest = compile_in_test "def meth; @ivar; end"
|
itest = compile_in_test "def meth; @ivar = 5; end"
|
||||||
assert itest.instance_type.names.include?(:ivar) , itest.instance_type.names.inspect
|
assert itest.instance_type.names.include?(:ivar) , itest.instance_type.names.inspect
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_compile_class_two
|
def test_compile_class_two
|
||||||
itest = compile_in_test "def meth; @ivar; end;def meth2(arg); @trivar = 5; end"
|
itest = compile_in_test "def meth; @ivar = 5; end;def meth2(arg); @trivar = 5; end"
|
||||||
assert itest.instance_type.names.include?(:trivar) , itest.instance_type.names.inspect
|
assert itest.instance_type.names.include?(:trivar) , itest.instance_type.names.inspect
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ module Vool
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_class_body_is_scope
|
def test_class_body_is_scope
|
||||||
clazz = VoolCompiler.ruby_to_vool in_Test("def meth; @ivar ;end")
|
clazz = VoolCompiler.ruby_to_vool in_Test("def meth; @ivar = 5 ;end")
|
||||||
assert_equal ScopeStatement , clazz.body.class
|
assert_equal ScopeStatement , clazz.body.class
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ module Vool
|
|||||||
end
|
end
|
||||||
|
|
||||||
def create_method
|
def create_method
|
||||||
VoolCompiler.ruby_to_vool in_Test("def meth; @ivar ;end")
|
VoolCompiler.ruby_to_vool in_Test("def meth; @ivar = 5;end")
|
||||||
test = Parfait.object_space.get_class_by_name(:Test)
|
test = Parfait.object_space.get_class_by_name(:Test)
|
||||||
test.get_method(:meth)
|
test.get_method(:meth)
|
||||||
end
|
end
|
||||||
@ -17,7 +17,7 @@ module Vool
|
|||||||
def test_method_has_source
|
def test_method_has_source
|
||||||
method = create_method
|
method = create_method
|
||||||
assert_equal ScopeStatement , method.source.class
|
assert_equal ScopeStatement , method.source.class
|
||||||
assert_equal InstanceVariable , method.source.statements.first.class
|
assert_equal IvarAssignment , method.source.statements.first.class
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_method_has_no_locals
|
def test_method_has_no_locals
|
||||||
@ -36,24 +36,23 @@ module Vool
|
|||||||
assert_equal Parfait::VoolMethod , method.class
|
assert_equal Parfait::VoolMethod , method.class
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def test_creates_method_statement_in_class
|
def test_creates_method_statement_in_class
|
||||||
clazz = VoolCompiler.ruby_to_vool in_Test("def meth; @ivar ;end")
|
clazz = VoolCompiler.ruby_to_vool in_Test("def meth; @ivar = 5 ;end")
|
||||||
assert_equal MethodStatement , clazz.body.statements.first.class
|
assert_equal MethodStatement , clazz.body.statements.first.class
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_parfait_class_creation
|
def test_parfait_class_creation
|
||||||
clazz = VoolCompiler.ruby_to_vool in_Test("def meth; @ivar ;end")
|
clazz = VoolCompiler.ruby_to_vool in_Test("def meth; @ivar = 5;end")
|
||||||
assert_equal Parfait::Class , clazz.body.statements.first.clazz.class
|
assert_equal Parfait::Class , clazz.body.statements.first.clazz.class
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_method_statement_has_class
|
def test_method_statement_has_class
|
||||||
clazz = VoolCompiler.ruby_to_vool in_Test("def meth; @ivar ;end")
|
clazz = VoolCompiler.ruby_to_vool in_Test("def meth; @ivar = 5;end")
|
||||||
assert clazz.body.statements.first.clazz
|
assert clazz.body.statements.first.clazz
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_method_statement_has_class_in_main
|
def test_method_statement_has_class_in_main
|
||||||
clazz = VoolCompiler.ruby_to_vool as_main("def meth; @ivar ;end")
|
clazz = VoolCompiler.ruby_to_vool as_main("def meth; @ivar = 5;end")
|
||||||
assert clazz.body.statements.first.clazz
|
assert clazz.body.statements.first.clazz
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user