From 2b405bc41c752097d7f83470cf540ae847a58206 Mon Sep 17 00:00:00 2001 From: James Nugent Date: Wed, 23 Mar 2016 05:14:43 -0700 Subject: [PATCH] deps: Update github.com/hashicorp/hil --- Godeps/Godeps.json | 4 +- vendor/github.com/hashicorp/hil/appveyor.yml | 18 +++++ vendor/github.com/hashicorp/hil/ast/ast.go | 1 + vendor/github.com/hashicorp/hil/ast/index.go | 46 ++++++------ .../hashicorp/hil/ast/variables_helper.go | 45 ++++++++++++ .../github.com/hashicorp/hil/check_types.go | 71 +++++++++++-------- vendor/github.com/hashicorp/hil/eval.go | 66 ++++++++++++++--- vendor/github.com/hashicorp/hil/y.go | 37 +++++----- 8 files changed, 207 insertions(+), 81 deletions(-) create mode 100644 vendor/github.com/hashicorp/hil/appveyor.yml create mode 100644 vendor/github.com/hashicorp/hil/ast/variables_helper.go diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 1d57dc97b9..76507749e3 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -738,11 +738,11 @@ }, { "ImportPath": "github.com/hashicorp/hil", - "Rev": "1586b586f59cfa528a751d4a62be88910d34e6e9" + "Rev": "59cce4313fb7be2d9064afbdb3cacd76737cfa3c" }, { "ImportPath": "github.com/hashicorp/hil/ast", - "Rev": "1586b586f59cfa528a751d4a62be88910d34e6e9" + "Rev": "59cce4313fb7be2d9064afbdb3cacd76737cfa3c" }, { "ImportPath": "github.com/hashicorp/logutils", diff --git a/vendor/github.com/hashicorp/hil/appveyor.yml b/vendor/github.com/hashicorp/hil/appveyor.yml new file mode 100644 index 0000000000..feaf7a34e2 --- /dev/null +++ b/vendor/github.com/hashicorp/hil/appveyor.yml @@ -0,0 +1,18 @@ +version: "build-{branch}-{build}" +image: Visual Studio 2015 +clone_folder: c:\gopath\src\github.com\hashicorp\hil +environment: + GOPATH: c:\gopath +init: + - git config --global core.autocrlf true +install: +- cmd: >- + echo %Path% + + go version + + go env + + go get -d -v -t ./... +build_script: +- cmd: go test -v ./... diff --git a/vendor/github.com/hashicorp/hil/ast/ast.go b/vendor/github.com/hashicorp/hil/ast/ast.go index f1a88d58c7..57030e812d 100644 --- a/vendor/github.com/hashicorp/hil/ast/ast.go +++ b/vendor/github.com/hashicorp/hil/ast/ast.go @@ -53,4 +53,5 @@ const ( TypeInt TypeFloat TypeList + TypeMap ) diff --git a/vendor/github.com/hashicorp/hil/ast/index.go b/vendor/github.com/hashicorp/hil/ast/index.go index 4d33135109..49a3b9c305 100644 --- a/vendor/github.com/hashicorp/hil/ast/index.go +++ b/vendor/github.com/hashicorp/hil/ast/index.go @@ -34,33 +34,39 @@ func (n *Index) Type(s Scope) (Type, error) { if !ok { return TypeInvalid, fmt.Errorf("unknown variable accessed: %s", variableAccess.Name) } - if variable.Type != TypeList { + + switch variable.Type { + case TypeList: + return n.typeList(variable, variableAccess.Name) + case TypeMap: + return n.typeMap(variable, variableAccess.Name) + default: return TypeInvalid, fmt.Errorf("invalid index operation into non-indexable type: %s", variable.Type) } +} +func (n *Index) typeList(variable Variable, variableName string) (Type, error) { + // We assume type checking has already determined that this is a list list := variable.Value.([]Variable) - // Ensure that the types of the list elements are homogenous - listTypes := make(map[Type]struct{}) - for _, v := range list { - if _, ok := listTypes[v.Type]; ok { - continue - } - listTypes[v.Type] = struct{}{} - } + return VariableListElementTypesAreHomogenous(variableName, list) +} - if len(listTypes) != 1 { - typesFound := make([]string, len(listTypes)) - i := 0 - for k, _ := range listTypes { - typesFound[0] = k.String() - i++ - } - types := strings.Join(typesFound, ", ") - return TypeInvalid, fmt.Errorf("list %q does not have homogenous types. found %s", variableAccess.Name, types) - } +func (n *Index) typeMap(variable Variable, variableName string) (Type, error) { + // We assume type checking has already determined that this is a map + vmap := variable.Value.(map[string]Variable) - return list[0].Type, nil + return VariableMapValueTypesAreHomogenous(variableName, vmap) +} + +func reportTypes(typesFound map[Type]struct{}) string { + stringTypes := make([]string, len(typesFound)) + i := 0 + for k, _ := range typesFound { + stringTypes[0] = k.String() + i++ + } + return strings.Join(stringTypes, ", ") } func (n *Index) GoString() string { diff --git a/vendor/github.com/hashicorp/hil/ast/variables_helper.go b/vendor/github.com/hashicorp/hil/ast/variables_helper.go new file mode 100644 index 0000000000..4b32841987 --- /dev/null +++ b/vendor/github.com/hashicorp/hil/ast/variables_helper.go @@ -0,0 +1,45 @@ +package ast + +import "fmt" + +func VariableListElementTypesAreHomogenous(variableName string, list []Variable) (Type, error) { + listTypes := make(map[Type]struct{}) + for _, v := range list { + if _, ok := listTypes[v.Type]; ok { + continue + } + listTypes[v.Type] = struct{}{} + } + + if len(listTypes) != 1 && len(list) != 0 { + return TypeInvalid, fmt.Errorf("list %q does not have homogenous types. found %s", variableName, reportTypes(listTypes)) + } + + if len(list) > 0 { + return list[0].Type, nil + } + + return TypeInvalid, fmt.Errorf("list %q does not have any elements so cannot determine type.", variableName) +} + +func VariableMapValueTypesAreHomogenous(variableName string, vmap map[string]Variable) (Type, error) { + valueTypes := make(map[Type]struct{}) + for _, v := range vmap { + if _, ok := valueTypes[v.Type]; ok { + continue + } + valueTypes[v.Type] = struct{}{} + } + + if len(valueTypes) != 1 && len(vmap) != 0 { + return TypeInvalid, fmt.Errorf("map %q does not have homogenous value types. found %s", variableName, reportTypes(valueTypes)) + } + + // For loop here is an easy way to get a single key, we return immediately. + for _, v := range vmap { + return v.Type, nil + } + + // This means the map is empty + return TypeInvalid, fmt.Errorf("map %q does not have any elements so cannot determine type.", variableName) +} diff --git a/vendor/github.com/hashicorp/hil/check_types.go b/vendor/github.com/hashicorp/hil/check_types.go index 3d157c597d..b5a88eefeb 100644 --- a/vendor/github.com/hashicorp/hil/check_types.go +++ b/vendor/github.com/hashicorp/hil/check_types.go @@ -241,7 +241,13 @@ func (tc *typeCheckConcat) TypeCheck(v *TypeCheck) (ast.Node, error) { types[len(n.Exprs)-1-i] = v.StackPop() } - // All concat args must be strings, so validate that + // If there is only one argument and it is a list, we evaluate to a list + if len(types) == 1 && types[0] == ast.TypeList { + v.StackPush(ast.TypeList) + return n, nil + } + + // Otherwise, all concat args must be strings, so validate that for i, t := range types { if t != ast.TypeString { cn := v.ImplicitConversion(t, ast.TypeString, n.Exprs[i]) @@ -251,7 +257,7 @@ func (tc *typeCheckConcat) TypeCheck(v *TypeCheck) (ast.Node, error) { } return nil, fmt.Errorf( - "output of an HIL expression must be a string (argument %d is %s)", i+1, t) + "output of an HIL expression must be a string, or a single list (argument %d is %s)", i+1, t) } } @@ -293,15 +299,6 @@ type typeCheckIndex struct { } func (tc *typeCheckIndex) TypeCheck(v *TypeCheck) (ast.Node, error) { - - value, err := tc.n.Key.Type(v.Scope) - if err != nil { - return nil, err - } - if value != ast.TypeInt { - return nil, fmt.Errorf("key of an index must be an int, was %s", value) - } - // Ensure we have a VariableAccess as the target varAccessNode, ok := tc.n.Target.(*ast.VariableAccess) if !ok { @@ -313,28 +310,40 @@ func (tc *typeCheckIndex) TypeCheck(v *TypeCheck) (ast.Node, error) { if !ok { return nil, fmt.Errorf("unknown variable accessed: %s", varAccessNode.Name) } - if variable.Type != ast.TypeList { + + keyType, err := tc.n.Key.Type(v.Scope) + if err != nil { + return nil, err + } + + switch variable.Type { + case ast.TypeList: + if keyType != ast.TypeInt { + return nil, fmt.Errorf("key of an index must be an int, was %s", keyType) + } + + valType, err := ast.VariableListElementTypesAreHomogenous(varAccessNode.Name, variable.Value.([]ast.Variable)) + if err != nil { + return tc.n, err + } + + v.StackPush(valType) + return tc.n, nil + case ast.TypeMap: + if keyType != ast.TypeString { + return nil, fmt.Errorf("key of an index must be a string, was %s", keyType) + } + + valType, err := ast.VariableMapValueTypesAreHomogenous(varAccessNode.Name, variable.Value.(map[string]ast.Variable)) + if err != nil { + return tc.n, err + } + + v.StackPush(valType) + return tc.n, nil + default: return nil, fmt.Errorf("invalid index operation into non-indexable type: %s", variable.Type) } - - list := variable.Value.([]ast.Variable) - - // Ensure that the types of the list elements are homogenous - listTypes := make(map[ast.Type]struct{}) - for _, v := range list { - if _, ok := listTypes[v.Type]; ok { - continue - } - listTypes[v.Type] = struct{}{} - } - - if len(listTypes) != 1 { - return nil, fmt.Errorf("list %q does not have homogenous types (%s)", varAccessNode.Name) - } - - // This is the type since the list is homogenous in type - v.StackPush(list[0].Type) - return tc.n, nil } func (v *TypeCheck) ImplicitConversion( diff --git a/vendor/github.com/hashicorp/hil/eval.go b/vendor/github.com/hashicorp/hil/eval.go index dd948d72a1..51c8aa7123 100644 --- a/vendor/github.com/hashicorp/hil/eval.go +++ b/vendor/github.com/hashicorp/hil/eval.go @@ -200,16 +200,35 @@ func (v *evalIndex) Eval(scope ast.Scope, stack *ast.Stack) (interface{}, ast.Ty if err != nil { return nil, ast.TypeInvalid, err } + key, keyType, err := evalKey.Eval(scope, stack) - - // Last sanity check - if targetType != ast.TypeList { - return nil, ast.TypeInvalid, fmt.Errorf("target for indexing must be ast.TypeList, is %s", targetType) - } - if keyType != ast.TypeInt { - return nil, ast.TypeInvalid, fmt.Errorf("key for indexing must be ast.TypeInt, is %s", keyType) + if err != nil { + return nil, ast.TypeInvalid, err } + variableName := v.Index.Target.(*ast.VariableAccess).Name + + switch targetType { + case ast.TypeList: + if keyType != ast.TypeInt { + return nil, ast.TypeInvalid, fmt.Errorf("key for indexing list %q must be an int, is %s", variableName, keyType) + } + + return v.evalListIndex(variableName, target, key) + case ast.TypeMap: + if keyType != ast.TypeString { + return nil, ast.TypeInvalid, fmt.Errorf("key for indexing map %q must be a string, is %s", variableName, keyType) + } + + return v.evalMapIndex(variableName, target, key) + default: + return nil, ast.TypeInvalid, fmt.Errorf("target %q for indexing must be ast.TypeList or ast.TypeMap, is %s", variableName, targetType) + } +} + +func (v *evalIndex) evalListIndex(variableName string, target interface{}, key interface{}) (interface{}, ast.Type, error) { + // We assume type checking was already done and we can assume that target + // is a list and key is an int list, ok := target.([]ast.Variable) if !ok { return nil, ast.TypeInvalid, fmt.Errorf("cannot cast target to []Variable") @@ -225,7 +244,7 @@ func (v *evalIndex) Eval(scope ast.Scope, stack *ast.Stack) (interface{}, ast.Ty } if keyInt < 0 || len(list) < keyInt+1 { - return nil, ast.TypeInvalid, fmt.Errorf("index %d out of range (max %d)", keyInt, len(list)) + return nil, ast.TypeInvalid, fmt.Errorf("index %d out of range for list %s (max %d)", keyInt, variableName, len(list)) } returnVal := list[keyInt].Value @@ -234,6 +253,31 @@ func (v *evalIndex) Eval(scope ast.Scope, stack *ast.Stack) (interface{}, ast.Ty return returnVal, returnType, nil } +func (v *evalIndex) evalMapIndex(variableName string, target interface{}, key interface{}) (interface{}, ast.Type, error) { + // We assume type checking was already done and we can assume that target + // is a map and key is a string + vmap, ok := target.(map[string]ast.Variable) + if !ok { + return nil, ast.TypeInvalid, fmt.Errorf("cannot cast target to map[string]Variable") + } + + keyString, ok := key.(string) + if !ok { + return nil, ast.TypeInvalid, fmt.Errorf("cannot cast key to string") + } + + if len(vmap) == 0 { + return nil, ast.TypeInvalid, fmt.Errorf("map is empty") + } + + value, ok := vmap[keyString] + if !ok { + return nil, ast.TypeInvalid, fmt.Errorf("key %q does not exist in map %s", keyString, variableName) + } + + return value.Value, value.Type, nil +} + type evalConcat struct{ *ast.Concat } func (v *evalConcat) Eval(s ast.Scope, stack *ast.Stack) (interface{}, ast.Type, error) { @@ -244,6 +288,12 @@ func (v *evalConcat) Eval(s ast.Scope, stack *ast.Stack) (interface{}, ast.Type, nodes = append(nodes, stack.Pop().(*ast.LiteralNode)) } + // Special case the single list + if len(nodes) == 1 && nodes[0].Typex == ast.TypeList { + return nodes[0].Value, ast.TypeList, nil + } + + // Otherwise concatenate the strings var buf bytes.Buffer for i := len(nodes) - 1; i >= 0; i-- { buf.WriteString(nodes[i].Value.(string)) diff --git a/vendor/github.com/hashicorp/hil/y.go b/vendor/github.com/hashicorp/hil/y.go index bf4ca1bc3d..cf9887cf3c 100644 --- a/vendor/github.com/hashicorp/hil/y.go +++ b/vendor/github.com/hashicorp/hil/y.go @@ -55,7 +55,7 @@ var parserStatenames = [...]string{} const parserEofCode = 1 const parserErrCode = 2 -const parserMaxDepth = 200 +const parserInitialStackSize = 16 //line lang.y:196 @@ -157,18 +157,17 @@ type parserParser interface { } type parserParserImpl struct { - lookahead func() int + lval parserSymType + stack [parserInitialStackSize]parserSymType + char int } func (p *parserParserImpl) Lookahead() int { - return p.lookahead() + return p.char } func parserNewParser() parserParser { - p := &parserParserImpl{ - lookahead: func() int { return -1 }, - } - return p + return &parserParserImpl{} } const parserFlag = -1000 @@ -296,22 +295,20 @@ func parserParse(parserlex parserLexer) int { func (parserrcvr *parserParserImpl) Parse(parserlex parserLexer) int { var parsern int - var parserlval parserSymType var parserVAL parserSymType var parserDollar []parserSymType _ = parserDollar // silence set and not used - parserS := make([]parserSymType, parserMaxDepth) + parserS := parserrcvr.stack[:] Nerrs := 0 /* number of errors */ Errflag := 0 /* error recovery flag */ parserstate := 0 - parserchar := -1 - parsertoken := -1 // parserchar translated into internal numbering - parserrcvr.lookahead = func() int { return parserchar } + parserrcvr.char = -1 + parsertoken := -1 // parserrcvr.char translated into internal numbering defer func() { // Make sure we report no lookahead when not parsing. parserstate = -1 - parserchar = -1 + parserrcvr.char = -1 parsertoken = -1 }() parserp := -1 @@ -343,8 +340,8 @@ parsernewstate: if parsern <= parserFlag { goto parserdefault /* simple state */ } - if parserchar < 0 { - parserchar, parsertoken = parserlex1(parserlex, &parserlval) + if parserrcvr.char < 0 { + parserrcvr.char, parsertoken = parserlex1(parserlex, &parserrcvr.lval) } parsern += parsertoken if parsern < 0 || parsern >= parserLast { @@ -352,9 +349,9 @@ parsernewstate: } parsern = parserAct[parsern] if parserChk[parsern] == parsertoken { /* valid shift */ - parserchar = -1 + parserrcvr.char = -1 parsertoken = -1 - parserVAL = parserlval + parserVAL = parserrcvr.lval parserstate = parsern if Errflag > 0 { Errflag-- @@ -366,8 +363,8 @@ parserdefault: /* default state action */ parsern = parserDef[parserstate] if parsern == -2 { - if parserchar < 0 { - parserchar, parsertoken = parserlex1(parserlex, &parserlval) + if parserrcvr.char < 0 { + parserrcvr.char, parsertoken = parserlex1(parserlex, &parserrcvr.lval) } /* look through exception table */ @@ -430,7 +427,7 @@ parserdefault: if parsertoken == parserEofCode { goto ret1 } - parserchar = -1 + parserrcvr.char = -1 parsertoken = -1 goto parsernewstate /* try again in the same state */ }