func new(g *ast.Grammar, record bool) (*Mem, error) { simp := interp.NewSimplifier(g) if record { simp = simp.OptimizeForRecord() } g = simp.Grammar() refs := ast.NewRefLookup(g) m := &Mem{ refs: refs, simplifier: simp, patterns: newPatternsSet(), zis: newIntsSet(), stackElms: newPairSet(), nullables: newBitsetSet(), Calls: []*CallNode{}, Returns: []map[int]int{}, Escapables: []bool{}, StateToNullable: []int{}, Accept: []bool{}, } start := m.patterns.add([]*ast.Pattern{refs["main"]}) e := &exprToFunc{m: make(map[*ast.Expr]funcs.Bool)} for _, p := range refs { p.Walk(e) if e.err != nil { return nil, e.err } } m.funcs = e.m m.Start = start return m, nil }
func TestExplosionAndSameTree(t *testing.T) { var input = `( .A:.B:.DeepLevel:.DeeperLevel:.DeepestLevel:->contains($string,"el") & ( .A:.B:.Rs:._:->eq("~a",$string) & ( .A:.B:.NumI32:->contains($int,[]int{28,1,52}) & ( .A:.B:.NumI64:>= 1 & ( .A:.B:.NumU32:<= uint(4) & ( .A:.B:.NumU64:== uint(4) & ( .A:.B:.YesNo:== true & ( .A:.B:.BS:== []byte{0x3, 0x2, 0x1, 0x0} & .A:.B:.Uuid: == []byte{0x3, 0x2, 0x1, 0x0} ) ) ) ) ) ) ) )` g, err := parser.ParseGrammar(input) if err != nil { t.Fatal(err) } // This one causes a state explosion of over 14000 states. // Since we know field names can't repeat the simplification can be made for record (JSON and proto) like serialization formats, but not for XML. g = interp.NewSimplifier(g).OptimizeForRecord().Grammar() t.Logf("%v", g) a, err := Compile(g) if err != nil { t.Fatal(err) } t.Logf("number of states %d", len(a.accept)) if len(a.accept) > 1000 { t.Fatal("number of states exploded") } }