Merge pull request #10591 from hashicorp/b-update-hil

vendor: update HIL with conditionals
This commit is contained in:
Mitchell Hashimoto 2016-12-07 15:20:34 -08:00 committed by GitHub
commit f7abd6eb1c
12 changed files with 693 additions and 39 deletions

View File

@ -5,9 +5,20 @@ type ArithmeticOp int
const (
ArithmeticOpInvalid ArithmeticOp = 0
ArithmeticOpAdd ArithmeticOp = iota
ArithmeticOpAdd ArithmeticOp = iota
ArithmeticOpSub
ArithmeticOpMul
ArithmeticOpDiv
ArithmeticOpMod
ArithmeticOpLogicalAnd
ArithmeticOpLogicalOr
ArithmeticOpEqual
ArithmeticOpNotEqual
ArithmeticOpLessThan
ArithmeticOpLessThanOrEqual
ArithmeticOpGreaterThan
ArithmeticOpGreaterThanOrEqual
)

36
vendor/github.com/hashicorp/hil/ast/conditional.go generated vendored Normal file
View File

@ -0,0 +1,36 @@
package ast
import (
"fmt"
)
type Conditional struct {
CondExpr Node
TrueExpr Node
FalseExpr Node
Posx Pos
}
// Accept passes the given visitor to the child nodes in this order:
// CondExpr, TrueExpr, FalseExpr. It then finally passes itself to the visitor.
func (n *Conditional) Accept(v Visitor) Node {
n.CondExpr = n.CondExpr.Accept(v)
n.TrueExpr = n.TrueExpr.Accept(v)
n.FalseExpr = n.FalseExpr.Accept(v)
return v(n)
}
func (n *Conditional) Pos() Pos {
return n.Posx
}
func (n *Conditional) Type(Scope) (Type, error) {
// This is not actually a useful value; the type checker ignores
// this function when analyzing conditionals, just as with Arithmetic.
return TypeInt, nil
}
func (n *Conditional) GoString() string {
return fmt.Sprintf("*%#v", *n)
}

View File

@ -2,6 +2,7 @@ package ast
import (
"fmt"
"reflect"
)
// LiteralNode represents a single literal value, such as "foo" or
@ -12,6 +13,51 @@ type LiteralNode struct {
Posx Pos
}
// NewLiteralNode returns a new literal node representing the given
// literal Go value, which must correspond to one of the primitive types
// supported by HIL. Lists and maps cannot currently be constructed via
// this function.
//
// If an inappropriately-typed value is provided, this function will
// return an error. The main intended use of this function is to produce
// "synthetic" literals from constants in code, where the value type is
// well known at compile time. To easily store these in global variables,
// see also MustNewLiteralNode.
func NewLiteralNode(value interface{}, pos Pos) (*LiteralNode, error) {
goType := reflect.TypeOf(value)
var hilType Type
switch goType.Kind() {
case reflect.Bool:
hilType = TypeBool
case reflect.Int:
hilType = TypeInt
case reflect.Float64:
hilType = TypeFloat
case reflect.String:
hilType = TypeString
default:
return nil, fmt.Errorf("unsupported literal node type: %T", value)
}
return &LiteralNode{
Value: value,
Typex: hilType,
Posx: pos,
}, nil
}
// MustNewLiteralNode wraps NewLiteralNode and panics if an error is
// returned, thus allowing valid literal nodes to be easily assigned to
// global variables.
func MustNewLiteralNode(value interface{}, pos Pos) *LiteralNode {
node, err := NewLiteralNode(value, pos)
if err != nil {
panic(err)
}
return node
}
func (n *LiteralNode) Accept(v Visitor) Node {
return v(n)
}

View File

