From c5aea187c2decc136869d3103dd75075dfac796c Mon Sep 17 00:00:00 2001 From: joeduffy Date: Tue, 24 Jan 2017 10:29:37 -0800 Subject: [PATCH] Creater a binder.Context structure This change introduces a binder.Context structure, with a *core.Context embedded, that carries additional semantic information forward to future passes in the compiler. In particular, this is how the evaluation/interpretation phase will gain access to types, scopes, and symbols. --- pkg/compiler/binder/binder.go | 133 +++--------------------------- pkg/compiler/binder/class.go | 8 +- pkg/compiler/binder/context.go | 139 ++++++++++++++++++++++++++++++++ pkg/compiler/binder/func.go | 6 +- pkg/compiler/binder/legacy.go | 14 ++-- pkg/compiler/binder/module.go | 8 +- pkg/compiler/binder/stmtexpr.go | 50 ++++++------ 7 files changed, 191 insertions(+), 167 deletions(-) create mode 100644 pkg/compiler/binder/context.go diff --git a/pkg/compiler/binder/binder.go b/pkg/compiler/binder/binder.go index 992a7bba6..31b9df245 100644 --- a/pkg/compiler/binder/binder.go +++ b/pkg/compiler/binder/binder.go @@ -22,47 +22,32 @@ import ( type Binder interface { core.Phase + // BindCtx represents the contextual information resulting from binding. + BindCtx() *Context + // BindPackages takes a package AST, resolves all dependencies and tokens inside of it, and returns a fully bound // package symbol that can be used for semantic operations (like interpretation and evaluation). BindPackage(pkg *pack.Package) *symbols.Package } -// TypeMap maps AST nodes to their corresponding type. The semantics of this differ based on the kind of node. For -// example, an ast.Expression's type is the type of its evaluation; an ast.LocalVariable's type is the bound type of its -// value. And so on. This is used during binding, type checking, and evaluation, to perform type-sensitive operations. -// This avoids needing to recreate scopes and/or storing type information on every single node in the AST. -type TypeMap map[ast.Node]symbols.Type - // New allocates a fresh binder object with the given workspace, context, and metadata reader. func New(w workspace.W, ctx *core.Context, reader metadata.Reader) Binder { - // Create a new binder and a new scope with an empty symbol table. - b := &binder{ + // Create a new binder with a fresh binding context. + return &binder{ w: w, - ctx: ctx, + ctx: NewContextFrom(ctx), reader: reader, - types: make(TypeMap), } - - // Create a global scope and populate it with all of the predefined type names. This one's never popped. - NewScope(ctx, &b.scope) - for _, prim := range types.Primitives { - b.scope.MustRegister(prim) - } - - return b } type binder struct { w workspace.W // a workspace in which this compilation is happening. - ctx *core.Context // a context shared across all phases of compilation. + ctx *Context // a binding context shared with future phases of compilation. reader metadata.Reader // a metadata reader (in case we encounter package references). - scope *Scope // the current (mutable) scope. - types TypeMap // the typechecked types for expressions (see TypeMap's comments above). } -func (b *binder) Diag() diag.Sink { - return b.ctx.Diag -} +func (b *binder) BindCtx() *Context { return b.ctx } +func (b *binder) Diag() diag.Sink { return b.ctx.Diag } // bindType binds a type token AST node to a symbol. func (b *binder) bindType(node *ast.TypeToken) symbols.Type { @@ -261,7 +246,7 @@ func (b *binder) requireToken(node ast.Node, tok tokens.Token) symbols.Symbol { } } else { // A simple token has no package, module, or class part. It refers to the symbol table. - if sym := b.scope.Lookup(tok); sym != nil { + if sym := b.ctx.Scope.Lookup(tok); sym != nil { return sym } else { b.Diag().Errorf(errors.ErrorSymbolNotFound.At(node), tok, "simple name not found") @@ -283,101 +268,3 @@ func (b *binder) requireClassMember(node ast.Node, class symbols.Type, tok token } return nil } - -// requireType requires that a type exists for the given AST node. -func (b *binder) requireType(node ast.Node) symbols.Type { - ty := b.types[node] - contract.Assertf(ty != nil, "Expected a typemap entry for %v node", node.GetKind()) - return ty -} - -// requireExprType fetches an expression's non-nil type. -func (b *binder) requireExprType(node ast.Expression) symbols.Type { - return b.requireType(node) -} - -// registerExprType registers an expression's type. -func (b *binder) registerExprType(node ast.Expression, tysym symbols.Type) { - contract.Require(tysym != nil, "tysym") - contract.Assert(b.types[node] == nil) - if glog.V(7) { - glog.V(7).Infof("Registered expression type: '%v' => %v", node.GetKind(), tysym.Name()) - } - b.types[node] = tysym -} - -// requireFunctionType fetches the non-nil registered type for a given function. -func (b *binder) requireFunctionType(node ast.Function) *symbols.FunctionType { - ty := b.requireType(node) - fty, ok := ty.(*symbols.FunctionType) - contract.Assertf(ok, "Expected function type for %v; got %v", node.GetKind(), fty.Token()) - return fty -} - -// registerFunctionType understands how to turn any function node into a type, and adds it to the type table. This -// works for any kind of function-like AST node: module property, class property, or lambda. -func (b *binder) registerFunctionType(node ast.Function) *symbols.FunctionType { - // Make a function type and inject it into the type table. - var params []symbols.Type - np := node.GetParameters() - if np != nil { - for _, param := range *np { - var ptysym symbols.Type - - // If there was an explicit type, look it up. - if param.Type != nil { - ptysym = b.scope.LookupType(param.Type.Tok) - } - - // If either the parameter's type was unknown, or the lookup failed (leaving an error), use the any type. - if ptysym == nil { - ptysym = types.Any - } - - params = append(params, ptysym) - } - } - - var ret symbols.Type - nr := node.GetReturnType() - if nr != nil { - ret = b.scope.LookupType(nr.Tok) - } - - tysym := symbols.NewFunctionType(params, ret) - if glog.V(7) { - glog.V(7).Infof("Registered function type: '%v' => %v", node.GetName().Ident, tysym.Name()) - } - b.types[node] = tysym - - return tysym -} - -// requireVariableType fetches the non-nil registered type for a given variable. -func (b *binder) requireVariableType(node ast.Variable) symbols.Type { - return b.requireType(node) -} - -// registerVariableType understands how to turn any variable node into a type, and adds it to the type table. This -// works for any kind of variable-like AST node: module property, class property, parameter, or local variable. -func (b *binder) registerVariableType(node ast.Variable) symbols.Type { - var tysym symbols.Type - - // If there is an explicit node type, use it. - nt := node.GetType() - if nt != nil { - tysym = b.scope.LookupType(nt.Tok) - } - - // Otherwise, either there was no type, or the lookup failed (leaving behind an error); use the any type. - if tysym == nil { - tysym = types.Any - } - - if glog.V(7) { - glog.V(7).Infof("Registered variable type: '%v' => %v", node.GetName().Ident, tysym.Name()) - } - b.types[node] = tysym - - return tysym -} diff --git a/pkg/compiler/binder/class.go b/pkg/compiler/binder/class.go index df1c70663..27e83833b 100644 --- a/pkg/compiler/binder/class.go +++ b/pkg/compiler/binder/class.go @@ -16,12 +16,12 @@ func (b *binder) bindClass(node *ast.Class, parent *symbols.Module) *symbols.Cla // Bind base type tokens to actual symbols. var extends symbols.Type if node.Extends != nil { - extends = b.scope.LookupType(node.Extends.Tok) + extends = b.ctx.Scope.LookupType(node.Extends.Tok) } var implements symbols.Types if node.Implements != nil { for _, impltok := range *node.Implements { - if impl := b.scope.LookupType(impltok.Tok); impl != nil { + if impl := b.ctx.Scope.LookupType(impltok.Tok); impl != nil { implements = append(implements, impl) } } @@ -61,7 +61,7 @@ func (b *binder) bindClassProperty(node *ast.ClassProperty, parent *symbols.Clas glog.V(3).Infof("Binding class '%v' property '%v'", parent.Name(), node.Name.Ident) // Look up this node's type and inject it into the type table. - ty := b.registerVariableType(node) + ty := b.ctx.RegisterVariableType(node) return symbols.NewClassPropertySym(node, parent, ty) } @@ -69,7 +69,7 @@ func (b *binder) bindClassMethod(node *ast.ClassMethod, parent *symbols.Class) * glog.V(3).Infof("Binding class '%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.registerFunctionType(node) + ty := b.ctx.RegisterFunctionType(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. diff --git a/pkg/compiler/binder/context.go b/pkg/compiler/binder/context.go new file mode 100644 index 000000000..dab9727a6 --- /dev/null +++ b/pkg/compiler/binder/context.go @@ -0,0 +1,139 @@ +// Copyright 2016 Marapongo, Inc. All rights reserved. + +package binder + +import ( + "github.com/golang/glog" + + "github.com/marapongo/mu/pkg/compiler/ast" + "github.com/marapongo/mu/pkg/compiler/core" + "github.com/marapongo/mu/pkg/compiler/symbols" + "github.com/marapongo/mu/pkg/compiler/types" + "github.com/marapongo/mu/pkg/util/contract" +) + +// Context holds binder-specific context information, like symbol and type binding information. +type Context struct { + *core.Context // inherits all of the other context info. + Scope *Scope // the current (mutable) scope. + Types TypeMap // the type-checked type symbols for expressions. +} + +func NewContextFrom(ctx *core.Context) *Context { + bctx := &Context{ + Context: ctx, + Types: make(TypeMap), + } + + // Create a global scope and populate it with all of the predefined type names. This one's never popped. + NewScope(ctx, &bctx.Scope) + for _, prim := range types.Primitives { + bctx.Scope.MustRegister(prim) + } + + return bctx +} + +// TypeMap maps AST nodes to their corresponding type. The semantics of this differ based on the kind of node. For +// example, an ast.Expression's type is the type of its evaluation; an ast.LocalVariable's type is the bound type of its +// value. And so on. This is used during binding, type checking, and evaluation, to perform type-sensitive operations. +// This avoids needing to recreate scopes and/or storing type information on every single node in the AST. +type TypeMap map[ast.Node]symbols.Type + +// RequireType requires that a type exists for the given AST node. +func (ctx *Context) RequireType(node ast.Node) symbols.Type { + ty := ctx.Types[node] + contract.Assertf(ty != nil, "Expected a typemap entry for %v node", node.GetKind()) + return ty +} + +// RequireExprType fetches an expression's non-nil type. +func (ctx *Context) RequireExprType(node ast.Expression) symbols.Type { + return ctx.RequireType(node) +} + +// RegisterExprType registers an expression's type. +func (ctx *Context) RegisterExprType(node ast.Expression, tysym symbols.Type) { + contract.Require(tysym != nil, "tysym") + contract.Assert(ctx.Types[node] == nil) + if glog.V(7) { + glog.V(7).Infof("Registered expression type: '%v' => %v", node.GetKind(), tysym.Name()) + } + ctx.Types[node] = tysym +} + +// RequireFunctionType fetches the non-nil registered type for a given function. +func (ctx *Context) RequireFunctionType(node ast.Function) *symbols.FunctionType { + ty := ctx.RequireType(node) + fty, ok := ty.(*symbols.FunctionType) + contract.Assertf(ok, "Expected function type for %v; got %v", node.GetKind(), fty.Token()) + return fty +} + +// RegisterFunctionType understands how to turn any function node into a type, and adds it to the type table. This +// works for any kind of function-like AST node: module property, class property, or lambda. +func (ctx *Context) RegisterFunctionType(node ast.Function) *symbols.FunctionType { + // Make a function type and inject it into the type table. + var params []symbols.Type + np := node.GetParameters() + if np != nil { + for _, param := range *np { + var ptysym symbols.Type + + // If there was an explicit type, look it up. + if param.Type != nil { + ptysym = ctx.Scope.LookupType(param.Type.Tok) + } + + // If either the parameter's type was unknown, or the lookup failed (leaving an error), use the any type. + if ptysym == nil { + ptysym = types.Any + } + + params = append(params, ptysym) + } + } + + var ret symbols.Type + nr := node.GetReturnType() + if nr != nil { + ret = ctx.Scope.LookupType(nr.Tok) + } + + tysym := symbols.NewFunctionType(params, ret) + if glog.V(7) { + glog.V(7).Infof("Registered function type: '%v' => %v", node.GetName().Ident, tysym.Name()) + } + ctx.Types[node] = tysym + + return tysym +} + +// RequireVariableType fetches the non-nil registered type for a given variable. +func (ctx *Context) RequireVariableType(node ast.Variable) symbols.Type { + return ctx.RequireType(node) +} + +// RegisterVariableType understands how to turn any variable node into a type, and adds it to the type table. This +// works for any kind of variable-like AST node: module property, class property, parameter, or local variable. +func (ctx *Context) RegisterVariableType(node ast.Variable) symbols.Type { + var tysym symbols.Type + + // If there is an explicit node type, use it. + nt := node.GetType() + if nt != nil { + tysym = ctx.Scope.LookupType(nt.Tok) + } + + // Otherwise, either there was no type, or the lookup failed (leaving behind an error); use the any type. + if tysym == nil { + tysym = types.Any + } + + if glog.V(7) { + glog.V(7).Infof("Registered variable type: '%v' => %v", node.GetName().Ident, tysym.Name()) + } + ctx.Types[node] = tysym + + return tysym +} diff --git a/pkg/compiler/binder/func.go b/pkg/compiler/binder/func.go index fa81d493d..f12323938 100644 --- a/pkg/compiler/binder/func.go +++ b/pkg/compiler/binder/func.go @@ -10,14 +10,14 @@ import ( // bindFunctionBody binds a function body, including a scope, its parameters, and its expressions and statements. func (b *binder) bindFunctionBody(node ast.Function) { // Enter a new scope, bind the parameters, and then bind the body using a visitor. - scope := b.scope.Push() + scope := b.ctx.Scope.Push() defer scope.Pop() params := node.GetParameters() if params != nil { for _, param := range *params { // Register this variable's type and associate its name with the identifier. - b.registerVariableType(param) - b.scope.TryRegister(param, symbols.NewLocalVariableSym(param)) + b.ctx.RegisterVariableType(param) + b.ctx.Scope.TryRegister(param, symbols.NewLocalVariableSym(param)) } } diff --git a/pkg/compiler/binder/legacy.go b/pkg/compiler/binder/legacy.go index ca41c859c..ad7174205 100644 --- a/pkg/compiler/binder/legacy.go +++ b/pkg/compiler/binder/legacy.go @@ -71,37 +71,37 @@ func (b *binder) ValidateStack(stack *ast.Stack) { // LookupService binds a name to a Service type. func (b *binder) LookupService(nm tokens.Name) (*ast.Service, bool) { - contract.Assertf(b.scope != nil, "Unexpected empty binding scope during LookupService") + contract.Assertf(b.ctx.Scope != nil, "Unexpected empty binding scope during LookupService") return nil, false } // LookupStack binds a name to a Stack type. func (b *binder) LookupStack(nm tokens.PackageName) (*ast.Stack, bool) { - contract.Assertf(b.scope != nil, "Unexpected empty binding scope during LookupStack") + contract.Assertf(b.ctx.Scope != nil, "Unexpected empty binding scope during LookupStack") return nil, false } // LookupUninstStack binds a name to a UninstStack type. func (b *binder) LookupUninstStack(nm tokens.PackageName) (*ast.UninstStack, bool) { - contract.Assertf(b.scope != nil, "Unexpected empty binding scope during LookupUninstStack") + contract.Assertf(b.ctx.Scope != nil, "Unexpected empty binding scope during LookupUninstStack") return nil, false } // LookupSchema binds a name to a Schema type. func (b *binder) LookupSchema(nm tokens.PackageName) (*ast.Schema, bool) { - contract.Assertf(b.scope != nil, "Unexpected empty binding scope during LookupSchema") + contract.Assertf(b.ctx.Scope != nil, "Unexpected empty binding scope during LookupSchema") return nil, false } // LookupSymbol binds a name to any kind of Symbol. func (b *binder) LookupSymbol(nm tokens.Name) (*legacy.Symbol, bool) { - contract.Assertf(b.scope != nil, "Unexpected empty binding scope during LookupSymbol") + contract.Assertf(b.ctx.Scope != nil, "Unexpected empty binding scope during LookupSymbol") return nil, false } // RegisterSymbol registers a symbol with the given name; if it already exists, the function returns false. func (b *binder) RegisterSymbol(sym *legacy.Symbol) bool { - contract.Assertf(b.scope != nil, "Unexpected empty binding scope during RegisterSymbol") + contract.Assertf(b.ctx.Scope != nil, "Unexpected empty binding scope during RegisterSymbol") return false } @@ -150,7 +150,6 @@ func (p *binderPreparePhase) VisitStack(stack *ast.Stack) { // Stack names are required. if stack.Name == "" { - p.Diag().Errorf(errors.ErrorMissingStackName.At(stack)) } // Stack versions must be valid semantic versions (and specifically, not ranges). In other words, we need @@ -348,7 +347,6 @@ func (p *binderBindPhase) VisitService(pstack *ast.Stack, parent *ast.Services, // A service cannot instantiate an abstract stack. if svc.BoundType != nil && svc.BoundType.Abstract { - p.Diag().Errorf(errors.ErrorCannotCreateAbstractStack.At(pstack), svc.Name, svc.BoundType.Name) } } diff --git a/pkg/compiler/binder/module.go b/pkg/compiler/binder/module.go index 4ea40ddf5..1fe8d63f8 100644 --- a/pkg/compiler/binder/module.go +++ b/pkg/compiler/binder/module.go @@ -24,7 +24,7 @@ func (b *binder) bindModule(node *ast.Module, parent *symbols.Package) *symbols. // First bind all imports to concrete symbols. These will be used to perform initialization later on. if node.Imports != nil { for _, imptok := range *node.Imports { - if imp := b.scope.LookupModule(imptok.Tok); imp != nil { + if imp := b.ctx.Scope.LookupModule(imptok.Tok); imp != nil { module.Imports = append(module.Imports, imp) } } @@ -62,7 +62,7 @@ func (b *binder) bindExport(node *ast.Export, parent *symbols.Module) *symbols.E glog.V(3).Infof("Binding module '%v' export '%v'", parent.Name(), node.Name.Ident) // To bind an export, simply look up the referent symbol and associate this name with it. - refsym := b.scope.Lookup(node.Referent.Tok) + refsym := b.ctx.Scope.Lookup(node.Referent.Tok) if refsym == nil { // TODO: issue a verification error; name not found! Also sub in a "bad" symbol. contract.Failf("Export name not found: %v", node.Referent) @@ -74,7 +74,7 @@ func (b *binder) bindModuleProperty(node *ast.ModuleProperty, parent *symbols.Mo 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.registerVariableType(node) + ty := b.ctx.RegisterVariableType(node) return symbols.NewModulePropertySym(node, parent, ty) } @@ -82,7 +82,7 @@ func (b *binder) bindModuleMethod(node *ast.ModuleMethod, parent *symbols.Module 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.registerFunctionType(node) + ty := b.ctx.RegisterFunctionType(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. diff --git a/pkg/compiler/binder/stmtexpr.go b/pkg/compiler/binder/stmtexpr.go index cf40db3b0..c0df7fe38 100644 --- a/pkg/compiler/binder/stmtexpr.go +++ b/pkg/compiler/binder/stmtexpr.go @@ -65,13 +65,13 @@ func (a *astBinder) After(node ast.Node) { // Expressions case *ast.NullLiteral: - a.b.registerExprType(n, types.Null) // register a null type. + a.b.ctx.RegisterExprType(n, types.Null) // register a null type. case *ast.BoolLiteral: - a.b.registerExprType(n, types.Bool) // register a bool type. + a.b.ctx.RegisterExprType(n, types.Bool) // register a bool type. case *ast.NumberLiteral: - a.b.registerExprType(n, types.Number) // register as a number type. + a.b.ctx.RegisterExprType(n, types.Number) // register as a number type. case *ast.StringLiteral: - a.b.registerExprType(n, types.String) // register as a string type. + a.b.ctx.RegisterExprType(n, types.String) // register as a string type. case *ast.ArrayLiteral: a.checkArrayLiteral(n) case *ast.ObjectLiteral: @@ -79,7 +79,7 @@ func (a *astBinder) After(node ast.Node) { case *ast.LoadLocationExpression: a.checkLoadLocationExpression(n) case *ast.LoadDynamicExpression: - a.b.registerExprType(n, types.Any) // register as an any type. + a.b.ctx.RegisterExprType(n, types.Any) // register as an any type. case *ast.NewExpression: a.checkNewExpression(n) case *ast.InvokeFunctionExpression: @@ -102,19 +102,19 @@ func (a *astBinder) After(node ast.Node) { // Ensure that all expression types resulted in a type registration. expr, isExpr := node.(ast.Expression) - contract.Assert(!isExpr || a.b.requireExprType(expr) != nil) + contract.Assert(!isExpr || a.b.ctx.RequireExprType(expr) != nil) } // Statements func (a *astBinder) visitBlock(node *ast.Block) { // Entering a new block requires a fresh lexical scope. - a.b.scope.Push() + a.b.ctx.Scope.Push() } func (a *astBinder) checkBlock(node *ast.Block) { // Exiting a block restores the prior lexical context. - a.b.scope.Pop() + a.b.ctx.Scope.Pop() } func (a *astBinder) checkBreakStatement(node *ast.BreakStatement) { @@ -144,8 +144,8 @@ func (a *astBinder) checkIfStatement(node *ast.IfStatement) { func (a *astBinder) visitLocalVariable(node *ast.LocalVariable) { // Encountering a new local variable results in registering it; both to the type and symbol table. - a.b.registerVariableType(node) - a.b.scope.TryRegister(node, symbols.NewLocalVariableSym(node)) + a.b.ctx.RegisterVariableType(node) + a.b.ctx.Scope.TryRegister(node, symbols.NewLocalVariableSym(node)) } func (a *astBinder) visitLabeledStatement(node *ast.LabeledStatement) { @@ -159,7 +159,7 @@ func (a *astBinder) visitLabeledStatement(node *ast.LabeledStatement) { func (a *astBinder) checkReturnStatement(node *ast.ReturnStatement) { // Ensure that the return expression is correct (present or missing; and its type). - fncty := a.b.requireFunctionType(a.fnc) + fncty := a.b.ctx.RequireFunctionType(a.fnc) if fncty.Return == nil { if node.Expression != nil { // The function has no return type ("void"), and yet the return had an expression. @@ -188,7 +188,7 @@ func (a *astBinder) checkWhileStatement(node *ast.WhileStatement) { // Expressions func (a *astBinder) checkExprType(expr ast.Expression, expect symbols.Type) bool { - actual := a.b.requireExprType(expr) + actual := a.b.ctx.RequireExprType(expr) if !types.CanConvert(actual, expect) { a.b.Diag().Errorf(errors.ErrorIncorrectExprType.At(expr), expect, actual) return false @@ -203,10 +203,10 @@ func (a *astBinder) checkArrayLiteral(node *ast.ArrayLiteral) { } // Now mark the resulting expression as an array of the right type. if node.ElemType == nil { - a.b.registerExprType(node, types.AnyArray) + a.b.ctx.RegisterExprType(node, types.AnyArray) } else { elemType := a.b.bindType(node.ElemType) - a.b.registerExprType(node, symbols.NewArrayType(elemType)) + a.b.ctx.RegisterExprType(node, symbols.NewArrayType(elemType)) // Ensure the elements, if any, are of the right type. if node.Elements != nil { @@ -220,10 +220,10 @@ func (a *astBinder) checkArrayLiteral(node *ast.ArrayLiteral) { func (a *astBinder) checkObjectLiteral(node *ast.ObjectLiteral) { // Mark the resulting object literal with the correct type. if node.Type == nil { - a.b.registerExprType(node, types.Any) + a.b.ctx.RegisterExprType(node, types.Any) } else { ty := a.b.bindType(node.Type) - a.b.registerExprType(node, ty) + a.b.ctx.RegisterExprType(node, ty) // Only permit object literals for records and interfaces. Classes have constructors. if !ty.Record() && !ty.Interface() { @@ -268,7 +268,7 @@ func (a *astBinder) checkLoadLocationExpression(node *ast.LoadLocationExpression sym = a.b.requireToken(node.Name, node.Name.Tok) } else { // If there's an object, we are accessing a class member property or function. - typ := a.b.requireExprType(*node.Object) + typ := a.b.ctx.RequireExprType(*node.Object) sym = a.b.requireClassMember(node.Name, typ, tokens.ClassMember(node.Name.Tok)) } @@ -279,16 +279,16 @@ func (a *astBinder) checkLoadLocationExpression(node *ast.LoadLocationExpression } else { switch s := sym.(type) { case ast.Function: - ty = a.b.requireFunctionType(s) + ty = a.b.ctx.RequireFunctionType(s) case ast.Variable: - ty = a.b.requireVariableType(s) + ty = a.b.ctx.RequireVariableType(s) default: contract.Failf("Unrecognized load location symbol type: %v", sym.Token()) } } // Register a pointer type so that this expression is a valid l-expr. - a.b.registerExprType(node, symbols.NewPointerType(ty)) + a.b.ctx.RegisterExprType(node, symbols.NewPointerType(ty)) } func (a *astBinder) checkNewExpression(node *ast.NewExpression) { @@ -306,7 +306,7 @@ func (a *astBinder) checkNewExpression(node *ast.NewExpression) { } } - a.b.registerExprType(node, ty) + a.b.ctx.RegisterExprType(node, ty) } func (a *astBinder) checkInvokeFunctionExpression(node *ast.InvokeFunctionExpression) { @@ -319,14 +319,14 @@ func (a *astBinder) checkLambdaExpression(node *ast.LambdaExpression) { var params []symbols.Type if pparams := node.GetParameters(); pparams != nil { for _, param := range *pparams { - params = append(params, a.b.requireVariableType(param)) + params = append(params, a.b.ctx.RequireVariableType(param)) } } var ret symbols.Type if pret := node.GetReturnType(); pret != nil { ret = a.b.bindType(pret) } - a.b.registerExprType(node, symbols.NewFunctionType(params, ret)) + a.b.ctx.RegisterExprType(node, symbols.NewFunctionType(params, ret)) } func (a *astBinder) checkUnaryOperatorExpression(node *ast.UnaryOperatorExpression) { @@ -341,7 +341,7 @@ func (a *astBinder) checkBinaryOperatorExpression(node *ast.BinaryOperatorExpres func (a *astBinder) checkCastExpression(node *ast.CastExpression) { // TODO: validate that this is legal. - a.b.registerExprType(node, a.b.bindType(node.Type)) + a.b.ctx.RegisterExprType(node, a.b.bindType(node.Type)) } func (a *astBinder) checkTypeOfExpression(node *ast.TypeOfExpression) { @@ -355,5 +355,5 @@ func (a *astBinder) checkConditionalExpression(node *ast.ConditionalExpression) func (a *astBinder) checkSequenceExpression(node *ast.SequenceExpression) { // The type of a sequence expression is just the type of the last expression in the sequence. // TODO: check that there's at least one! - a.b.registerExprType(node, a.b.requireExprType(node.Expressions[len(node.Expressions)-1])) + a.b.ctx.RegisterExprType(node, a.b.ctx.RequireExprType(node.Expressions[len(node.Expressions)-1])) }