github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/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 pkg == nil, the Universe scope is used and the provided 20 // position pos is ignored. If pkg != nil, and pos is invalid, 21 // the package scope is used. Otherwise, pos must belong to the 22 // package. 23 // 24 // An error is returned if pos is not within the package or 25 // if the node cannot be evaluated. 26 // 27 // Note: Eval should not be used instead of running Check to compute 28 // types and values, but in addition to Check. Eval will re-evaluate 29 // its argument each time, and it also does not know about the context 30 // in which an expression is used (e.g., an assignment). Thus, top- 31 // level untyped constants will return an untyped type rather then the 32 // respective context-specific type. 33 // 34 func Eval(fset *token.FileSet, pkg *Package, pos token.Pos, expr string) (_ TypeAndValue, err error) { 35 // determine scope 36 var scope *Scope 37 if pkg == nil { 38 scope = Universe 39 pos = token.NoPos 40 } else if !pos.IsValid() { 41 scope = pkg.scope 42 } else { 43 // The package scope extent (position information) may be 44 // incorrect (files spread across a wide range of fset 45 // positions) - ignore it and just consider its children 46 // (file scopes). 47 for _, fscope := range pkg.scope.children { 48 if scope = fscope.Innermost(pos); scope != nil { 49 break 50 } 51 } 52 if scope == nil || debug { 53 s := scope 54 for s != nil && s != pkg.scope { 55 s = s.parent 56 } 57 // s == nil || s == pkg.scope 58 if s == nil { 59 return TypeAndValue{}, fmt.Errorf("no position %s found in package %s", fset.Position(pos), pkg.name) 60 } 61 } 62 } 63 64 // parse expressions 65 node, err := parser.ParseExprFrom(fset, "eval", expr, 0) 66 if err != nil { 67 return TypeAndValue{}, err 68 } 69 70 // initialize checker 71 check := NewChecker(nil, fset, pkg, nil) 72 check.scope = scope 73 check.pos = pos 74 defer check.handleBailout(&err) 75 76 // evaluate node 77 var x operand 78 check.rawExpr(&x, node, nil) 79 check.processDelayed(0) // incl. all functions 80 81 return TypeAndValue{x.mode, x.typ, x.val}, nil 82 }