@ -30,6 +30,11 @@ func registerBuiltins(scope *ast.BasicScope) *ast.BasicScope {
// Math operations
scope.FuncMap["__builtin_IntMath"] = builtinIntMath()
scope.FuncMap["__builtin_FloatMath"] = builtinFloatMath()
scope.FuncMap["__builtin_BoolCompare"] = builtinBoolCompare()
scope.FuncMap["__builtin_FloatCompare"] = builtinFloatCompare()
scope.FuncMap["__builtin_IntCompare"] = builtinIntCompare()
scope.FuncMap["__builtin_StringCompare"] = builtinStringCompare()
scope.FuncMap["__builtin_Logical"] = builtinLogical()
return scope
}
@ -99,6 +104,136 @@ func builtinIntMath() ast.Function {
}
}
func builtinBoolCompare() ast.Function {
return ast.Function{
ArgTypes: []ast.Type{ast.TypeInt, ast.TypeBool, ast.TypeBool},
Variadic: false,
ReturnType: ast.TypeBool,
Callback: func(args []interface{}) (interface{}, error) {
op := args[0].(ast.ArithmeticOp)
lhs := args[1].(bool)
rhs := args[2].(bool)
switch op {
case ast.ArithmeticOpEqual:
return lhs == rhs, nil
case ast.ArithmeticOpNotEqual:
return lhs != rhs, nil
default:
return nil, errors.New("invalid comparison operation")
}
},
}
}
func builtinFloatCompare() ast.Function {
return ast.Function{
ArgTypes: []ast.Type{ast.TypeInt, ast.TypeFloat, ast.TypeFloat},
Variadic: false,
ReturnType: ast.TypeBool,
Callback: func(args []interface{}) (interface{}, error) {
op := args[0].(ast.ArithmeticOp)
lhs := args[1].(float64)
rhs := args[2].(float64)
switch op {
case ast.ArithmeticOpEqual:
return lhs == rhs, nil
case ast.ArithmeticOpNotEqual:
return lhs != rhs, nil
case ast.ArithmeticOpLessThan:
return lhs < rhs, nil
case ast.ArithmeticOpLessThanOrEqual:
return lhs <= rhs, nil
case ast.ArithmeticOpGreaterThan:
return lhs > rhs, nil
case ast.ArithmeticOpGreaterThanOrEqual:
return lhs >= rhs, nil
default:
return nil, errors.New("invalid comparison operation")
}
},
}
}
func builtinIntCompare() ast.Function {
return ast.Function{
ArgTypes: []ast.Type{ast.TypeInt, ast.TypeInt, ast.TypeInt},
Variadic: false,
ReturnType: ast.TypeBool,
Callback: func(args []interface{}) (interface{}, error) {
op := args[0].(ast.ArithmeticOp)
lhs := args[1].(int)
rhs := args[2].(int)
switch op {
case ast.ArithmeticOpEqual:
return lhs == rhs, nil
case ast.ArithmeticOpNotEqual:
return lhs != rhs, nil
case ast.ArithmeticOpLessThan:
return lhs < rhs, nil
case ast.ArithmeticOpLessThanOrEqual:
return lhs <= rhs, nil
case ast.ArithmeticOpGreaterThan:
return lhs > rhs, nil
case ast.ArithmeticOpGreaterThanOrEqual:
return lhs >= rhs, nil
default:
return nil, errors.New("invalid comparison operation")
}
},
}
}
func builtinStringCompare() ast.Function {
return ast.Function{
ArgTypes: []ast.Type{ast.TypeInt, ast.TypeString, ast.TypeString},
Variadic: false,
ReturnType: ast.TypeBool,
Callback: func(args []interface{}) (interface{}, error) {
op := args[0].(ast.ArithmeticOp)
lhs := args[1].(string)
rhs := args[2].(string)
switch op {
case ast.ArithmeticOpEqual:
return lhs == rhs, nil
case ast.ArithmeticOpNotEqual:
return lhs != rhs, nil
default:
return nil, errors.New("invalid comparison operation")
}
},
}
}
func builtinLogical() ast.Function {
return ast.Function{
ArgTypes: []ast.Type{ast.TypeInt},
Variadic: true,
VariadicType: ast.TypeBool,
ReturnType: ast.TypeBool,
Callback: func(args []interface{}) (interface{}, error) {
op := args[0].(ast.ArithmeticOp)
result := args[1].(bool)
for _, raw := range args[2:] {
arg := raw.(bool)
switch op {
case ast.ArithmeticOpLogicalOr:
result = result || arg
case ast.ArithmeticOpLogicalAnd:
result = result && arg
default:
return nil, errors.New("invalid logical operator")
}
}
return result, nil
},
}
}
func builtinFloatToInt() ast.Function {
return ast.Function{
ArgTypes: []ast.Type{ast.TypeFloat},

View File

@ -67,6 +67,9 @@ func (v *TypeCheck) visit(raw ast.Node) ast.Node {
case *ast.Call:
tc := &typeCheckCall{n}
result, err = tc.TypeCheck(v)
case *ast.Conditional:
tc := &typeCheckConditional{n}
result, err = tc.TypeCheck(v)
case *ast.Index:
tc := &typeCheckIndex{n}
result, err = tc.TypeCheck(v)
@ -113,6 +116,18 @@ func (tc *typeCheckArithmetic) TypeCheck(v *TypeCheck) (ast.Node, error) {
exprs[len(tc.n.Exprs)-1-i] = v.StackPop()
}
switch tc.n.Op {
case ast.ArithmeticOpLogicalAnd, ast.ArithmeticOpLogicalOr:
return tc.checkLogical(v, exprs)
case ast.ArithmeticOpEqual, ast.ArithmeticOpNotEqual, ast.ArithmeticOpLessThan, ast.ArithmeticOpGreaterThan, ast.ArithmeticOpGreaterThanOrEqual, ast.ArithmeticOpLessThanOrEqual:
return tc.checkComparison(v, exprs)
default:
return tc.checkNumeric(v, exprs)
}
}
func (tc *typeCheckArithmetic) checkNumeric(v *TypeCheck, exprs []ast.Type) (ast.Node, error) {
// Determine the resulting type we want. We do this by going over
// every expression until we find one with a type we recognize.
// We do this because the first expr might be a string ("var.foo")
@ -177,6 +192,116 @@ func (tc *typeCheckArithmetic) TypeCheck(v *TypeCheck) (ast.Node, error) {
}, nil
}
func (tc *typeCheckArithmetic) checkComparison(v *TypeCheck, exprs []ast.Type) (ast.Node, error) {
if len(exprs) != 2 {
// This should never happen, because the parser never produces
// nodes that violate this.
return nil, fmt.Errorf(
"comparison operators must have exactly two operands",
)
}
// The first operand always dictates the type for a comparison.
compareFunc := ""
compareType := exprs[0]
switch compareType {
case ast.TypeBool:
compareFunc = "__builtin_BoolCompare"
case ast.TypeFloat:
compareFunc = "__builtin_FloatCompare"
case ast.TypeInt:
compareFunc = "__builtin_IntCompare"
case ast.TypeString:
compareFunc = "__builtin_StringCompare"
default:
return nil, fmt.Errorf(
"comparison operators apply only to bool, float, int, and string",
)
}
// Verify (and possibly, convert) the args
for i, arg := range exprs {
if arg != compareType {
cn := v.ImplicitConversion(exprs[i], compareType, tc.n.Exprs[i])
if cn != nil {
tc.n.Exprs[i] = cn
continue
}
return nil, fmt.Errorf(
"operand %d should be %s, got %s",
i+1, compareType, arg,
)
}
}
// Only ints and floats can have the <, >, <= and >= operators applied
switch tc.n.Op {
case ast.ArithmeticOpEqual, ast.ArithmeticOpNotEqual:
// anything goes
default:
switch compareType {
case ast.TypeFloat, ast.TypeInt:
// fine
default:
return nil, fmt.Errorf(
"<, >, <= and >= may apply only to int and float values",
)
}
}
// Comparison operators always return bool
v.StackPush(ast.TypeBool)
// Replace our node with a call to the proper function. This isn't
// type checked but we already verified types.
args := make([]ast.Node, len(tc.n.Exprs)+1)
args[0] = &ast.LiteralNode{
Value: tc.n.Op,
Typex: ast.TypeInt,
Posx: tc.n.Pos(),
}
copy(args[1:], tc.n.Exprs)
return &ast.Call{
Func: compareFunc,
Args: args,
Posx: tc.n.Pos(),
}, nil
}
func (tc *typeCheckArithmetic) checkLogical(v *TypeCheck, exprs []ast.Type) (ast.Node, error) {
for i, t := range exprs {
if t != ast.TypeBool {
cn := v.ImplicitConversion(t, ast.TypeBool, tc.n.Exprs[i])
if cn == nil {
return nil, fmt.Errorf(
"logical operators require boolean operands, not %s",
t,
)
}
tc.n.Exprs[i] = cn
}
}
// Return type is always boolean
v.StackPush(ast.TypeBool)
// Arithmetic nodes are replaced with a call to a built-in function
args := make([]ast.Node, len(tc.n.Exprs)+1)
args[0] = &ast.LiteralNode{
Value: tc.n.Op,
Typex: ast.TypeInt,
Posx: tc.n.Pos(),
}
copy(args[1:], tc.n.Exprs)
return &ast.Call{
Func: "__builtin_Logical",
Args: args,
Posx: tc.n.Pos(),
}, nil
}
type typeCheckCall struct {
n *ast.Call
}
@ -240,6 +365,79 @@ func (tc *typeCheckCall) TypeCheck(v *TypeCheck) (ast.Node, error) {
return tc.n, nil
}
type typeCheckConditional struct {
n *ast.Conditional
}
func (tc *typeCheckConditional) TypeCheck(v *TypeCheck) (ast.Node, error) {
// On the stack we have the types of the condition, true and false
// expressions, but they are in reverse order.
falseType := v.StackPop()
trueType := v.StackPop()
condType := v.StackPop()
if condType != ast.TypeBool {
cn := v.ImplicitConversion(condType, ast.TypeBool, tc.n.CondExpr)
if cn == nil {
return nil, fmt.Errorf(
"condition must be type bool, not %s", condType.Printable(),
)
}
tc.n.CondExpr = cn
}
// The types of the true and false expression must match
if trueType != falseType {
// Since passing around stringified versions of other types is
// common, we pragmatically allow the false expression to dictate
// the result type when the true expression is a string.
if trueType == ast.TypeString {
cn := v.ImplicitConversion(trueType, falseType, tc.n.TrueExpr)
if cn == nil {
return nil, fmt.Errorf(
"true and false expression types must match; have %s and %s",
trueType.Printable(), falseType.Printable(),
)
}
tc.n.TrueExpr = cn
trueType = falseType
} else {
cn := v.ImplicitConversion(falseType, trueType, tc.n.FalseExpr)
if cn == nil {
return nil, fmt.Errorf(
"true and false expression types must match; have %s and %s",
trueType.Printable(), falseType.Printable(),
)
}
tc.n.FalseExpr = cn
falseType = trueType
}
}
// Currently list and map types cannot be used, because we cannot
// generally assert that their element types are consistent.
// Such support might be added later, either by improving the type
// system or restricting usage to only variable and literal expressions,
// but for now this is simply prohibited because it doesn't seem to
// be a common enough case to be worth the complexity.
switch trueType {
case ast.TypeList:
return nil, fmt.Errorf(
"conditional operator cannot be used with list values",
)
case ast.TypeMap:
return nil, fmt.Errorf(
"conditional operator cannot be used with map values",
)
}
// Result type (guaranteed to also match falseType due to the above)
v.StackPush(trueType)
return tc.n, nil
}
type typeCheckOutput struct {
n *ast.Output
}

View File

@ -232,6 +232,8 @@ func evalNode(raw ast.Node) (EvalNode, error) {
return &evalIndex{n}, nil
case *ast.Call:
return &evalCall{n}, nil
case *ast.Conditional:
return &evalConditional{n}, nil
case *ast.Output:
return &evalOutput{n}, nil
case *ast.LiteralNode:
@ -274,6 +276,23 @@ func (v *evalCall) Eval(s ast.Scope, stack *ast.Stack) (interface{}, ast.Type, e
return result, function.ReturnType, nil
}
type evalConditional struct{ *ast.Conditional }
func (v *evalConditional) Eval(s ast.Scope, stack *ast.Stack) (interface{}, ast.Type, error) {
// On the stack we have literal nodes representing the resulting values
// of the condition, true and false expressions, but they are in reverse
// order.
falseLit := stack.Pop().(*ast.LiteralNode)
trueLit := stack.Pop().(*ast.LiteralNode)
condLit := stack.Pop().(*ast.LiteralNode)
if condLit.Value.(bool) {
return trueLit.Value, trueLit.Typex, nil
} else {
return falseLit.Value, trueLit.Typex, nil
}
}
type evalIndex struct{ *ast.Index }
func (v *evalIndex) Eval(scope ast.Scope, stack *ast.Stack) (interface{}, ast.Type, error) {

View File

@ -16,6 +16,22 @@ func init() {
// the *lowest* precedence first. Operators within the same group
// have left-to-right associativity.
binaryOps = []map[scanner.TokenType]ast.ArithmeticOp{
{
scanner.OR: ast.ArithmeticOpLogicalOr,
},
{
scanner.AND: ast.ArithmeticOpLogicalAnd,
},
{
scanner.EQUAL: ast.ArithmeticOpEqual,
scanner.NOTEQUAL: ast.ArithmeticOpNotEqual,
},
{
scanner.GT: ast.ArithmeticOpGreaterThan,
scanner.GTE: ast.ArithmeticOpGreaterThanOrEqual,
scanner.LT: ast.ArithmeticOpLessThan,
scanner.LTE: ast.ArithmeticOpLessThanOrEqual,
},
{
scanner.PLUS: ast.ArithmeticOpAdd,
scanner.MINUS: ast.ArithmeticOpSub,

View File

@ -191,7 +191,56 @@ func (p *parser) ParseInterpolation() (ast.Node, error) {
}
func (p *parser) ParseExpression() (ast.Node, error) {
return p.parseBinaryOps(binaryOps)
return p.parseTernaryCond()
}
func (p *parser) parseTernaryCond() (ast.Node, error) {
// The ternary condition operator (.. ? .. : ..) behaves somewhat
// like a binary operator except that the "operator" is itself
// an expression enclosed in two punctuation characters.
// The middle expression is parsed as if the ? and : symbols
// were parentheses. The "rhs" (the "false expression") is then
// treated right-associatively so it behaves similarly to the
// middle in terms of precedence.
startPos := p.peeker.Peek().Pos
var cond, trueExpr, falseExpr ast.Node
var err error
cond, err = p.parseBinaryOps(binaryOps)
if err != nil {
return nil, err
}
next := p.peeker.Peek()
if next.Type != scanner.QUESTION {
return cond, nil
}
p.peeker.Read() // eat question mark
trueExpr, err = p.ParseExpression()
if err != nil {
return nil, err
}
colon := p.peeker.Read()
if colon.Type != scanner.COLON {
return nil, ExpectationError(":", colon)
}
falseExpr, err = p.ParseExpression()
if err != nil {
return nil, err
}
return &ast.Conditional{
CondExpr: cond,
TrueExpr: trueExpr,
FalseExpr: falseExpr,
Posx: startPos,
}, nil
}
// parseBinaryOps calls itself recursively to work through all of the
@ -348,6 +397,30 @@ func (p *parser) ParseExpressionTerm() (ast.Node, error) {
Posx: opTok.Pos,
}, nil
case scanner.BANG:
opTok := p.peeker.Read()
// important to use ParseExpressionTerm rather than ParseExpression
// here, otherwise we can capture a following binary expression into
// our negation.
operand, err := p.ParseExpressionTerm()
if err != nil {
return nil, err
}
// The AST currently represents binary negation as an equality
// test with "false".
return &ast.Arithmetic{
Op: ast.ArithmeticOpEqual,
Exprs: []ast.Node{
&ast.LiteralNode{
Value: false,
Typex: ast.TypeBool,
Posx: opTok.Pos,
},
operand,
},
Posx: opTok.Pos,
}, nil
case scanner.IDENTIFIER:
return p.ParseScopeInteraction()

View File

@ -168,7 +168,7 @@ func scanInterpolationToken(s string, startPos ast.Pos) (*Token, int, ast.Pos) {
var token *Token
switch next {
case '(', ')', '[', ']', ',', '.', '+', '-', '*', '/', '%':
case '(', ')', '[', ']', ',', '.', '+', '-', '*', '/', '%', '?', ':':
// Easy punctuation symbols that don't have any special meaning
// during scanning, and that stand for themselves in the
// TokenType enumeration.
@ -189,6 +189,91 @@ func scanInterpolationToken(s string, startPos ast.Pos) (*Token, int, ast.Pos) {
Content: s[:1],
Pos: pos,
}
case '!':
if len(s) >= 2 && s[:2] == "!=" {
token = &Token{
Type: NOTEQUAL,
Content: s[:2],
Pos: pos,
}
} else {
token = &Token{
Type: BANG,
Content: s[:1],
Pos: pos,
}
}
case '<':
if len(s) >= 2 && s[:2] == "<=" {
token = &Token{
Type: LTE,
Content: s[:2],
Pos: pos,
}
} else {
token = &Token{
Type: LT,
Content: s[:1],
Pos: pos,
}
}
case '>':
if len(s) >= 2 && s[:2] == ">=" {
token = &Token{
Type: GTE,
Content: s[:2],
Pos: pos,
}
} else {
token = &Token{
Type: GT,
Content: s[:1],
Pos: pos,
}
}
case '=':
if len(s) >= 2 && s[:2] == "==" {
token = &Token{
Type: EQUAL,
Content: s[:2],
Pos: pos,
}
} else {
// A single equals is not a valid operator
token = &Token{
Type: INVALID,
Content: s[:1],
Pos: pos,
}
}
case '&':
if len(s) >= 2 && s[:2] == "&&" {
token = &Token{
Type: AND,
Content: s[:2],
Pos: pos,
}
} else {
token = &Token{
Type: INVALID,
Content: s[:1],
Pos: pos,
}
}
case '|':
if len(s) >= 2 && s[:2] == "||" {
token = &Token{
Type: OR,
Content: s[:2],
Pos: pos,
}
} else {
token = &Token{
Type: INVALID,
Content: s[:1],
Pos: pos,
}
}
default:
if next >= '0' && next <= '9' {
num, numType := scanNumber(s)

View File

@ -48,6 +48,20 @@ const (
SLASH TokenType = '/'
PERCENT TokenType = '%'
AND TokenType = '∧'
OR TokenType = ''
BANG TokenType = '!'
EQUAL TokenType = '='
NOTEQUAL TokenType = '≠'
GT TokenType = '>'
LT TokenType = '<'
GTE TokenType = '≥'
LTE TokenType = '≤'
QUESTION TokenType = '?'
COLON TokenType = ':'
EOF TokenType = '␄'
// Produced for sequences that cannot be understood as valid tokens
@ -73,6 +87,16 @@ func (t *Token) String() string {
return fmt.Sprintf("opening quote")
case CQUOTE:
return fmt.Sprintf("closing quote")
case AND:
return "&&"
case OR:
return "||"
case NOTEQUAL:
return "!="
case GTE:
return ">="
case LTE:
return "<="
default:
// The remaining token types have content that
// speaks for itself.

View File

@ -4,32 +4,43 @@ package scanner
import "fmt"
const _TokenType_name = "BEGINPERCENTOPARENCPARENSTARPLUSCOMMAMINUSPERIODSLASHBOOLFLOATINTEGERSTRINGOBRACKETCBRACKETIDENTIFIERLITERALENDOQUOTECQUOTEEOFINVALID"
const _TokenType_name = "BANGBEGINPERCENTOPARENCPARENSTARPLUSCOMMAMINUSPERIODSLASHCOLONLTEQUALGTQUESTIONBOOLFLOATINTEGERSTRINGOBRACKETCBRACKETIDENTIFIERLITERALENDOQUOTECQUOTEANDORNOTEQUALLTEGTEEOFINVALID"
var _TokenType_map = map[TokenType]string{
36: _TokenType_name[0:5],
37: _TokenType_name[5:12],
40: _TokenType_name[12:18],
41: _TokenType_name[18:24],
42: _TokenType_name[24:28],
43: _TokenType_name[28:32],
44: _TokenType_name[32:37],
45: _TokenType_name[37:42],
46: _TokenType_name[42:48],
47: _TokenType_name[48:53],
66: _TokenType_name[53:57],
70: _TokenType_name[57:62],
73: _TokenType_name[62:69],
83: _TokenType_name[69:75],
91: _TokenType_name[75:83],
93: _TokenType_name[83:91],
105: _TokenType_name[91:101],
111: _TokenType_name[101:108],
125: _TokenType_name[108:111],
8220: _TokenType_name[111:117],
8221: _TokenType_name[117:123],
9220: _TokenType_name[123:126],
65533: _TokenType_name[126:133],
33: _TokenType_name[0:4],
36: _TokenType_name[4:9],
37: _TokenType_name[9:16],
40: _TokenType_name[16:22],
41: _TokenType_name[22:28],
42: _TokenType_name[28:32],
43: _TokenType_name[32:36],
44: _TokenType_name[36:41],
45: _TokenType_name[41:46],
46: _TokenType_name[46:52],
47: _TokenType_name[52:57],
58: _TokenType_name[57:62],
60: _TokenType_name[62:64],
61: _TokenType_name[64:69],
62: _TokenType_name[69:71],
63: _TokenType_name[71:79],
66: _TokenType_name[79:83],
70: _TokenType_name[83:88],
73: _TokenType_name[88:95],
83: _TokenType_name[95:101],
91: _TokenType_name[101:109],
93: _TokenType_name[109:117],
105: _TokenType_name[117:127],
111: _TokenType_name[127:134],
125: _TokenType_name[134:137],
8220: _TokenType_name[137:143],
8221: _TokenType_name[143:149],
8743: _TokenType_name[149:152],
8744: _TokenType_name[152:154],
8800: _TokenType_name[154:162],
8804: _TokenType_name[162:165],
8805: _TokenType_name[165:168],
9220: _TokenType_name[168:171],
65533: _TokenType_name[171:178],
}
func (i TokenType) String() string {

24
vendor/vendor.json vendored
View File

@ -1586,28 +1586,28 @@
"revisionTime": "2016-11-30T20:58:18Z"
},
{
"checksumSHA1": "/TJCBetWCMVsOpehJzVk3S/xtWM=",
"checksumSHA1": "xONRNgLDc5OqCUmyDN3iBRKmKB0=",
"path": "github.com/hashicorp/hil",
"revision": "76d6c606283f17780baaad00df4b6ce8e9fca941",
"revisionTime": "2016-11-20T06:09:40Z"
"revision": "bf046eec69cc383b7f32c47990336409601c8116",
"revisionTime": "2016-12-04T02:32:26Z"
},
{
"checksumSHA1": "YPJwewz3dAqEWOGP2qIIWeCufF0=",
"checksumSHA1": "oZ2a2x9qyHqvqJdv/Du3LGeaFdA=",
"path": "github.com/hashicorp/hil/ast",
"revision": "76d6c606283f17780baaad00df4b6ce8e9fca941",
"revisionTime": "2016-11-20T06:09:40Z"
"revision": "bf046eec69cc383b7f32c47990336409601c8116",
"revisionTime": "2016-12-04T02:32:26Z"
},
{
"checksumSHA1": "+mEEIN7pTcda+Vu837rQBkHYzao=",
"checksumSHA1": "p/zZysJW/AaPXXPCI20nM2arPnw=",
"path": "github.com/hashicorp/hil/parser",
"revision": "76d6c606283f17780baaad00df4b6ce8e9fca941",
"revisionTime": "2016-11-20T06:09:40Z"
"revision": "bf046eec69cc383b7f32c47990336409601c8116",
"revisionTime": "2016-12-04T02:32:26Z"
},
{
"checksumSHA1": "2aIAMbqPrE0qyYoJSL6qjVm+Tt0=",
"checksumSHA1": "FlzgVCYqnODad4pKujXhSaGcrIo=",
"path": "github.com/hashicorp/hil/scanner",
"revision": "76d6c606283f17780baaad00df4b6ce8e9fca941",
"revisionTime": "2016-11-20T06:09:40Z"
"revision": "bf046eec69cc383b7f32c47990336409601c8116",
"revisionTime": "2016-12-04T02:32:26Z"
},
{
"path": "github.com/hashicorp/logutils",