Source file src/go/types/eval.go
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/ast" 10 "go/parser" 11 "go/token" 12 ) 13 14 // Eval returns the type and, if constant, the value for the 15 // expression expr, evaluated at position pos of package pkg, 16 // which must have been derived from type-checking an AST with 17 // complete position information relative to the provided file 18 // set. 19 // 20 // The meaning of the parameters fset, pkg, and pos is the 21 // same as in CheckExpr. An error is returned if expr cannot 22 // be parsed successfully, or the resulting expr AST cannot be 23 // type-checked. 24 func Eval(fset *token.FileSet, pkg *Package, pos token.Pos, expr string) (_ TypeAndValue, err error) { 25 // parse expressions 26 node, err := parser.ParseExprFrom(fset, "eval", expr, 0) 27 if err != nil { 28 return TypeAndValue{}, err 29 } 30 31 info := &Info{ 32 Types: make(map[ast.Expr]TypeAndValue), 33 } 34 err = CheckExpr(fset, pkg, pos, node, info) 35 return info.Types[node], err 36 } 37 38 // CheckExpr type checks the expression expr as if it had appeared at position 39 // pos of package pkg. Type information about the expression is recorded in 40 // info. The expression may be an identifier denoting an uninstantiated generic 41 // function or type. 42 // 43 // If pkg == nil, the Universe scope is used and the provided 44 // position pos is ignored. If pkg != nil, and pos is invalid, 45 // the package scope is used. Otherwise, pos must belong to the 46 // package. 47 // 48 // An error is returned if pos is not within the package or 49 // if the node cannot be type-checked. 50 // 51 // Note: Eval and CheckExpr should not be used instead of running Check 52 // to compute types and values, but in addition to Check, as these 53 // functions ignore the context in which an expression is used (e.g., an 54 // assignment). Thus, top-level untyped constants will return an 55 // untyped type rather then the respective context-specific type. 56 // 57 func CheckExpr(fset *token.FileSet, pkg *Package, pos token.Pos, expr ast.Expr, info *Info) (err error) { 58 // determine scope 59 var scope *Scope 60 if pkg == nil { 61 scope = Universe 62 pos = token.NoPos 63 } else if !pos.IsValid() { 64 scope = pkg.scope 65 } else { 66 // The package scope extent (position information) may be 67 // incorrect (files spread across a wide range of fset 68 // positions) - ignore it and just consider its children 69 // (file scopes). 70 for _, fscope := range pkg.scope.children { 71 if scope = fscope.Innermost(pos); scope != nil { 72 break 73 } 74 } 75 if scope == nil || debug { 76 s := scope 77 for s != nil && s != pkg.scope { 78 s = s.parent 79 } 80 // s == nil || s == pkg.scope 81 if s == nil { 82 return fmt.Errorf("no position %s found in package %s", fset.Position(pos), pkg.name) 83 } 84 } 85 } 86 87 // initialize checker 88 check := NewChecker(nil, fset, pkg, info) 89 check.scope = scope 90 check.pos = pos 91 defer check.handleBailout(&err) 92 93 // evaluate node 94 var x operand 95 check.rawExpr(&x, expr, nil, true) // allow generic expressions 96 check.processDelayed(0) // incl. all functions 97 check.recordUntyped() 98 99 return nil 100 } 101