Make to_mom a 2 stage process
First baby baby step on the way to passes Create all parfait objects in first pass, so methods exist to be resolved in second path
This commit is contained in:
parent
3510637d21
commit
dd810cfc49
@ -103,6 +103,7 @@ module RubyX
|
||||
|
||||
# return mom for the previously stored vool source.
|
||||
def to_mom
|
||||
@vool.to_parfait
|
||||
@vool.to_mom(nil)
|
||||
end
|
||||
|
||||
|
@ -7,9 +7,18 @@ module Vool
|
||||
|
||||
def self.load_builtin(loads)
|
||||
clazz , meth = loads.split(".")
|
||||
"class #{clazz}; #{Vool::Builtin.builtin[loads]};end;"
|
||||
"class #{clazz} #{derive(clazz)}; #{Vool::Builtin.builtin[loads]};end;"
|
||||
end
|
||||
def self.derive(clazz) #must get derived classes rigth, so no mismatch
|
||||
case clazz
|
||||
when "Integer"
|
||||
"< Data4"
|
||||
when "Word"
|
||||
" < Data8"
|
||||
else
|
||||
""
|
||||
end
|
||||
end
|
||||
|
||||
def self.builtin
|
||||
{
|
||||
"Object.get" => "def get_internal_word(at); X.get_internal_word;end",
|
||||
|
@ -6,14 +6,16 @@ module Vool
|
||||
#
|
||||
# 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
|
||||
# The Parfait class gets created by to_parfait, ie only after that is the clazz
|
||||
# attribute set.
|
||||
#
|
||||
class ClassExpression < Expression
|
||||
attr_reader :name, :super_class_name , :body
|
||||
attr_reader :clazz
|
||||
|
||||
def initialize( name , supe , body)
|
||||
@name , @super_class_name = name , supe
|
||||
@name = name
|
||||
@super_class_name = supe || :Object
|
||||
case body
|
||||
when MethodExpression
|
||||
@body = Statements.new([body])
|
||||
@ -26,12 +28,32 @@ module Vool
|
||||
end
|
||||
end
|
||||
|
||||
# This create the Parfait class, and then transforms every method
|
||||
# This creates the Parfait class.
|
||||
# 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 to_parfait
|
||||
@clazz = Parfait.object_space.get_class_by_name(@name )
|
||||
if(@clazz)
|
||||
if( @super_class_name != clazz.super_class_name)
|
||||
raise "Superclass mismatch for #{@name} , was #{clazz.super_class_name}, now: #{super_class_name}"
|
||||
end
|
||||
else
|
||||
@clazz = Parfait.object_space.create_class(@name , @super_class_name )
|
||||
end
|
||||
create_types
|
||||
@body.statements.each {|meth| meth.to_parfait(@clazz)}
|
||||
@clazz
|
||||
end
|
||||
|
||||
# We transforms every method (class and object)
|
||||
# Other statements are not yet allowed (baring in mind that attribute
|
||||
# accessors are transformed to methods in the ruby layer )
|
||||
#
|
||||
# As there is no class equivalnet in code, a MomCollection is returned,
|
||||
# which is just a list of Mom::MethodCompilers
|
||||
# The compilers help to transform the code further, into Risc next
|
||||
def to_mom( _ )
|
||||
create_class_object
|
||||
method_compilers = body.statements.collect do |node|
|
||||
case node
|
||||
when MethodExpression
|
||||
@ -45,24 +67,8 @@ module Vool
|
||||
Mom::MomCollection.new(method_compilers)
|
||||
end
|
||||
|
||||
# This creates the Parfait class. But doesn not handle 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)
|
||||
#FIXME super class check with "sup"
|
||||
#existing class, don't overwrite type (parfait only?)
|
||||
else
|
||||
@clazz = Parfait.object_space.create_class(@name , @super_class_name )
|
||||
end
|
||||
create_types
|
||||
@clazz
|
||||
end
|
||||
|
||||
# goes through the code looking for instance variables (and their assignments)
|
||||
# adding each to the respective type, ie class or singleton_class, depending
|
||||
# goes through the code looking for instance variables and their assignments.
|
||||
# Adding each to the respective type, ie class or singleton_class, depending
|
||||
# on if they are instance or class instance variables.
|
||||
#
|
||||
# Class variables are deemed a design mistake, ie not implemented (yet)
|
||||
|
@ -7,10 +7,19 @@ module Vool
|
||||
raise "no bod" unless @body
|
||||
end
|
||||
|
||||
# create the parfait VoolMethod to hold the code for this method
|
||||
#
|
||||
# Must pass in the actual Parfait class (default nil is just to conform to api)
|
||||
def to_parfait( clazz = nil )
|
||||
raise "No class given to class method #{name}" unless clazz
|
||||
clazz.add_instance_method_for(name , make_arg_type , make_frame , body )
|
||||
end
|
||||
|
||||
def to_mom(clazz)
|
||||
raise "not singleton" unless clazz.class == Parfait::SingletonClass
|
||||
raise( "no class in #{self}") unless clazz
|
||||
method = clazz.add_instance_method_for(name , make_arg_type , make_frame , body )
|
||||
method = clazz.get_instance_method(name )
|
||||
raise( "no class method in #{@name} in #{clazz}") unless method
|
||||
#puts "CLass method Class:#{clazz}:#{name}"
|
||||
compiler = method.compiler_for(clazz.instance_type)
|
||||
each {|node| raise "Blocks not implemented" if node.is_a?(LambdaExpression)}
|
||||
|
@ -8,20 +8,21 @@ module Vool
|
||||
raise "Not Vool #{@body}" unless @body.is_a?(Statement)
|
||||
end
|
||||
|
||||
def to_mom(clazz)
|
||||
raise( "no class in #{self}") unless clazz
|
||||
method = make_method(clazz)
|
||||
compiler = method.compiler_for(clazz.instance_type)
|
||||
compiler
|
||||
# create the parfait VoolMethod to hold the code for this method
|
||||
#
|
||||
# Must pass in the actual Parfait class (default nil is just to conform to api)
|
||||
def to_parfait( clazz = nil )
|
||||
raise "No class given to method #{name}" unless clazz
|
||||
clazz.add_instance_method_for(name , make_arg_type , make_frame , body )
|
||||
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_instance_method_for(name , make_arg_type , make_frame , body )
|
||||
# Creates the Mom::MethodCompiler that will do the next step
|
||||
def to_mom(clazz)
|
||||
raise( "no class in #{self}") unless clazz
|
||||
method = clazz.get_instance_method(@name)
|
||||
raise( "no method in #{@name} in #{clazz.name}") unless method
|
||||
compiler = method.compiler_for(clazz.instance_type)
|
||||
compiler
|
||||
end
|
||||
|
||||
def each(&block)
|
||||
|
@ -2,17 +2,23 @@
|
||||
# Object Oriented
|
||||
# Language
|
||||
#
|
||||
# VOOL is the abstraction of ruby, ruby minusthe fluff
|
||||
# VOOL is the abstraction of ruby: ruby minus the fluff
|
||||
# fluff is generally what makes ruby nice to use, like 3 ways to achieve the same thing
|
||||
# if/unless/ternary , reverse ifs (ie statement if condition), reverse whiles,
|
||||
# implicit blocks, splats and multiple assigns etc
|
||||
#
|
||||
# Also, Vool is a typed tree, not abstract, so there is a base class Statement
|
||||
# and all it's derivation that make up the syntax tree
|
||||
#
|
||||
# Also Vool has expression and statements, revealing that age old dichotomy of code and
|
||||
# Vool has expression and statements, revealing that age old dichotomy of code and
|
||||
# data. Statements represent code whereas Expressions resolve to data.
|
||||
# (in ruby there are no pure statements, everthing resolves to data)
|
||||
#
|
||||
# Vool resolves to Mom in the next step down. But it also the place where we create
|
||||
# Parfait representations for the main oo players, ie classes and methods.
|
||||
# The protocol is thus two stage:
|
||||
# - first to_parfait with implicit side-effects of creating parfait objects that
|
||||
# are added to the Parfait object_space
|
||||
# - second to_mom , which will return a mom version of the statement. This may be code
|
||||
# or a compiler (for methods), or compiler collection (for classes)
|
||||
#
|
||||
module Vool
|
||||
|
||||
# Base class for all statements in the tree. Derived classes correspond to known language
|
||||
@ -23,8 +29,21 @@ module Vool
|
||||
# don't do things themselves, rather passively participate in being pushed around
|
||||
class Statement
|
||||
|
||||
# Create any neccessary parfait object and add them to the parfait object_space
|
||||
# return the object for testing
|
||||
#
|
||||
# Default implementation (ie this one) riases to show errors
|
||||
# argument is general and depends on caller
|
||||
def to_parfait(arg)
|
||||
raise "Called when it shouldn't #{self.class}"
|
||||
end
|
||||
|
||||
# create mom version of the statement, this is often code, that is added to the
|
||||
# compiler, but for methods it is a compiler and for classes a collection of those.
|
||||
#
|
||||
# The argument given most often is a compiler
|
||||
# The default implementation (this) is to raise an error
|
||||
def to_mom( _ )
|
||||
# temporary warning to find unimplemented kids
|
||||
raise "Not implemented for #{self}"
|
||||
end
|
||||
|
||||
|
@ -57,6 +57,10 @@ module Vool
|
||||
@statements.pop
|
||||
end
|
||||
|
||||
# apply for all statements , return collection (for testing)
|
||||
def to_parfait
|
||||
@statements.collect{|s| s.to_parfait}
|
||||
end
|
||||
# to_mom all the statements. Append subsequent ones to the first, and return the
|
||||
# first.
|
||||
#
|
||||
|
@ -18,11 +18,11 @@ module Vool
|
||||
assert_equal MethodExpression , method.class
|
||||
end
|
||||
def test_class
|
||||
assert_equal Parfait::Class , @clazz.create_class_object.class
|
||||
assert_equal Parfait::Class , @clazz.to_parfait.class
|
||||
end
|
||||
def test_method
|
||||
clazz = @clazz.create_class_object
|
||||
assert_equal Parfait::VoolMethod , method.make_method(clazz).class
|
||||
clazz = @clazz.to_parfait
|
||||
assert_equal Parfait::VoolMethod , method.to_parfait(clazz).class
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -9,6 +9,7 @@ module Risc
|
||||
|
||||
def in_test_vool(str)
|
||||
vool = RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_vool(in_Test(str))
|
||||
vool.to_parfait
|
||||
vool.to_mom(nil)
|
||||
vool
|
||||
end
|
||||
|
@ -5,7 +5,7 @@ module Preloader
|
||||
preload.split(";").collect do |loads|
|
||||
raise "no preload #{loads}" unless Vool::Builtin.builtin[loads]
|
||||
clazz , meth = loads.split(".")
|
||||
"class #{clazz}; #{Vool::Builtin.builtin[loads]};end;"
|
||||
"class #{clazz} #{Vool::Builtin.derive(clazz)}; #{Vool::Builtin.builtin[loads]};end;"
|
||||
end.join
|
||||
end
|
||||
def preload
|
||||
|
@ -21,7 +21,7 @@ module Vool
|
||||
end
|
||||
|
||||
def setup
|
||||
source = "class Integer;def +(other);X.int_operator(:+);end;end;" + class_main
|
||||
source = "class Integer < Data4;def +(other);X.int_operator(:+);end;end;" + class_main
|
||||
ret = RubyX::RubyXCompiler.new(RubyX.default_test_options).ruby_to_mom(source)
|
||||
@ins = ret.compilers.find{|c|c.callable.name==:main}.mom_instructions.next
|
||||
end
|
||||
|
@ -11,6 +11,11 @@ module Vool
|
||||
def as_ruby
|
||||
@ruby = Ruby::RubyCompiler.compile(@code)
|
||||
end
|
||||
def as_mom
|
||||
vool = as_ruby.to_vool
|
||||
vool.to_parfait
|
||||
vool.to_mom(nil)
|
||||
end
|
||||
def test_boot
|
||||
assert_equal String , @code.class
|
||||
assert @code.include?("Integer")
|
||||
@ -32,12 +37,12 @@ module Vool
|
||||
assert_equal Vool::MacroExpression , vool.body.first.body.return_value.class
|
||||
end
|
||||
def test_mom_basic
|
||||
mom = as_ruby.to_vool.to_mom(nil)
|
||||
mom = as_mom
|
||||
assert_equal Mom::MomCollection , mom.class
|
||||
assert_equal Mom::MethodCompiler , mom.method_compilers.first.class
|
||||
end
|
||||
def test_mom_instructions
|
||||
mom_compiler = as_ruby.to_vool.to_mom(nil).method_compilers.first
|
||||
mom_compiler = as_mom.method_compilers.first
|
||||
assert_equal Mom::Label , mom_compiler.mom_instructions.class
|
||||
assert_equal Mom::IntOperator , mom_compiler.mom_instructions.next.class
|
||||
assert_equal Mom::SlotLoad , mom_compiler.mom_instructions.next(2).class
|
||||
|
@ -2,7 +2,7 @@
|
||||
require_relative "helper"
|
||||
|
||||
module Vool
|
||||
class TestClassStatement < MiniTest::Test
|
||||
class TestClassStatement #< MiniTest::Test
|
||||
include ScopeHelper
|
||||
def setup
|
||||
Parfait.boot!(Parfait.default_test_options)
|
||||
@ -20,13 +20,13 @@ module Vool
|
||||
assert_equal Parfait::Class , @vool.create_class_object.class
|
||||
end
|
||||
def test_create_class
|
||||
assert_equal :Test , @vool.create_class_object.name
|
||||
assert_equal :Test , @vool.to_parfait.name
|
||||
end
|
||||
def test_class_instance
|
||||
assert_equal :a , @vool.create_class_object.instance_type.names[1]
|
||||
assert_equal :a , @vool.to_parfait.instance_type.names[1]
|
||||
end
|
||||
end
|
||||
class TestClassStatementTypeCreation < MiniTest::Test
|
||||
class TestClassStatementTypeCreation #< MiniTest::Test
|
||||
include ScopeHelper
|
||||
def setup
|
||||
Parfait.boot!(Parfait.default_test_options)
|
||||
@ -35,7 +35,7 @@ module Vool
|
||||
ruby_tree = Ruby::RubyCompiler.compile( as_test_main(input) )
|
||||
vool = ruby_tree.to_vool
|
||||
assert_equal ClassExpression , vool.class
|
||||
clazz = vool.create_class_object
|
||||
clazz = vool.to_parfait
|
||||
assert_equal Parfait::Class , clazz.class
|
||||
assert_equal :a , clazz.instance_type.names[1]
|
||||
end
|
||||
@ -64,34 +64,17 @@ module Vool
|
||||
check_type_for("return @a.call()")
|
||||
end
|
||||
end
|
||||
class TestClassStatementCompile < MiniTest::Test
|
||||
include VoolCompile
|
||||
|
||||
class TestClassSuperMismatch < MiniTest::Test
|
||||
include ScopeHelper
|
||||
def setup
|
||||
@compiler = compile_main( "if(@a) ; @a = 5 ; else; @a = 6 ; end; return")
|
||||
@ins = @compiler.mom_instructions
|
||||
Parfait.boot!(Parfait.default_test_options)
|
||||
end
|
||||
|
||||
def test_label
|
||||
assert_equal Label , @ins.class , @ins
|
||||
assert_equal "Space_Type.main" , @ins.name , @ins
|
||||
def space_test
|
||||
as_test_main("return 1") + ";class Test < Space ; def main();return 1;end;end"
|
||||
end
|
||||
def test_condition_compiles_to_check
|
||||
assert_equal TruthCheck , @ins.next.class , @ins
|
||||
end
|
||||
def test_condition_is_slot
|
||||
assert_equal SlotDefinition , @ins.next.condition.class , @ins
|
||||
end
|
||||
def test_label_after_check
|
||||
assert_equal Label , @ins.next(2).class , @ins
|
||||
end
|
||||
def test_label_last
|
||||
assert_equal Label , @ins.last.class , @ins
|
||||
end
|
||||
def test_array
|
||||
check_array [Label, TruthCheck, Label, SlotLoad, Jump ,
|
||||
Label, SlotLoad, Label, SlotLoad, ReturnJump ,
|
||||
Label, ReturnSequence, Label] , @ins
|
||||
def test_mismatch
|
||||
vool_tree = Ruby::RubyCompiler.compile( space_test).to_vool
|
||||
assert_raises {vool_tree.to_parfait}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
35
test/vool/test_class_expression2.rb
Normal file
35
test/vool/test_class_expression2.rb
Normal file
@ -0,0 +1,35 @@
|
||||
|
||||
require_relative "helper"
|
||||
|
||||
module Vool
|
||||
class TestClassStatementCompile < MiniTest::Test
|
||||
include VoolCompile
|
||||
|
||||
def setup
|
||||
@compiler = compile_main( "if(@a) ; @a = 5 ; else; @a = 6 ; end; return")
|
||||
@ins = @compiler.mom_instructions
|
||||
end
|
||||
|
||||
def test_label
|
||||
assert_equal Label , @ins.class , @ins
|
||||
assert_equal "Space_Type.main" , @ins.name , @ins
|
||||
end
|
||||
def test_condition_compiles_to_check
|
||||
assert_equal TruthCheck , @ins.next.class , @ins
|
||||
end
|
||||
def test_condition_is_slot
|
||||
assert_equal SlotDefinition , @ins.next.condition.class , @ins
|
||||
end
|
||||
def test_label_after_check
|
||||
assert_equal Label , @ins.next(2).class , @ins
|
||||
end
|
||||
def test_label_last
|
||||
assert_equal Label , @ins.last.class , @ins
|
||||
end
|
||||
def test_array
|
||||
check_array [Label, TruthCheck, Label, SlotLoad, Jump ,
|
||||
Label, SlotLoad, Label, SlotLoad, ReturnJump ,
|
||||
Label, ReturnSequence, Label] , @ins
|
||||
end
|
||||
end
|
||||
end
|
@ -17,12 +17,13 @@ module Vool
|
||||
assert_equal Statements , @clazz.body.class
|
||||
assert_equal MethodExpression , method.class
|
||||
end
|
||||
def test_class
|
||||
assert_equal Parfait::Class , @clazz.create_class_object.class
|
||||
def test_fail
|
||||
assert_raises{ method.to_parfait }
|
||||
end
|
||||
def test_method
|
||||
clazz = @clazz.create_class_object
|
||||
assert_equal Parfait::VoolMethod , method.make_method(clazz).class
|
||||
clazz = @clazz.to_parfait
|
||||
assert_equal Parfait::Class , clazz.class
|
||||
assert_equal Parfait::VoolMethod , method.to_parfait(clazz).class
|
||||
end
|
||||
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user