diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index ab45f39b8..6b5158124 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -666,11 +666,11 @@ }, { "ImportPath": "github.com/hashicorp/hil", - "Rev": "42518c6f01625b5e6948a6a0e6a0792df126c548" + "Rev": "0457360d54ca4d081a769eaa1617e0462153fd70" }, { "ImportPath": "github.com/hashicorp/hil/ast", - "Rev": "42518c6f01625b5e6948a6a0e6a0792df126c548" + "Rev": "0457360d54ca4d081a769eaa1617e0462153fd70" }, { "ImportPath": "github.com/hashicorp/logutils", diff --git a/vendor/github.com/hashicorp/hil/.gitignore b/vendor/github.com/hashicorp/hil/.gitignore index e43b0f988..9d6e5df38 100644 --- a/vendor/github.com/hashicorp/hil/.gitignore +++ b/vendor/github.com/hashicorp/hil/.gitignore @@ -1 +1,3 @@ .DS_Store +.idea +*.iml diff --git a/vendor/github.com/hashicorp/hil/ast/ast.go b/vendor/github.com/hashicorp/hil/ast/ast.go index 1d784c78a..f1a88d58c 100644 --- a/vendor/github.com/hashicorp/hil/ast/ast.go +++ b/vendor/github.com/hashicorp/hil/ast/ast.go @@ -52,4 +52,5 @@ const ( TypeString TypeInt TypeFloat + TypeList ) diff --git a/vendor/github.com/hashicorp/hil/ast/index.go b/vendor/github.com/hashicorp/hil/ast/index.go new file mode 100644 index 000000000..4d3313510 --- /dev/null +++ b/vendor/github.com/hashicorp/hil/ast/index.go @@ -0,0 +1,68 @@ +package ast + +import ( + "fmt" + "strings" +) + +// Index represents an indexing operation into another data structure +type Index struct { + Target Node + Key Node + Posx Pos +} + +func (n *Index) Accept(v Visitor) Node { + return v(n) +} + +func (n *Index) Pos() Pos { + return n.Posx +} + +func (n *Index) String() string { + return fmt.Sprintf("Index(%s, %s)", n.Target, n.Key) +} + +func (n *Index) Type(s Scope) (Type, error) { + variableAccess, ok := n.Target.(*VariableAccess) + if !ok { + return TypeInvalid, fmt.Errorf("target is not a variable") + } + + variable, ok := s.LookupVar(variableAccess.Name) + if !ok { + return TypeInvalid, fmt.Errorf("unknown variable accessed: %s", variableAccess.Name) + } + if variable.Type != TypeList { + return TypeInvalid, fmt.Errorf("invalid index operation into non-indexable type: %s", variable.Type) + } + + 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{}{} + } + + 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) + } + + return list[0].Type, nil +} + +func (n *Index) GoString() string { + return fmt.Sprintf("*%#v", *n) +} diff --git a/vendor/github.com/hashicorp/hil/ast/scope.go b/vendor/github.com/hashicorp/hil/ast/scope.go index 77c3ee79a..7a975d999 100644 --- a/vendor/github.com/hashicorp/hil/ast/scope.go +++ b/vendor/github.com/hashicorp/hil/ast/scope.go @@ -1,5 +1,10 @@ package ast +import ( + "fmt" + "reflect" +) + // Scope is the interface used to look up variables and functions while // evaluating. How these functions/variables are defined are up to the caller. type Scope interface { @@ -14,6 +19,26 @@ type Variable struct { Type Type } +// NewVariable creates a new Variable for the given value. This will +// attempt to infer the correct type. If it can't, an error will be returned. +func NewVariable(v interface{}) (result Variable, err error) { + switch v := reflect.ValueOf(v); v.Kind() { + case reflect.String: + result.Type = TypeString + default: + err = fmt.Errorf("Unknown type: %s", v.Kind()) + } + + result.Value = v + return +} + +// String implements Stringer on Variable, displaying the type and value +// of the Variable. +func (v Variable) String() string { + return fmt.Sprintf("{Variable (%s): %+v}", v.Type, v.Value) +} + // Function defines a function that can be executed by the engine. // The type checker will validate that the proper types will be called // to the callback. diff --git a/vendor/github.com/hashicorp/hil/ast/type_string.go b/vendor/github.com/hashicorp/hil/ast/type_string.go index 5410e011e..32bfde840 100644 --- a/vendor/github.com/hashicorp/hil/ast/type_string.go +++ b/vendor/github.com/hashicorp/hil/ast/type_string.go @@ -10,6 +10,7 @@ const ( _Type_name_2 = "TypeString" _Type_name_3 = "TypeInt" _Type_name_4 = "TypeFloat" + _Type_name_5 = "TypeList" ) var ( @@ -18,6 +19,7 @@ var ( _Type_index_2 = [...]uint8{0, 10} _Type_index_3 = [...]uint8{0, 7} _Type_index_4 = [...]uint8{0, 9} + _Type_index_5 = [...]uint8{0, 8} ) func (i Type) String() string { @@ -32,6 +34,8 @@ func (i Type) String() string { return _Type_name_3 case i == 16: return _Type_name_4 + case i == 32: + return _Type_name_5 default: return fmt.Sprintf("Type(%d)", i) } diff --git a/vendor/github.com/hashicorp/hil/check_types.go b/vendor/github.com/hashicorp/hil/check_types.go index 563591cf1..afffffcf1 100644 --- a/vendor/github.com/hashicorp/hil/check_types.go +++ b/vendor/github.com/hashicorp/hil/check_types.go @@ -61,6 +61,9 @@ func (v *TypeCheck) visit(raw ast.Node) ast.Node { case *ast.Call: tc := &typeCheckCall{n} result, err = tc.TypeCheck(v) + case *ast.Index: + tc := &typeCheckIndex{n} + result, err = tc.TypeCheck(v) case *ast.Concat: tc := &typeCheckConcat{n} result, err = tc.TypeCheck(v) @@ -285,6 +288,55 @@ func (tc *typeCheckVariableAccess) TypeCheck(v *TypeCheck) (ast.Node, error) { return tc.n, nil } +type typeCheckIndex struct { + n *ast.Index +} + +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 { + return nil, fmt.Errorf("target of an index must be a VariableAccess node, was %T", tc.n.Target) + } + + // Get the variable + variable, ok := v.Scope.LookupVar(varAccessNode.Name) + if !ok { + return nil, fmt.Errorf("unknown variable accessed: %s", varAccessNode.Name) + } + if variable.Type != ast.TypeList { + 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( actual ast.Type, expected ast.Type, n ast.Node) ast.Node { if v.Implicit == nil { diff --git a/vendor/github.com/hashicorp/hil/eval.go b/vendor/github.com/hashicorp/hil/eval.go index edc2d0128..6b81c760b 100644 --- a/vendor/github.com/hashicorp/hil/eval.go +++ b/vendor/github.com/hashicorp/hil/eval.go @@ -140,6 +140,8 @@ func (v *evalVisitor) visit(raw ast.Node) ast.Node { // types as well as any other EvalNode implementations. func evalNode(raw ast.Node) (EvalNode, error) { switch n := raw.(type) { + case *ast.Index: + return &evalIndex{n}, nil case *ast.Call: return &evalCall{n}, nil case *ast.Concat: @@ -184,6 +186,53 @@ func (v *evalCall) Eval(s ast.Scope, stack *ast.Stack) (interface{}, ast.Type, e return result, function.ReturnType, nil } +type evalIndex struct{ *ast.Index } + +func (v *evalIndex) Eval(scope ast.Scope, stack *ast.Stack) (interface{}, ast.Type, error) { + evalVarAccess, err := evalNode(v.Target) + if err != nil { + return nil, ast.TypeInvalid, err + } + target, targetType, err := evalVarAccess.Eval(scope, stack) + + evalKey, err := evalNode(v.Key) + 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) + } + + list, ok := target.([]ast.Variable) + if !ok { + return nil, ast.TypeInvalid, fmt.Errorf("cannot cast target to []Variable") + } + + keyInt, ok := key.(int) + if !ok { + return nil, ast.TypeInvalid, fmt.Errorf("cannot cast key to int") + } + + if len(list) == 0 { + return nil, ast.TypeInvalid, fmt.Errorf("list is empty") + } + + if keyInt < 0 || len(list) < keyInt+1 { + return nil, ast.TypeInvalid, fmt.Errorf("index %d out of range (max %d)", keyInt, len(list)) + } + + returnVal := list[keyInt].Value + returnType := list[keyInt].Type + + return returnVal, returnType, nil +} + type evalConcat struct{ *ast.Concat } func (v *evalConcat) Eval(s ast.Scope, stack *ast.Stack) (interface{}, ast.Type, error) { diff --git a/vendor/github.com/hashicorp/hil/lang.y b/vendor/github.com/hashicorp/hil/lang.y index 296ebeb92..6dc15f0d8 100644 --- a/vendor/github.com/hashicorp/hil/lang.y +++ b/vendor/github.com/hashicorp/hil/lang.y @@ -21,6 +21,7 @@ import ( %token PROGRAM_BRACKET_LEFT PROGRAM_BRACKET_RIGHT %token PROGRAM_STRING_START PROGRAM_STRING_END %token PAREN_LEFT PAREN_RIGHT COMMA +%token SQUARE_BRACKET_LEFT SQUARE_BRACKET_RIGHT %token ARITH_OP IDENTIFIER INTEGER FLOAT STRING @@ -157,6 +158,17 @@ expr: { $$ = &ast.Call{Func: $1.Value.(string), Args: $3, Posx: $1.Pos} } +| IDENTIFIER SQUARE_BRACKET_LEFT expr SQUARE_BRACKET_RIGHT + { + $$ = &ast.Index{ + Target: &ast.VariableAccess{ + Name: $1.Value.(string), + Posx: $1.Pos, + }, + Key: $3, + Posx: $1.Pos, + } + } args: { diff --git a/vendor/github.com/hashicorp/hil/lex.go b/vendor/github.com/hashicorp/hil/lex.go index 8db6e13c8..a66694641 100644 --- a/vendor/github.com/hashicorp/hil/lex.go +++ b/vendor/github.com/hashicorp/hil/lex.go @@ -166,6 +166,10 @@ func (x *parserLex) lexModeInterpolation(yylval *parserSymType) int { return PAREN_LEFT case ')': return PAREN_RIGHT + case '[': + return SQUARE_BRACKET_LEFT + case ']': + return SQUARE_BRACKET_RIGHT case ',': return COMMA case '+': diff --git a/vendor/github.com/hashicorp/hil/y.go b/vendor/github.com/hashicorp/hil/y.go index fee7aaafb..bf4ca1bc3 100644 --- a/vendor/github.com/hashicorp/hil/y.go +++ b/vendor/github.com/hashicorp/hil/y.go @@ -24,11 +24,13 @@ const PROGRAM_STRING_END = 57349 const PAREN_LEFT = 57350 const PAREN_RIGHT = 57351 const COMMA = 57352 -const ARITH_OP = 57353 -const IDENTIFIER = 57354 -const INTEGER = 57355 -const FLOAT = 57356 -const STRING = 57357 +const SQUARE_BRACKET_LEFT = 57353 +const SQUARE_BRACKET_RIGHT = 57354 +const ARITH_OP = 57355 +const IDENTIFIER = 57356 +const INTEGER = 57357 +const FLOAT = 57358 +const STRING = 57359 var parserToknames = [...]string{ "$end", @@ -41,6 +43,8 @@ var parserToknames = [...]string{ "PAREN_LEFT", "PAREN_RIGHT", "COMMA", + "SQUARE_BRACKET_LEFT", + "SQUARE_BRACKET_RIGHT", "ARITH_OP", "IDENTIFIER", "INTEGER", @@ -53,7 +57,7 @@ const parserEofCode = 1 const parserErrCode = 2 const parserMaxDepth = 200 -//line lang.y:184 +//line lang.y:196 //line yacctab:1 var parserExca = [...]int{ @@ -62,52 +66,57 @@ var parserExca = [...]int{ -2, 0, } -const parserNprod = 20 +const parserNprod = 21 const parserPrivate = 57344 var parserTokenNames []string var parserStates []string -const parserLast = 34 +const parserLast = 37 var parserAct = [...]int{ - 9, 7, 3, 16, 22, 8, 17, 17, 20, 17, - 1, 18, 6, 23, 8, 19, 25, 26, 21, 11, - 2, 24, 7, 4, 5, 0, 10, 27, 0, 14, - 15, 12, 13, 6, + 9, 7, 29, 17, 23, 16, 17, 3, 17, 20, + 8, 18, 21, 17, 6, 19, 27, 28, 22, 8, + 1, 25, 26, 7, 11, 2, 24, 10, 4, 30, + 5, 0, 14, 15, 12, 13, 6, } var parserPact = [...]int{ - -3, -1000, -3, -1000, -1000, -1000, -1000, 18, -1000, -2, - 18, -3, -1000, -1000, 18, 0, -1000, 18, -5, -1000, - 18, -1000, -1000, 7, -4, -1000, 18, -4, + -3, -1000, -3, -1000, -1000, -1000, -1000, 19, -1000, 0, + 19, -3, -1000, -1000, 19, 1, -1000, 19, -5, -1000, + 19, 19, -1000, -1000, 7, -7, -10, -1000, 19, -1000, + -7, } var parserPgo = [...]int{ - 0, 0, 24, 23, 19, 2, 13, 10, + 0, 0, 30, 28, 24, 7, 26, 20, } var parserR1 = [...]int{ 0, 7, 7, 4, 4, 5, 5, 2, 1, 1, - 1, 1, 1, 1, 1, 1, 6, 6, 6, 3, + 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, + 3, } var parserR2 = [...]int{ 0, 0, 1, 1, 2, 1, 1, 3, 3, 1, - 1, 1, 2, 3, 1, 4, 0, 3, 1, 1, + 1, 1, 2, 3, 1, 4, 4, 0, 3, 1, + 1, } var parserChk = [...]int{ - -1000, -7, -4, -5, -3, -2, 15, 4, -5, -1, - 8, -4, 13, 14, 11, 12, 5, 11, -1, -1, - 8, -1, 9, -6, -1, 9, 10, -1, + -1000, -7, -4, -5, -3, -2, 17, 4, -5, -1, + 8, -4, 15, 16, 13, 14, 5, 13, -1, -1, + 8, 11, -1, 9, -6, -1, -1, 9, 10, 12, + -1, } var parserDef = [...]int{ - 1, -2, 2, 3, 5, 6, 19, 0, 4, 0, + 1, -2, 2, 3, 5, 6, 20, 0, 4, 0, 0, 9, 10, 11, 0, 14, 7, 0, 0, 12, - 16, 13, 8, 0, 18, 15, 0, 17, + 17, 0, 13, 8, 0, 19, 0, 15, 0, 16, + 18, } var parserTok1 = [...]int{ @@ -116,7 +125,7 @@ var parserTok1 = [...]int{ var parserTok2 = [...]int{ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, - 12, 13, 14, 15, + 12, 13, 14, 15, 16, 17, } var parserTok3 = [...]int{ 0, @@ -464,7 +473,7 @@ parserdefault: case 1: parserDollar = parserS[parserpt-0 : parserpt+1] - //line lang.y:35 + //line lang.y:36 { parserResult = &ast.LiteralNode{ Value: "", @@ -474,7 +483,7 @@ parserdefault: } case 2: parserDollar = parserS[parserpt-1 : parserpt+1] - //line lang.y:43 + //line lang.y:44 { parserResult = parserDollar[1].node @@ -497,13 +506,13 @@ parserdefault: } case 3: parserDollar = parserS[parserpt-1 : parserpt+1] - //line lang.y:66 + //line lang.y:67 { parserVAL.node = parserDollar[1].node } case 4: parserDollar = parserS[parserpt-2 : parserpt+1] - //line lang.y:70 + //line lang.y:71 { var result []ast.Node if c, ok := parserDollar[1].node.(*ast.Concat); ok { @@ -519,37 +528,37 @@ parserdefault: } case 5: parserDollar = parserS[parserpt-1 : parserpt+1] - //line lang.y:86 + //line lang.y:87 { parserVAL.node = parserDollar[1].node } case 6: parserDollar = parserS[parserpt-1 : parserpt+1] - //line lang.y:90 + //line lang.y:91 { parserVAL.node = parserDollar[1].node } case 7: parserDollar = parserS[parserpt-3 : parserpt+1] - //line lang.y:96 + //line lang.y:97 { parserVAL.node = parserDollar[2].node } case 8: parserDollar = parserS[parserpt-3 : parserpt+1] - //line lang.y:102 + //line lang.y:103 { parserVAL.node = parserDollar[2].node } case 9: parserDollar = parserS[parserpt-1 : parserpt+1] - //line lang.y:106 + //line lang.y:107 { parserVAL.node = parserDollar[1].node } case 10: parserDollar = parserS[parserpt-1 : parserpt+1] - //line lang.y:110 + //line lang.y:111 { parserVAL.node = &ast.LiteralNode{ Value: parserDollar[1].token.Value.(int), @@ -559,7 +568,7 @@ parserdefault: } case 11: parserDollar = parserS[parserpt-1 : parserpt+1] - //line lang.y:118 + //line lang.y:119 { parserVAL.node = &ast.LiteralNode{ Value: parserDollar[1].token.Value.(float64), @@ -569,7 +578,7 @@ parserdefault: } case 12: parserDollar = parserS[parserpt-2 : parserpt+1] - //line lang.y:126 + //line lang.y:127 { // This is REALLY jank. We assume that a singular ARITH_OP // means 0 ARITH_OP expr, which... is weird. We don't want to @@ -590,7 +599,7 @@ parserdefault: } case 13: parserDollar = parserS[parserpt-3 : parserpt+1] - //line lang.y:145 + //line lang.y:146 { parserVAL.node = &ast.Arithmetic{ Op: parserDollar[2].token.Value.(ast.ArithmeticOp), @@ -600,37 +609,50 @@ parserdefault: } case 14: parserDollar = parserS[parserpt-1 : parserpt+1] - //line lang.y:153 + //line lang.y:154 { parserVAL.node = &ast.VariableAccess{Name: parserDollar[1].token.Value.(string), Posx: parserDollar[1].token.Pos} } case 15: parserDollar = parserS[parserpt-4 : parserpt+1] - //line lang.y:157 + //line lang.y:158 { parserVAL.node = &ast.Call{Func: parserDollar[1].token.Value.(string), Args: parserDollar[3].nodeList, Posx: parserDollar[1].token.Pos} } case 16: - parserDollar = parserS[parserpt-0 : parserpt+1] + parserDollar = parserS[parserpt-4 : parserpt+1] //line lang.y:162 + { + parserVAL.node = &ast.Index{ + Target: &ast.VariableAccess{ + Name: parserDollar[1].token.Value.(string), + Posx: parserDollar[1].token.Pos, + }, + Key: parserDollar[3].node, + Posx: parserDollar[1].token.Pos, + } + } + case 17: + parserDollar = parserS[parserpt-0 : parserpt+1] + //line lang.y:174 { parserVAL.nodeList = nil } - case 17: + case 18: parserDollar = parserS[parserpt-3 : parserpt+1] - //line lang.y:166 + //line lang.y:178 { parserVAL.nodeList = append(parserDollar[1].nodeList, parserDollar[3].node) } - case 18: + case 19: parserDollar = parserS[parserpt-1 : parserpt+1] - //line lang.y:170 + //line lang.y:182 { parserVAL.nodeList = append(parserVAL.nodeList, parserDollar[1].node) } - case 19: + case 20: parserDollar = parserS[parserpt-1 : parserpt+1] - //line lang.y:176 + //line lang.y:188 { parserVAL.node = &ast.LiteralNode{ Value: parserDollar[1].token.Value.(string), diff --git a/vendor/github.com/hashicorp/hil/y.output b/vendor/github.com/hashicorp/hil/y.output index 92c1ff4bc..26df788c5 100644 --- a/vendor/github.com/hashicorp/hil/y.output +++ b/vendor/github.com/hashicorp/hil/y.output @@ -5,7 +5,7 @@ state 0 PROGRAM_BRACKET_LEFT shift 7 STRING shift 6 - . reduce 1 (src line 34) + . reduce 1 (src line 35) interpolation goto 5 literal goto 4 @@ -26,7 +26,7 @@ state 2 PROGRAM_BRACKET_LEFT shift 7 STRING shift 6 - . reduce 2 (src line 42) + . reduce 2 (src line 43) interpolation goto 5 literal goto 4 @@ -35,25 +35,25 @@ state 2 state 3 literalModeTop: literalModeValue. (3) - . reduce 3 (src line 64) + . reduce 3 (src line 65) state 4 literalModeValue: literal. (5) - . reduce 5 (src line 84) + . reduce 5 (src line 85) state 5 literalModeValue: interpolation. (6) - . reduce 6 (src line 89) + . reduce 6 (src line 90) state 6 - literal: STRING. (19) + literal: STRING. (20) - . reduce 19 (src line 174) + . reduce 20 (src line 186) state 7 @@ -77,7 +77,7 @@ state 7 state 8 literalModeTop: literalModeTop literalModeValue. (4) - . reduce 4 (src line 69) + . reduce 4 (src line 70) state 9 @@ -113,7 +113,7 @@ state 11 PROGRAM_BRACKET_LEFT shift 7 STRING shift 6 - . reduce 9 (src line 105) + . reduce 9 (src line 106) interpolation goto 5 literal goto 4 @@ -122,13 +122,13 @@ state 11 state 12 expr: INTEGER. (10) - . reduce 10 (src line 109) + . reduce 10 (src line 110) state 13 expr: FLOAT. (11) - . reduce 11 (src line 117) + . reduce 11 (src line 118) state 14 @@ -152,15 +152,17 @@ state 14 state 15 expr: IDENTIFIER. (14) expr: IDENTIFIER.PAREN_LEFT args PAREN_RIGHT + expr: IDENTIFIER.SQUARE_BRACKET_LEFT expr SQUARE_BRACKET_RIGHT PAREN_LEFT shift 20 - . reduce 14 (src line 152) + SQUARE_BRACKET_LEFT shift 21 + . reduce 14 (src line 153) state 16 interpolation: PROGRAM_BRACKET_LEFT expr PROGRAM_BRACKET_RIGHT. (7) - . reduce 7 (src line 94) + . reduce 7 (src line 95) state 17 @@ -175,7 +177,7 @@ state 17 STRING shift 6 . error - expr goto 21 + expr goto 22 interpolation goto 5 literal goto 4 literalModeTop goto 11 @@ -185,7 +187,7 @@ state 18 expr: PAREN_LEFT expr.PAREN_RIGHT expr: expr.ARITH_OP expr - PAREN_RIGHT shift 22 + PAREN_RIGHT shift 23 ARITH_OP shift 17 . error @@ -194,12 +196,12 @@ state 19 expr: ARITH_OP expr. (12) expr: expr.ARITH_OP expr - . reduce 12 (src line 125) + . reduce 12 (src line 126) state 20 expr: IDENTIFIER PAREN_LEFT.args PAREN_RIGHT - args: . (16) + args: . (17) PROGRAM_BRACKET_LEFT shift 7 PAREN_LEFT shift 10 @@ -208,52 +210,79 @@ state 20 INTEGER shift 12 FLOAT shift 13 STRING shift 6 - . reduce 16 (src line 161) + . reduce 17 (src line 173) - expr goto 24 + expr goto 25 interpolation goto 5 literal goto 4 literalModeTop goto 11 literalModeValue goto 3 - args goto 23 + args goto 24 state 21 + expr: IDENTIFIER SQUARE_BRACKET_LEFT.expr SQUARE_BRACKET_RIGHT + + PROGRAM_BRACKET_LEFT shift 7 + PAREN_LEFT shift 10 + ARITH_OP shift 14 + IDENTIFIER shift 15 + INTEGER shift 12 + FLOAT shift 13 + STRING shift 6 + . error + + expr goto 26 + interpolation goto 5 + literal goto 4 + literalModeTop goto 11 + literalModeValue goto 3 + +state 22 expr: expr.ARITH_OP expr expr: expr ARITH_OP expr. (13) - . reduce 13 (src line 144) - - -state 22 - expr: PAREN_LEFT expr PAREN_RIGHT. (8) - - . reduce 8 (src line 100) + . reduce 13 (src line 145) state 23 - expr: IDENTIFIER PAREN_LEFT args.PAREN_RIGHT - args: args.COMMA expr + expr: PAREN_LEFT expr PAREN_RIGHT. (8) - PAREN_RIGHT shift 25 - COMMA shift 26 - . error + . reduce 8 (src line 101) state 24 - expr: expr.ARITH_OP expr - args: expr. (18) + expr: IDENTIFIER PAREN_LEFT args.PAREN_RIGHT + args: args.COMMA expr - ARITH_OP shift 17 - . reduce 18 (src line 169) + PAREN_RIGHT shift 27 + COMMA shift 28 + . error state 25 - expr: IDENTIFIER PAREN_LEFT args PAREN_RIGHT. (15) + expr: expr.ARITH_OP expr + args: expr. (19) - . reduce 15 (src line 156) + ARITH_OP shift 17 + . reduce 19 (src line 181) state 26 + expr: expr.ARITH_OP expr + expr: IDENTIFIER SQUARE_BRACKET_LEFT expr.SQUARE_BRACKET_RIGHT + + SQUARE_BRACKET_RIGHT shift 29 + ARITH_OP shift 17 + . error + + +state 27 + expr: IDENTIFIER PAREN_LEFT args PAREN_RIGHT. (15) + + . reduce 15 (src line 157) + + +state 28 args: args COMMA.expr PROGRAM_BRACKET_LEFT shift 7 @@ -265,29 +294,35 @@ state 26 STRING shift 6 . error - expr goto 27 + expr goto 30 interpolation goto 5 literal goto 4 literalModeTop goto 11 literalModeValue goto 3 -state 27 +state 29 + expr: IDENTIFIER SQUARE_BRACKET_LEFT expr SQUARE_BRACKET_RIGHT. (16) + + . reduce 16 (src line 161) + + +state 30 expr: expr.ARITH_OP expr - args: args COMMA expr. (17) + args: args COMMA expr. (18) ARITH_OP shift 17 - . reduce 17 (src line 165) + . reduce 18 (src line 177) -15 terminals, 8 nonterminals -20 grammar rules, 28/2000 states +17 terminals, 8 nonterminals +21 grammar rules, 31/2000 states 0 shift/reduce, 0 reduce/reduce conflicts reported 57 working sets used -memory: parser 40/30000 -23 extra closures -57 shift entries, 1 exceptions -15 goto entries -27 entries saved by goto default -Optimizer space used: output 34/30000 -34 table entries, 2 zero -maximum spread: 15, maximum offset: 26 +memory: parser 45/30000 +26 extra closures +67 shift entries, 1 exceptions +16 goto entries +31 entries saved by goto default +Optimizer space used: output 37/30000 +37 table entries, 1 zero +maximum spread: 17, maximum offset: 28