func TestSimplifyTree(t *testing.T) { left := ast.NewTreeNode(ast.NewStringName("A"), ast.NewTreeNode(ast.NewStringName("B"), ast.NewContains( ast.NewTreeNode(ast.NewStringName("C"), ast.NewZAny()), )), ) right := ast.NewTreeNode(ast.NewStringName("A"), ast.NewTreeNode(ast.NewStringName("B"), ast.NewContains( ast.NewTreeNode(ast.NewStringName("D"), ast.NewZAny()), )), ) input := ast.NewAnd(left, right) expected := ast.NewTreeNode(ast.NewStringName("A"), ast.NewTreeNode(ast.NewStringName("B"), ast.NewAnd( ast.NewContains( ast.NewTreeNode(ast.NewStringName("C"), ast.NewZAny()), ), ast.NewContains( ast.NewTreeNode(ast.NewStringName("D"), ast.NewZAny()), ), )), ) output := NewSimplifier(input.Grammar()).Simplify(input) t.Logf("%v", output) if !expected.Equal(output) { t.Fatalf("expected %v, but got %v", expected, output) } }
func simplifyChildren(children []*ast.Pattern, op func(left, right *ast.Pattern) *ast.Pattern, record bool) []*ast.Pattern { if len(children) == 0 || len(children) == 1 { return children } if record { c0 := children[0].GetContains().GetPattern().GetTreeNode() c1 := children[1].GetContains().GetPattern().GetTreeNode() if c0 != nil && c1 != nil { if c0.GetName().Equal(c1.GetName()) { newchild := ast.NewContains(ast.NewTreeNode(c0.GetName(), op(c0.GetPattern(), c1.GetPattern()))) children[1] = newchild return simplifyChildren(children[1:], op, record) } } } t0 := children[0].TreeNode t1 := children[1].TreeNode if t0 != nil && t1 != nil { if t0.GetName().Equal(t1.GetName()) { newchild := ast.NewTreeNode(t0.GetName(), op(t0.GetPattern(), t1.GetPattern())) children[1] = newchild return simplifyChildren(children[1:], op, record) } } return append([]*ast.Pattern{children[0]}, simplifyChildren(children[1:], op, record)...) }
func simplifyContains(p *ast.Pattern) *ast.Pattern { if isEmpty(p) || isZany(p) { return ast.NewZAny() } if isNotZany(p) { return p } return ast.NewContains(p) }
func TestSimplifyRecordLeaf1(t *testing.T) { input := ast.NewAnd( ast.NewContains(ast.NewTreeNode(ast.NewStringName("A"), combinator.Value(funcs.Contains(funcs.StringVar(), funcs.StringConst("a"))))), ast.NewContains(ast.NewTreeNode(ast.NewStringName("A"), combinator.Value(funcs.Contains(funcs.StringVar(), funcs.StringConst("b"))))), ) t.Logf("input: %v", input) expected := ast.NewContains(ast.NewTreeNode(ast.NewStringName("A"), combinator.Value(funcs.And( funcs.Contains(funcs.StringVar(), funcs.StringConst("a")), funcs.Contains(funcs.StringVar(), funcs.StringConst("b")), )))) output := NewSimplifier(input.Grammar()).OptimizeForRecord().Simplify(input) expected.Format() output.Format() t.Logf("%v", output) if !expected.Equal(output) { t.Fatalf("expected %v, but got %v", expected, output) } }
func TestSimplifyContainsFalseTreeNode(t *testing.T) { input := ast.NewContains(ast.NewTreeNode(ast.NewAnyNameExcept(ast.NewAnyName()), ast.NewZAny())) expected := ast.NewNot(ast.NewZAny()) output := NewSimplifier(input.Grammar()).Simplify(input) t.Logf("%v", output) if !expected.Equal(output) { t.Fatalf("expected %v, but got %v", expected, output) } }
func (this *nameToNumber) translate(context *context, p *ast.Pattern) (*ast.Pattern, error) { typ := p.GetValue() switch v := typ.(type) { case *ast.Empty, *ast.LeafNode, *ast.ZAny: return p, nil case *ast.TreeNode: return this.translateName(context, v.GetName(), v.GetPattern()) case *ast.Concat: l, err1 := this.translate(context, v.GetLeftPattern()) r, err2 := this.translate(context, v.GetRightPattern()) return ast.NewConcat(l, r), anyErr(err1, err2) case *ast.Or: l, err1 := this.translate(context, v.GetLeftPattern()) r, err2 := this.translate(context, v.GetRightPattern()) return ast.NewOr(l, r), anyErr(err1, err2) case *ast.And: l, err1 := this.translate(context, v.GetLeftPattern()) r, err2 := this.translate(context, v.GetRightPattern()) return ast.NewAnd(l, r), anyErr(err1, err2) case *ast.ZeroOrMore: p, err := this.translate(context, v.GetPattern()) return ast.NewZeroOrMore(p), err case *ast.Reference: c, ok := this.refs[v.GetName()] if !ok { this.refs[v.GetName()] = context return p, nil } if !c.Equal(context) { //TODO we could probably create a new reference here // for every conflicting combination of msg x repeated x referece name return nil, &ErrDup{v.GetName(), c, context} } return p, nil case *ast.Not: p, err := this.translate(context, v.GetPattern()) return ast.NewNot(p), err case *ast.Contains: p, err := this.translate(context, v.GetPattern()) return ast.NewContains(p), err case *ast.Optional: p, err := this.translate(context, v.GetPattern()) return ast.NewOptional(p), err case *ast.Interleave: l, err1 := this.translate(context, v.GetLeftPattern()) r, err2 := this.translate(context, v.GetRightPattern()) return ast.NewInterleave(l, r), anyErr(err1, err2) } panic(fmt.Sprintf("unknown pattern typ %T", typ)) }
func simplifyConcat(p1, p2 *ast.Pattern) *ast.Pattern { if isNotZany(p1) || isNotZany(p2) { return emptyset } if p1.Concat != nil { return simplifyConcat( p1.Concat.GetLeftPattern(), ast.NewConcat(p1.Concat.GetRightPattern(), p2), ) } if isEmpty(p1) { return p2 } if isEmpty(p2) { return p1 } if isZany(p1) && p2.Concat != nil { if l := p2.Concat.GetLeftPattern(); isZany(p2.Concat.GetRightPattern()) { return ast.NewContains(l) } } return ast.NewConcat(p1, p2) }