github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/src/go/types/eval.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package types 6 7 import ( 8 "fmt" 9 "go/parser" 10 "go/token" 11 ) 12 13 // Eval returns the type and, if constant, the value for the 14 // expression expr, evaluated at position pos of package pkg, 15 // which must have been derived from type-checking an AST with 16 // complete position information relative to the provided file 17 // set. 18 // 19 // If the expression contains function literals, their bodies 20 // are ignored (i.e., the bodies are not type-checked). 21 // 22 // If pkg == nil, the Universe scope is used and the provided 23 // position pos is ignored. If pkg != nil, and pos is invalid, 24 // the package scope is used. Otherwise, pos must belong to the 25 // package. 26 // 27 // An error is returned if pos is not within the package or 28 // if the node cannot be evaluated. 29 // 30 // Note: Eval should not be used instead of running Check to compute 31 // types and values, but in addition to Check. Eval will re-evaluate 32 // its argument each time, and it also does not know about the context 33 // in which an expression is used (e.g., an assignment). Thus, top- 34 // level untyped constants will return an untyped type rather then the 35 // respective context-specific type. 36 // 37 func Eval(fset *token.FileSet, pkg *Package, pos token.Pos, expr string) (TypeAndValue, error) { 38 // determine scope 39 var scope *Scope 40 if pkg == nil { 41 scope = Universe 42 pos = token.NoPos 43 } else if !pos.IsValid() { 44 scope = pkg.scope 45 } else { 46 // The package scope extent (position information) may be 47 // incorrect (files spread across a wide range of fset 48 // positions) - ignore it and just consider its children 49 // (file scopes). 50 for _, fscope := range pkg.scope.children { 51 if scope = fscope.Innermost(pos); scope != nil { 52 break 53 } 54 } 55 if scope == nil || debug { 56 s := scope 57 for s != nil && s != pkg.scope { 58 s = s.parent 59 } 60 // s == nil || s == pkg.scope 61 if s == nil { 62 return TypeAndValue{}, fmt.Errorf("no position %s found in package %s", fset.Position(pos), pkg.name) 63 } 64 } 65 } 66 67 // parse expressions 68 node, err := parser.ParseExprFrom(fset, "eval", expr, 0) 69 if err != nil { 70 return TypeAndValue{}, err 71 } 72 73 // initialize checker 74 check := NewChecker(nil, fset, pkg, nil) 75 check.scope = scope 76 check.pos = pos 77 defer check.handleBailout(&err) 78 79 // evaluate node 80 var x operand 81 check.rawExpr(&x, node, nil) 82 return TypeAndValue{x.mode, x.typ, x.val}, err 83 }