Fix more phasing issues
This change fixes a few more phasing issues in the compiler. Namely, it now splits all passes into three distinct phases: 1. Declarations: simply populating names. 2. Definitions: chasing down any references to other names from those declared entities. For instance, base classes, other modules, etc. 3. Bodies: fully type-checking everything else, which will depend upon both declarations and definitions being fully present.
This commit is contained in:
parent
9bcfbe859f
commit
a91f3e6050
4 changed files with 176 additions and 171 deletions
|
@ -10,32 +10,43 @@ import (
|
|||
"github.com/marapongo/mu/pkg/util/contract"
|
||||
)
|
||||
|
||||
func (b *binder) bindClass(node *ast.Class, parent *symbols.Module) *symbols.Class {
|
||||
func (b *binder) pushClass(class *symbols.Class) func() {
|
||||
priorclass := b.ctx.Currclass
|
||||
b.ctx.Currclass = class
|
||||
return func() { b.ctx.Currclass = priorclass }
|
||||
}
|
||||
|
||||
func (b *binder) bindClassDeclaration(node *ast.Class, parent *symbols.Module) *symbols.Class {
|
||||
glog.V(3).Infof("Binding module '%v' class '%v'", parent.Name(), node.Name.Ident)
|
||||
|
||||
// Bind base type tokens to actual symbols.
|
||||
extends := b.ctx.LookupType(node.Extends)
|
||||
var implements symbols.Types
|
||||
if node.Implements != nil {
|
||||
for _, impltok := range *node.Implements {
|
||||
if impl := b.ctx.LookupType(impltok); impl != nil {
|
||||
implements = append(implements, impl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now create a class symbol. This is required as a parent for the members.
|
||||
class := symbols.NewClassSym(node, parent, extends, implements)
|
||||
// Now create an empty class symbol. This is required as a parent for the members.
|
||||
class := symbols.NewClassSym(node, parent, nil, nil)
|
||||
b.ctx.RegisterSymbol(node, class)
|
||||
|
||||
return class
|
||||
}
|
||||
|
||||
func (b *binder) bindClassDefinition(class *symbols.Class) {
|
||||
// Bind base type tokens to actual symbols.
|
||||
if class.Node.Extends != nil {
|
||||
class.SetBase(b.ctx.LookupType(class.Node.Extends))
|
||||
}
|
||||
|
||||
if class.Node.Implements != nil {
|
||||
for _, impltok := range *class.Node.Implements {
|
||||
if impl := b.ctx.LookupType(impltok); impl != nil {
|
||||
class.Implements = append(class.Implements, impl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
b.bindClassMembers(class)
|
||||
}
|
||||
|
||||
func (b *binder) bindClassMembers(class *symbols.Class) {
|
||||
// Set the current class in the context so we can e.g. enforce accessibility.
|
||||
priorclass := b.ctx.Currclass
|
||||
b.ctx.Currclass = class
|
||||
defer func() { b.ctx.Currclass = priorclass }()
|
||||
pop := b.pushClass(class)
|
||||
defer pop()
|
||||
|
||||
// Bind each member at the symbolic level; in particular, we do not yet bind bodies of methods.
|
||||
if class.Node.Members != nil {
|
||||
|
@ -81,7 +92,7 @@ func (b *binder) bindClassMethod(node *ast.ClassMethod, parent *symbols.Class) *
|
|||
return sym
|
||||
}
|
||||
|
||||
func (b *binder) bindClassMethodBodies(class *symbols.Class) {
|
||||
func (b *binder) bindClassBodies(class *symbols.Class) {
|
||||
for _, member := range symbols.StableClassMemberMap(class.Members) {
|
||||
switch m := class.Members[member].(type) {
|
||||
case *symbols.ClassMethod:
|
||||
|
|
|
@ -3,23 +3,102 @@
|
|||
package binder
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"github.com/marapongo/mu/pkg/compiler/ast"
|
||||
"github.com/marapongo/mu/pkg/compiler/symbols"
|
||||
"github.com/marapongo/mu/pkg/util/contract"
|
||||
)
|
||||
|
||||
// createModule simply creates a module symbol with its immutable information. In particular, it doesn't yet bind
|
||||
// members, since inter-module references must be resolved in later passes.
|
||||
func (b *binder) createModule(node *ast.Module, parent *symbols.Package) *symbols.Module {
|
||||
glog.V(3).Infof("Creating package '%v' module '%v'", parent.Name(), node.Name.Ident)
|
||||
func (b *binder) pushModule(module *symbols.Module) func() {
|
||||
priormodule := b.ctx.Currmodule
|
||||
b.ctx.Currmodule = module
|
||||
return func() { b.ctx.Currmodule = priormodule }
|
||||
}
|
||||
|
||||
func (b *binder) bindModuleDeclarations(node *ast.Module, parent *symbols.Package) *symbols.Module {
|
||||
glog.V(3).Infof("Binding package '%v' module '%v' decls", parent.Name(), node.Name.Ident)
|
||||
|
||||
// Create the module symbol and register it.
|
||||
module := symbols.NewModuleSym(node, parent)
|
||||
b.ctx.RegisterSymbol(node, module)
|
||||
|
||||
// Now bind module member declarations; this just populates the top-level declaration symbolic information, without
|
||||
// any inter-dependencies on other module declarations that may not have yet been completed.
|
||||
b.bindModuleMemberDeclarations(module)
|
||||
|
||||
return module
|
||||
}
|
||||
|
||||
// bindModuleMemberDeclarations binds a module's member names. This must be done before binding definitions because
|
||||
// they could mention other members whose symbolic information may not have been registered yet. Note that class
|
||||
// definitions are not yet bound during this pass, since they could reference module members not yet bound.
|
||||
func (b *binder) bindModuleMemberDeclarations(module *symbols.Module) {
|
||||
glog.V(3).Infof("Binding module '%v' member decls", module.Token())
|
||||
|
||||
// Set the current module in the context so we can e.g. enforce accessibility.
|
||||
pop := b.pushModule(module)
|
||||
defer pop()
|
||||
|
||||
// Now bind all member declarations.
|
||||
if module.Node.Members != nil {
|
||||
members := *module.Node.Members
|
||||
for _, nm := range ast.StableModuleMembers(members) {
|
||||
switch m := members[nm].(type) {
|
||||
case *ast.Class:
|
||||
module.Members[nm] = b.bindClassDeclaration(m, module)
|
||||
case *ast.Export:
|
||||
module.Members[nm] = b.bindExportDeclaration(m, module)
|
||||
case *ast.ModuleMethod:
|
||||
module.Members[nm] = b.bindModuleMethodDeclaration(m, module)
|
||||
case *ast.ModuleProperty:
|
||||
module.Members[nm] = b.bindModulePropertyDeclaration(m, module)
|
||||
default:
|
||||
contract.Failf("Unrecognized module member type: %v", reflect.TypeOf(m))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (b *binder) bindExportDeclaration(node *ast.Export, parent *symbols.Module) *symbols.Export {
|
||||
glog.V(3).Infof("Binding module '%v' export '%v' decl", parent.Name(), node.Name.Ident)
|
||||
|
||||
// Simply register an empty export, unlinked to the referent yet.
|
||||
sym := symbols.NewExportSym(node, parent, nil)
|
||||
b.ctx.RegisterSymbol(node, sym)
|
||||
return sym
|
||||
}
|
||||
|
||||
func (b *binder) bindModulePropertyDeclaration(node *ast.ModuleProperty,
|
||||
parent *symbols.Module) *symbols.ModuleProperty {
|
||||
glog.V(3).Infof("Binding module '%v' property '%v' decl", parent.Name(), node.Name.Ident)
|
||||
|
||||
// Simply create an untyped property declaration. The type lookup will happen in a subsequent pass.
|
||||
sym := symbols.NewModulePropertySym(node, parent, nil)
|
||||
b.ctx.RegisterSymbol(node, sym)
|
||||
return sym
|
||||
}
|
||||
|
||||
func (b *binder) bindModuleMethodDeclaration(node *ast.ModuleMethod,
|
||||
parent *symbols.Module) *symbols.ModuleMethod {
|
||||
glog.V(3).Infof("Binding module '%v' method '%v' decl", parent.Name(), node.Name.Ident)
|
||||
|
||||
// Simply create a function declaration without any type. That will happen in a subsequent pass.
|
||||
sym := symbols.NewModuleMethodSym(node, parent, nil)
|
||||
b.ctx.RegisterSymbol(node, sym)
|
||||
return sym
|
||||
}
|
||||
|
||||
func (b *binder) bindModuleDefinitions(module *symbols.Module) {
|
||||
// Now we can bind module imports.
|
||||
b.bindModuleImports(module)
|
||||
|
||||
// And finish binding the members themselves.
|
||||
b.bindModuleMemberDefinitions(module)
|
||||
}
|
||||
|
||||
// bindModuleImports binds module import tokens to their symbols. This is done as a second pass just in case there are
|
||||
// inter-module dependencies.
|
||||
func (b *binder) bindModuleImports(module *symbols.Module) {
|
||||
|
@ -33,131 +112,58 @@ func (b *binder) bindModuleImports(module *symbols.Module) {
|
|||
}
|
||||
}
|
||||
|
||||
// bindModuleClassNames binds a module's classes. This must be done before binding variables and exports since they
|
||||
// might mention classes by name, and so the symbolic information must have been registered beforehand. Note that class
|
||||
// definitions are not yet bound during this pass, since they could reference module members not yet bound.
|
||||
func (b *binder) bindModuleClasses(module *symbols.Module) {
|
||||
glog.V(3).Infof("Binding module '%v' classes", module.Token())
|
||||
// bindModuleMemberDefinitions finishes binding module members, by doing lookups sensitive to the definition pass.
|
||||
func (b *binder) bindModuleMemberDefinitions(module *symbols.Module) {
|
||||
glog.V(3).Infof("Binding module '%v' member defns", module.Token())
|
||||
|
||||
// Set the current module in the context so we can e.g. enforce accessibility.
|
||||
priormodule := b.ctx.Currmodule
|
||||
b.ctx.Currmodule = module
|
||||
defer func() { b.ctx.Currmodule = priormodule }()
|
||||
pop := b.pushModule(module)
|
||||
defer pop()
|
||||
|
||||
// Now bind all class members.
|
||||
if module.Node.Members != nil {
|
||||
members := *module.Node.Members
|
||||
for _, nm := range ast.StableModuleMembers(members) {
|
||||
member := members[nm]
|
||||
if class, isclass := member.(*ast.Class); isclass {
|
||||
module.Members[nm] = b.bindClass(class, module)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bindModuleClassMembers binds all class member definitions within a module (function signatures and varaibles),
|
||||
// but doesn't actually bind any function bodies yet.
|
||||
func (b *binder) bindModuleClassMembers(module *symbols.Module) {
|
||||
glog.V(3).Infof("Binding module '%v' class members", module.Token())
|
||||
|
||||
// Set the current module in the context so we can e.g. enforce accessibility.
|
||||
priormodule := b.ctx.Currmodule
|
||||
b.ctx.Currmodule = module
|
||||
defer func() { b.ctx.Currmodule = priormodule }()
|
||||
|
||||
// Now bind all class member definitions.
|
||||
// Now bind all member definitions.
|
||||
for _, nm := range symbols.StableModuleMemberMap(module.Members) {
|
||||
if class, isclass := module.Members[nm].(*symbols.Class); isclass {
|
||||
b.bindClassMembers(class)
|
||||
switch m := module.Members[nm].(type) {
|
||||
case *symbols.Class:
|
||||
b.bindClassDefinition(m)
|
||||
case *symbols.Export:
|
||||
b.bindExportDefinition(m)
|
||||
case *symbols.ModuleMethod:
|
||||
b.bindModuleMethodDefinition(m)
|
||||
case *symbols.ModuleProperty:
|
||||
b.bindModulePropertyDefinition(m)
|
||||
default:
|
||||
contract.Failf("Unrecognized module member type: %v", reflect.TypeOf(m))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bindModuleMembers binds a module's property and method members. This must be done after binding classes, and before
|
||||
// binding exports, so that any classes referenced are found (and because exports might refer to these).
|
||||
func (b *binder) bindModuleMembers(module *symbols.Module) {
|
||||
glog.V(3).Infof("Binding module '%v' methods and properties", module.Token())
|
||||
func (b *binder) bindExportDefinition(export *symbols.Export) {
|
||||
glog.V(3).Infof("Binding module export '%v' defn", export.Token)
|
||||
|
||||
// Set the current module in the context so we can e.g. enforce accessibility.
|
||||
priormodule := b.ctx.Currmodule
|
||||
b.ctx.Currmodule = module
|
||||
defer func() { b.ctx.Currmodule = priormodule }()
|
||||
|
||||
// Now bind all module methods and properties.
|
||||
if module.Node.Members != nil {
|
||||
members := *module.Node.Members
|
||||
for _, nm := range ast.StableModuleMembers(members) {
|
||||
member := members[nm]
|
||||
if method, ismethod := member.(*ast.ModuleMethod); ismethod {
|
||||
module.Members[nm] = b.bindModuleMethod(method, module)
|
||||
} else if property, isproperty := member.(*ast.ModuleProperty); isproperty {
|
||||
module.Members[nm] = b.bindModuleProperty(property, module)
|
||||
}
|
||||
}
|
||||
}
|
||||
// To bind an export definition, simply look up the referent symbol and associate this name with it.
|
||||
export.Referent = b.ctx.LookupSymbol(export.Node.Referent, export.Node.Referent.Tok, true)
|
||||
}
|
||||
|
||||
// bindModuleExports binds a module's exports. This must be done after binding classes and members, since an export
|
||||
// might refer to those by symbolic token reference. This can also safely be done before method bodies.
|
||||
func (b *binder) bindModuleExports(module *symbols.Module) {
|
||||
glog.V(3).Infof("Binding module '%v' methods and properties", module.Token())
|
||||
func (b *binder) bindModulePropertyDefinition(property *symbols.ModuleProperty) {
|
||||
glog.V(3).Infof("Binding module property '%v' defn", property.Token)
|
||||
|
||||
// Set the current module in the context so we can e.g. enforce accessibility.
|
||||
priormodule := b.ctx.Currmodule
|
||||
b.ctx.Currmodule = module
|
||||
defer func() { b.ctx.Currmodule = priormodule }()
|
||||
|
||||
// Now bind all module methods and properties.
|
||||
if module.Node.Members != nil {
|
||||
members := *module.Node.Members
|
||||
for _, nm := range ast.StableModuleMembers(members) {
|
||||
member := members[nm]
|
||||
if export, isexport := member.(*ast.Export); isexport {
|
||||
module.Members[nm] = b.bindExport(export, module)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Look up this node's type and remember the type on the symbol.
|
||||
property.Ty = b.ctx.LookupType(property.Node.Type)
|
||||
}
|
||||
|
||||
func (b *binder) bindExport(node *ast.Export, parent *symbols.Module) *symbols.Export {
|
||||
glog.V(3).Infof("Binding module '%v' export '%v'", parent.Name(), node.Name.Ident)
|
||||
func (b *binder) bindModuleMethodDefinition(method *symbols.ModuleMethod) {
|
||||
glog.V(3).Infof("Binding module method '%v' defn", method.Token)
|
||||
|
||||
// To bind an export, simply look up the referent symbol and associate this name with it.
|
||||
if refsym := b.ctx.LookupSymbol(node.Referent, node.Referent.Tok, true); refsym != nil {
|
||||
sym := symbols.NewExportSym(node, parent, refsym)
|
||||
b.ctx.RegisterSymbol(node, sym)
|
||||
return sym
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *binder) bindModuleProperty(node *ast.ModuleProperty, parent *symbols.Module) *symbols.ModuleProperty {
|
||||
glog.V(3).Infof("Binding module '%v' property '%v'", parent.Name(), node.Name.Ident)
|
||||
|
||||
// Look up this node's type and inject it into the type table.
|
||||
ty := b.ctx.LookupType(node.Type)
|
||||
sym := symbols.NewModulePropertySym(node, parent, ty)
|
||||
b.ctx.RegisterSymbol(node, sym)
|
||||
return sym
|
||||
}
|
||||
|
||||
func (b *binder) bindModuleMethod(node *ast.ModuleMethod, parent *symbols.Module) *symbols.ModuleMethod {
|
||||
glog.V(3).Infof("Binding module '%v' method '%v'", parent.Name(), node.Name.Ident)
|
||||
|
||||
// Make a function type out of this method and inject it into the type table.
|
||||
ty := b.ctx.LookupFunctionType(node)
|
||||
sym := symbols.NewModuleMethodSym(node, parent, ty)
|
||||
b.ctx.RegisterSymbol(node, sym)
|
||||
// Make a function type out of this method and store it on the symbol.
|
||||
method.Type = b.ctx.LookupFunctionType(method.Node)
|
||||
|
||||
// Note that we don't actually bind the body of this method yet. Until we have gone ahead and injected *all*
|
||||
// top-level symbols into the type table, we would potentially encounter missing intra-module symbols.
|
||||
return sym
|
||||
}
|
||||
|
||||
// bindModuleMethodBodies binds both the module's direct methods in addition to class methods. This must be done after
|
||||
// bindModuleBodies binds both the module's direct methods in addition to class methods. This must be done after
|
||||
// all top-level symbolic information has been bound, in case definitions, statements, and expressions depend upon them.
|
||||
func (b *binder) bindModuleMethodBodies(module *symbols.Module) {
|
||||
func (b *binder) bindModuleBodies(module *symbols.Module) {
|
||||
// Set the current module in the context so we can e.g. enforce accessibility. We need to do this again while
|
||||
// binding the module bodies so that the correct context is reestablished for lookups, etc.
|
||||
priormodule := b.ctx.Currmodule
|
||||
|
@ -171,7 +177,7 @@ func (b *binder) bindModuleMethodBodies(module *symbols.Module) {
|
|||
case *symbols.ModuleMethod:
|
||||
b.bindModuleMethodBody(m)
|
||||
case *symbols.Class:
|
||||
b.bindClassMethodBodies(m)
|
||||
b.bindClassBodies(m)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,16 +53,16 @@ func (b *binder) resolveBindPackage(pkg *pack.Package, pkgurl pack.PackageURL) *
|
|||
// Resolve all package dependencies.
|
||||
b.resolvePackageDeps(pkgsym)
|
||||
|
||||
// Now bind all of the package's modules (if any). This pass does not yet actually bind class members yet.
|
||||
b.bindPackageModules(pkgsym)
|
||||
// Now bind all of the package's declarations (if any). This pass does not yet actually bind definitions.
|
||||
b.bindPackageDeclarations(pkgsym)
|
||||
|
||||
// Next go ahead and bind class members. This happens in a full pass after resolving all modules, because this
|
||||
// phase might reference members that are only now exposed after the above phase.
|
||||
b.bindPackageClassMembers(pkgsym)
|
||||
// Next go ahead and bind definitions. This happens in a full pass after resolving all modules, because this
|
||||
// phase might reference other declarations that are only now exposed after the above phase.
|
||||
b.bindPackageDefinitions(pkgsym)
|
||||
|
||||
// Finally, bind all of the package's method bodies. This second pass is required to ensure that inter-module
|
||||
// dependencies can resolve to symbols, after reaching the symbol-level fixed point above.
|
||||
b.bindPackageMethodBodies(pkgsym)
|
||||
b.bindPackageBodies(pkgsym)
|
||||
|
||||
return respkg
|
||||
}
|
||||
|
@ -137,53 +137,32 @@ func (b *binder) resolveDep(dep pack.PackageURL) *symbols.ResolvedPackage {
|
|||
return nil
|
||||
}
|
||||
|
||||
// bindPackageModules recursively binds all modules and stores them in the given package. Note that this does not yet
|
||||
// bind module bodies -- both module and class methods -- because those require the top-levels for all modules first.
|
||||
func (b *binder) bindPackageModules(pkg *symbols.Package) {
|
||||
// bindPackageDeclarations recursively binds all named entities and stores them in the given package. This doesn't yet
|
||||
// bind definitions, because those require the top-level declarations for all modules and members to be available first.
|
||||
func (b *binder) bindPackageDeclarations(pkg *symbols.Package) {
|
||||
contract.Require(pkg != nil, "pkg")
|
||||
if pkg.Node.Modules != nil {
|
||||
// First, for each module, simply create the symbol. This ensures that inter-module references are found.
|
||||
modules := *pkg.Node.Modules
|
||||
for _, modtok := range ast.StableModules(modules) {
|
||||
pkg.Modules[modtok] = b.createModule(modules[modtok], pkg)
|
||||
}
|
||||
|
||||
// Now that every module has a symbol entry, bind all module imports.
|
||||
for _, mod := range symbols.StableModuleMap(pkg.Modules) {
|
||||
b.bindModuleImports(pkg.Modules[mod])
|
||||
}
|
||||
|
||||
// Next, we must bind the top level class names. This is because inter-module references on classes might
|
||||
// exist in many places (properties, signatures, exports, and so on).
|
||||
for _, mod := range symbols.StableModuleMap(pkg.Modules) {
|
||||
b.bindModuleClasses(pkg.Modules[mod])
|
||||
}
|
||||
|
||||
// Now we can safely bind the property and method members.
|
||||
for _, mod := range symbols.StableModuleMap(pkg.Modules) {
|
||||
b.bindModuleMembers(pkg.Modules[mod])
|
||||
}
|
||||
|
||||
// And finally, we can bind the exports, that might refer to all of the above.
|
||||
for _, mod := range symbols.StableModuleMap(pkg.Modules) {
|
||||
b.bindModuleExports(pkg.Modules[mod])
|
||||
pkg.Modules[modtok] = b.bindModuleDeclarations(modules[modtok], pkg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bindPackageClassMembers binds all class member definitions within a package (function signatures and varaibles), but
|
||||
// doesn't actually bind any function bodies yet.
|
||||
func (b *binder) bindPackageClassMembers(pkg *symbols.Package) {
|
||||
// bindPackageDefinitions binds all definitions within a package (classes, signatures, varaibles, etc), but doesn't
|
||||
// actually bind any function bodies yet. The function bodies may depend upon information that depends upon information
|
||||
// that isn't fully computed until after the definition pass has been completed.
|
||||
func (b *binder) bindPackageDefinitions(pkg *symbols.Package) {
|
||||
contract.Require(pkg != nil, "pkg")
|
||||
for _, mod := range symbols.StableModuleMap(pkg.Modules) {
|
||||
b.bindModuleClassMembers(pkg.Modules[mod])
|
||||
b.bindModuleDefinitions(pkg.Modules[mod])
|
||||
}
|
||||
}
|
||||
|
||||
// bindPackageMethodBodies binds all method bodies, in a distinct pass, after binding all symbol-level information.
|
||||
func (b *binder) bindPackageMethodBodies(pkg *symbols.Package) {
|
||||
// bindPackageBodies binds all method bodies, in a distinct pass, after binding all symbol-level information.
|
||||
func (b *binder) bindPackageBodies(pkg *symbols.Package) {
|
||||
contract.Require(pkg != nil, "pkg")
|
||||
for _, mod := range symbols.StableModuleMap(pkg.Modules) {
|
||||
b.bindModuleMethodBodies(pkg.Modules[mod])
|
||||
b.bindModuleBodies(pkg.Modules[mod])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/marapongo/mu/pkg/compiler/ast"
|
||||
"github.com/marapongo/mu/pkg/diag"
|
||||
"github.com/marapongo/mu/pkg/tokens"
|
||||
"github.com/marapongo/mu/pkg/util/contract"
|
||||
)
|
||||
|
||||
// Class is a fully bound class symbol.
|
||||
|
@ -52,6 +53,17 @@ func (node *Class) GetInit() *ClassMethod {
|
|||
return nil
|
||||
}
|
||||
|
||||
// SetBase mutates the base class, in cases where it wasn't available at initialization time.
|
||||
func (node *Class) SetBase(extends Type) {
|
||||
contract.Assert(node.Extends == nil)
|
||||
node.Extends = extends
|
||||
|
||||
// If this class extends something else, wire up the "super" variable too.
|
||||
if extends != nil {
|
||||
node.Super = NewSpecialVariableSym(tokens.SuperVariable, extends)
|
||||
}
|
||||
}
|
||||
|
||||
// NewClassSym returns a new Class symbol with the given node, parent, extends, and implements, and empty members.
|
||||
func NewClassSym(node *ast.Class, parent *Module, extends Type, implements Types) *Class {
|
||||
nm := tokens.TypeName(node.Name.Ident)
|
||||
|
@ -65,7 +77,6 @@ func NewClassSym(node *ast.Class, parent *Module, extends Type, implements Types
|
|||
),
|
||||
),
|
||||
Parent: parent,
|
||||
Extends: extends,
|
||||
Implements: implements,
|
||||
Members: make(ClassMemberMap),
|
||||
}
|
||||
|
@ -73,10 +84,8 @@ func NewClassSym(node *ast.Class, parent *Module, extends Type, implements Types
|
|||
// Populate the "this" variable for instance methods.
|
||||
class.This = NewSpecialVariableSym(tokens.ThisVariable, class)
|
||||
|
||||
// If this class extends something else, wire up the "super" variable too.
|
||||
if extends != nil {
|
||||
class.Super = NewSpecialVariableSym(tokens.SuperVariable, extends)
|
||||
}
|
||||
// Set the base class, possibly initializing "super" if appropriate.
|
||||
class.SetBase(extends)
|
||||
|
||||
return class
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue