mirror of https://github.com/hashicorp/terraform
parent
25a2fbc902
commit
ec3b5f3886
@ -0,0 +1,74 @@
|
||||
package lang
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/config/lang/ast"
|
||||
)
|
||||
|
||||
func TestLookupType(t *testing.T) {
|
||||
cases := []struct {
|
||||
Input ast.Node
|
||||
Scope *Scope
|
||||
Output ast.Type
|
||||
Error bool
|
||||
}{
|
||||
{
|
||||
&customUntyped{},
|
||||
nil,
|
||||
ast.TypeInvalid,
|
||||
true,
|
||||
},
|
||||
|
||||
{
|
||||
&customTyped{},
|
||||
nil,
|
||||
ast.TypeString,
|
||||
false,
|
||||
},
|
||||
|
||||
{
|
||||
&ast.LiteralNode{
|
||||
Value: 42,
|
||||
Type: ast.TypeInt,
|
||||
},
|
||||
nil,
|
||||
ast.TypeInt,
|
||||
false,
|
||||
},
|
||||
|
||||
{
|
||||
&ast.VariableAccess{
|
||||
Name: "foo",
|
||||
},
|
||||
&Scope{
|
||||
VarMap: map[string]Variable{
|
||||
"foo": Variable{Type: ast.TypeInt},
|
||||
},
|
||||
},
|
||||
ast.TypeInt,
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
actual, err := LookupType(tc.Input, tc.Scope)
|
||||
if (err != nil) != tc.Error {
|
||||
t.Fatalf("bad: %s\n\nInput: %#v", err, tc.Input)
|
||||
}
|
||||
if actual != tc.Output {
|
||||
t.Fatalf("bad: %s\n\nInput: %#v", actual, tc.Input)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type customUntyped struct{}
|
||||
|
||||
func (n customUntyped) Accept(ast.Visitor) {}
|
||||
func (n customUntyped) Pos() (v ast.Pos) { return }
|
||||
|
||||
type customTyped struct{}
|
||||
|
||||
func (n customTyped) Accept(ast.Visitor) {}
|
||||
func (n customTyped) Pos() (v ast.Pos) { return }
|
||||
func (n customTyped) Type(*Scope) (ast.Type, error) { return ast.TypeString, nil }
|
||||
@ -0,0 +1,58 @@
|
||||
package lang
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/terraform/config/lang/ast"
|
||||
)
|
||||
|
||||
// LookupType looks up the type of the given node with the given scope.
|
||||
func LookupType(raw ast.Node, scope *Scope) (ast.Type, error) {
|
||||
switch n := raw.(type) {
|
||||
case *ast.LiteralNode:
|
||||
return typedLiteralNode{n}.Type(scope)
|
||||
case *ast.VariableAccess:
|
||||
return typedVariableAccess{n}.Type(scope)
|
||||
default:
|
||||
if t, ok := raw.(TypedNode); ok {
|
||||
return t.Type(scope)
|
||||
}
|
||||
|
||||
return ast.TypeInvalid, fmt.Errorf(
|
||||
"unknown node to get type of: %T", raw)
|
||||
}
|
||||
}
|
||||
|
||||
// TypedNode is an interface that custom AST nodes should implement
|
||||
// if they want to work with LookupType. All the builtin AST nodes have
|
||||
// implementations of this.
|
||||
type TypedNode interface {
|
||||
Type(*Scope) (ast.Type, error)
|
||||
}
|
||||
|
||||
type typedLiteralNode struct {
|
||||
n *ast.LiteralNode
|
||||
}
|
||||
|
||||
func (n typedLiteralNode) Type(s *Scope) (ast.Type, error) {
|
||||
return n.n.Type, nil
|
||||
}
|
||||
|
||||
type typedVariableAccess struct {
|
||||
n *ast.VariableAccess
|
||||
}
|
||||
|
||||
func (n typedVariableAccess) Type(s *Scope) (ast.Type, error) {
|
||||
v, ok := s.LookupVar(n.n.Name)
|
||||
if !ok {
|
||||
return ast.TypeInvalid, fmt.Errorf(
|
||||
"%s: couldn't find variable %s", n.n.Pos(), n.n.Name)
|
||||
}
|
||||
|
||||
return v.Type, nil
|
||||
}
|
||||
|
||||
var supportedTransforms = map[ast.Type]ast.Type{
|
||||
ast.TypeString: ast.TypeInt,
|
||||
ast.TypeInt: ast.TypeString,
|
||||
}
|
||||
Loading…
Reference in new issue