dependencies: Update github.com/hashicorp/hil

This commit is contained in:
James Nugent 2016-02-26 14:56:07 -05:00
parent 5ecc068038
commit 0de1a391de
12 changed files with 374 additions and 100 deletions

4
Godeps/Godeps.json generated
View File

@ -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",

View File

@ -1 +1,3 @@
.DS_Store
.idea
*.iml

View File

@ -52,4 +52,5 @@ const (
TypeString
TypeInt
TypeFloat
TypeList
)

68
vendor/github.com/hashicorp/hil/ast/index.go generated vendored Normal file
View File

@ -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)
}

View File

@ -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.

View File

@ -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)
}

View File

@ -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 {

View File

@ -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) {

View File

@ -21,6 +21,7 @@ import (
%token <str> PROGRAM_BRACKET_LEFT PROGRAM_BRACKET_RIGHT
%token <str> PROGRAM_STRING_START PROGRAM_STRING_END
%token <str> PAREN_LEFT PAREN_RIGHT COMMA
%token <str> SQUARE_BRACKET_LEFT SQUARE_BRACKET_RIGHT
%token <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:
{

View File

@ -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 '+':

114
vendor/github.com/hashicorp/hil/y.go generated vendored
View File

@ -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),

View File

@ -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