github.com/rsc/go@v0.0.0-20150416155037-e040fd465409/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 // This file implements New, Eval and EvalNode. 6 7 package types 8 9 import ( 10 "fmt" 11 "go/ast" 12 "go/parser" 13 "go/token" 14 ) 15 16 // New is a convenience function to create a new type from a given 17 // expression or type literal string evaluated in Universe scope. 18 // New(str) is shorthand for Eval(str, nil, nil), but only returns 19 // the type result, and panics in case of an error. 20 // Position info for objects in the result type is undefined. 21 // 22 func New(str string) Type { 23 tv, err := Eval(str, nil, nil) 24 if err != nil { 25 panic(err) 26 } 27 return tv.Type 28 } 29 30 // Eval returns the type and, if constant, the value for the 31 // expression or type literal string str evaluated in scope. 32 // If the expression contains function literals, the function 33 // bodies are ignored (though they must be syntactically correct). 34 // 35 // If pkg == nil, the Universe scope is used and the provided 36 // scope is ignored. Otherwise, the scope must belong to the 37 // package (either the package scope, or nested within the 38 // package scope). 39 // 40 // An error is returned if the scope is incorrect, the string 41 // has syntax errors, or if it cannot be evaluated in the scope. 42 // Position info for objects in the result type is undefined. 43 // 44 // Note: Eval should not be used instead of running Check to compute 45 // types and values, but in addition to Check. Eval will re-evaluate 46 // its argument each time, and it also does not know about the context 47 // in which an expression is used (e.g., an assignment). Thus, top- 48 // level untyped constants will return an untyped type rather then the 49 // respective context-specific type. 50 // 51 func Eval(str string, pkg *Package, scope *Scope) (TypeAndValue, error) { 52 node, err := parser.ParseExpr(str) 53 if err != nil { 54 return TypeAndValue{}, err 55 } 56 57 // Create a file set that looks structurally identical to the 58 // one created by parser.ParseExpr for correct error positions. 59 fset := token.NewFileSet() 60 fset.AddFile("", len(str), fset.Base()).SetLinesForContent([]byte(str)) 61 62 return EvalNode(fset, node, pkg, scope) 63 } 64 65 // EvalNode is like Eval but instead of string it accepts 66 // an expression node and respective file set. 67 // 68 // An error is returned if the scope is incorrect 69 // if the node cannot be evaluated in the scope. 70 // 71 func EvalNode(fset *token.FileSet, node ast.Expr, pkg *Package, scope *Scope) (tv TypeAndValue, err error) { 72 // verify package/scope relationship 73 if pkg == nil { 74 scope = Universe 75 } else { 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 TypeAndValue{}, fmt.Errorf("scope does not belong to package %s", pkg.name) 83 } 84 } 85 86 // initialize checker 87 check := NewChecker(nil, fset, pkg, nil) 88 check.scope = scope 89 defer check.handleBailout(&err) 90 91 // evaluate node 92 var x operand 93 check.rawExpr(&x, node, nil) 94 return TypeAndValue{x.mode, x.typ, x.val}, nil 95 }