Torsten Rüger
a722a4c285
When the lambda is passed as argument, it must be moved. This triggers the generation of a corresponding parfait object (as before, and as for other constants) but now also triggers the code build. The code being the constant as it were Also some more name fixes from renames
82 lines
2.8 KiB
Ruby
82 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 hadle 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 )
|
|
#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( @clazz , ivar_hash ) )
|
|
@clazz
|
|
end
|
|
end
|
|
|
|
def to_s(depth = 0)
|
|
at_depth(depth , "class #{name}" , @body.to_s(depth + 1) , "end")
|
|
end
|
|
end
|
|
end
|