2017-04-01 14:57:39 +02:00
|
|
|
module Vool
|
2019-08-08 11:19:27 +02:00
|
|
|
# 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
|
|
|
|
#
|
2019-09-24 14:44:33 +02:00
|
|
|
# The Parfait class gets created by to_parfait, ie only after that is the clazz
|
|
|
|
# attribute set.
|
|
|
|
#
|
2019-08-19 10:33:12 +02:00
|
|
|
class ClassExpression < Expression
|
2017-04-01 14:57:39 +02:00
|
|
|
attr_reader :name, :super_class_name , :body
|
2017-04-08 11:11:52 +02:00
|
|
|
attr_reader :clazz
|
2017-04-01 14:57:39 +02:00
|
|
|
|
|
|
|
def initialize( name , supe , body)
|
2019-09-24 14:44:33 +02:00
|
|
|
@name = name
|
|
|
|
@super_class_name = supe || :Object
|
2018-06-29 22:29:10 +02:00
|
|
|
case body
|
2019-08-19 10:33:12 +02:00
|
|
|
when MethodExpression
|
2018-06-29 22:29:10 +02:00
|
|
|
@body = Statements.new([body])
|
|
|
|
when Statements
|
|
|
|
@body = body
|
|
|
|
when nil
|
|
|
|
@body = Statements.new([])
|
|
|
|
else
|
|
|
|
raise "what body #{body}"
|
|
|
|
end
|
2017-04-08 11:11:52 +02:00
|
|
|
end
|
|
|
|
|
2019-09-24 14:44:33 +02:00
|
|
|
# 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 )
|
2019-08-08 11:19:27 +02:00
|
|
|
#
|
|
|
|
# As there is no class equivalnet in code, a MomCollection is returned,
|
|
|
|
# which is just a list of Mom::MethodCompilers
|
2019-09-24 14:44:33 +02:00
|
|
|
# The compilers help to transform the code further, into Risc next
|
2017-04-12 10:52:23 +02:00
|
|
|
def to_mom( _ )
|
2018-07-06 19:01:17 +02:00
|
|
|
method_compilers = body.statements.collect do |node|
|
2019-02-17 13:37:50 +01:00
|
|
|
case node
|
2019-08-19 13:33:02 +02:00
|
|
|
when MethodExpression
|
2019-02-17 13:37:50 +01:00
|
|
|
node.to_mom(@clazz)
|
2019-08-19 13:33:02 +02:00
|
|
|
when ClassMethodExpression
|
2019-09-23 19:57:33 +02:00
|
|
|
node.to_mom(@clazz.singleton_class)
|
2019-02-17 13:37:50 +01:00
|
|
|
else
|
2019-02-16 16:54:45 +01:00
|
|
|
raise "Only methods for now #{node.class}:#{node}"
|
|
|
|
end
|
2018-06-26 19:46:58 +02:00
|
|
|
end
|
2019-08-06 17:33:27 +02:00
|
|
|
Mom::MomCollection.new(method_compilers)
|
2017-04-12 10:52:23 +02:00
|
|
|
end
|
|
|
|
|
2019-09-24 14:44:33 +02:00
|
|
|
# goes through the code looking for instance variables and their assignments.
|
|
|
|
# Adding each to the respective type, ie class or singleton_class, depending
|
2019-09-19 14:48:27 +02:00
|
|
|
# on if they are instance or class instance variables.
|
|
|
|
#
|
2019-09-19 19:48:21 +02:00
|
|
|
# Class variables are deemed a design mistake, ie not implemented (yet)
|
2019-09-19 14:48:27 +02:00
|
|
|
def create_types
|
|
|
|
self.body.statements.each do |node|
|
|
|
|
case node
|
|
|
|
when MethodExpression
|
|
|
|
target = @clazz
|
|
|
|
when ClassMethodExpression
|
2019-09-23 19:57:33 +02:00
|
|
|
target = @clazz.singleton_class
|
2019-09-19 14:48:27 +02:00
|
|
|
else
|
|
|
|
raise "Only methods for now #{node.class}:#{node}"
|
|
|
|
end
|
|
|
|
node.each do |exp|
|
|
|
|
case exp
|
|
|
|
when InstanceVariable, IvarAssignment
|
|
|
|
target.add_instance_variable( exp.name , :Object )
|
|
|
|
when ClassVariable #, ClassVarAssignment
|
|
|
|
raise "Class variables not implemented #{node.name}"
|
|
|
|
end
|
|
|
|
end
|
2019-09-18 21:07:05 +02:00
|
|
|
end
|
|
|
|
end
|
2018-07-03 21:18:19 +02:00
|
|
|
def to_s(depth = 0)
|
2019-09-19 19:48:21 +02:00
|
|
|
derive = super_class_name ? "< #{super_class_name}" : ""
|
|
|
|
at_depth(depth , "class #{name} #{derive}\n#{@body.to_s(depth + 1)}\nend")
|
2018-07-03 21:18:19 +02:00
|
|
|
end
|
2017-04-01 14:57:39 +02:00
|
|
|
end
|
|
|
|
end
|