Reworked to allow derived classes to call base class methods which have been overridden via explicit qualification

[SVN r13588]
This commit is contained in:
Dave Abrahams 2002-04-30 14:51:07 +00:00
parent 5d20da9769
commit abb0398b5a

View File

@ -7,15 +7,54 @@ import numbers ;
import errors : * ;
import set ;
import modules ;
import assert ;
classes = ;
# Declare a class with the given name. The caller should have defined
# a (local) rule called 'name' which acts as the new class'
# constructor. Module-local variables declared in the constructor will
# act like instance variables, and rules defined in the constructor
# will act like methods.
rule class ( name : bases * )
# Construct a class in the module of the caller, which should be a
# class instance. This rule is imported into each class and instance
# under the name <class-name>.__init__ for the most-derived class and
# all of its bases. It extracts <class-name> by inspecting the
# backtrace and uses that to call the user-defined intitialization
# function.
local rule __init__ (
* # all arguments are forwarded directly to the user-defined
# initialization function.
)
{
# pull the name of the class being initialized from the backtrace
local bt = [ BACKTRACE ] ;
local class = [ MATCH ^(.*)[.]__init__$ : $(bt[4]) ] ;
assert.nonempty-variable class ;
# The calling module is the instance names
local instance = [ CALLER_MODULE ] ;
# call the class rule that was defined by the user, from within the instance module
module $(instance)
{
# This invocation defines all of the class' member rules within the instance
$(class).$(class) $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
}
# Make all the class' member rules available as qualified names
# within the instance
local rules = [ RULENAMES $(instance) ] ;
IMPORT $(instance) : $(rules) : $(instance) : $(class).$(rules) ;
}
# Declare a class. The caller should have defined a (local) rule
# called 'name' which acts as the new class' constructor. Module-local
# variables declared in the constructor will act like instance
# variables, and rules defined in the constructor will act like
# methods.
rule class (
name # The name of the class and of its initialization rule in
# the caller's module
: bases * # list of base classes
)
{
if $(name) in $(classes)
{
@ -29,7 +68,6 @@ rule class ( name : bases * )
# This is a record of the class' base classes
modules.poke class@$(name) : __bases__ : $(bases) ;
#modules.poke class@$(name) : __derived__ : ;
modules.poke class@$(name) : __name__ : $(name) ;
module class@$(name)
@ -38,29 +76,34 @@ rule class ( name : bases * )
# users can easily call "inherit", for example.
import class : * ;
# The constructor will be known as "__init__" in the class'
# namespace.
IMPORT [ CALLER_MODULE ] : $(__name__) : class@$(__name__) : __init__ ;
# Cause the __init__ function and all of the class modules
# rules to be visible to the builtin RULENAMES rule. We'll
# need them in order to implement subclasses and instances of
# the class.
EXPORT class@$(__name__) : __init__ # [ RULENAMES class ]
;
# The constructor will be called through the __init__ rule
# above. We import both rules into the class' module here,
# then export them. Although rules are actually only called in
# instances' modules, collecting them here saves us a
# recursive traversal of all bases to import names into the
# instance.
IMPORT [ CALLER_MODULE ] : $(__name__) : class@$(__name__) : $(__name__).$(__name__) ;
IMPORT class : __init__ : class@$(__name__) : $(__name__).__init__ ;
EXPORT class@$(__name__) : $(__name__).$(__name__) $(__name__).__init__ ;
# Bring the __init__ functions in from the base classes, using
# the optional localize parameter so that it will execute in
# the instance's module
# Bring the __init__ functions in from the base classes, and
# check for inheritance cycles.
for local base in $(__bases__)
{
# ECHO import __init__ from module class@$(base) into class@$(__name__) as $(base).__init__ ;
IMPORT class@$(base) : __init__ : class@$(__name__) : $(base).__init__ ;
EXPORT class@$(__name__) : $(base).__init__ ;
local base-rules = [ RULENAMES class@$(base) ] ;
if ( $(__name__).$(__name__) in $(base-rules) )
|| ( $(__name__).__init__ in $(base-rules) )
{
error base class cycle in class $(__name__) ;
}
IMPORT class@$(base) : $(base-rules) : class@$(__name__) : $(base-rules) ;
EXPORT class@$(__name__) : $(base-rules) ;
# Also make note of bidirectional inheritance links.
module class@$(base)
{
# not using symbolic name "name" here because it might
# be a module-local variable
__derived__ += $(1) ;
}
}
@ -86,7 +129,7 @@ rule instance ( name : class args * : * )
IMPORT $(<) : $(rules) : : $(<).$(rules) ;
# Now initialize the instance
__init__ $(>[2-]) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
$(>[1]).__init__ $(>[2-]) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
# Make a record of the instance's class. We need to do this
# last because it will be set to each of the class' base
@ -209,7 +252,6 @@ rule __test__ ( )
}
}
}
class myclass ;
local rule derived1 ( z_ )
@ -245,6 +287,12 @@ rule __test__ ( )
{
return derived2.g ;
}
rule get-x ( )
{
# Test the ability to call base class functions with qualification.
return [ myclass.get-x ] ;
}
}
class derived2 : myclass ;