rubyx/lib/vool/class_expression.rb
Torsten Rüger 38491d120b removed unused NamedList
args and locals got inlined into message, forgot to delete then
ripples out due to type creation
small type class api change, more ripples, but also more consistent
2019-09-18 22:07:05 +03:00

86 lines
2.8 KiB
Ruby

module Vool
# 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
#
# 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
class ClassExpression < Expression
attr_reader :name, :super_class_name , :body
attr_reader :clazz
def initialize( name , supe , body)
@name , @super_class_name = name , supe
case body
when MethodExpression
@body = Statements.new([body])
when Statements
@body = body
when nil
@body = Statements.new([])
else
raise "what body #{body}"
end
end
# This create the Parfait class, and then transforms every method
#
# As there is no class equivalnet in code, a MomCollection is returned,
# which is just a list of Mom::MethodCompilers
def to_mom( _ )
create_class_object
method_compilers = body.statements.collect do |node|
case node
when MethodExpression
node.to_mom(@clazz)
when ClassMethodExpression
node.to_mom(@clazz.meta_class)
else
raise "Only methods for now #{node.class}:#{node}"
end
end
Mom::MomCollection.new(method_compilers)
end
def each(&block)
block.call(self)
@body.each(&block) if @body
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
create_new_class
end
@clazz
end
def create_new_class
@clazz = Parfait.object_space.create_class(@name , @super_class_name )
#TODO this should start from Object Type and add one name at a time.
# So the "trail" of types leading to this one exists.
# Also the Class always has a valid type.
ivar_hash = {}
self.each do |node|
next unless node.is_a?(InstanceVariable) or node.is_a?(IvarAssignment)
ivar_hash[node.name] = :Object
end
@clazz.set_instance_type( Parfait::Type.for_hash( ivar_hash , @clazz ) )
end
def to_s(depth = 0)
at_depth(depth , "class #{name}" , @body.to_s(depth + 1) , "end")
end
end
end