func topDown(pattern *ast.Pattern, f func(*ast.Pattern)) { f(pattern) typ := pattern.GetValue() switch v := typ.(type) { case *ast.TreeNode: topDown(v.GetPattern(), f) case *ast.Concat: topDown(v.GetLeftPattern(), f) topDown(v.GetRightPattern(), f) case *ast.Or: topDown(v.GetLeftPattern(), f) topDown(v.GetRightPattern(), f) case *ast.And: topDown(v.GetLeftPattern(), f) topDown(v.GetRightPattern(), f) case *ast.ZeroOrMore: topDown(v.GetPattern(), f) case *ast.Not: topDown(v.GetPattern(), f) case *ast.Contains: topDown(v.GetPattern(), f) case *ast.Optional: topDown(v.GetPattern(), f) case *ast.Interleave: topDown(v.GetLeftPattern(), f) topDown(v.GetRightPattern(), f) case *ast.Empty, *ast.LeafNode, *ast.Reference, *ast.ZAny: // do nothing default: panic(fmt.Sprintf("unknown pattern typ %T", typ)) } }
//Nullable returns whether the input Pattern p also matches the empty string. //This is a naive implementation and it does not handle left recursion. func Nullable(refs ast.RefLookup, p *ast.Pattern) bool { typ := p.GetValue() switch v := typ.(type) { case *ast.Empty: return true case *ast.TreeNode: return false case *ast.LeafNode: return false case *ast.Concat: return Nullable(refs, v.GetLeftPattern()) && Nullable(refs, v.GetRightPattern()) case *ast.Or: return Nullable(refs, v.GetLeftPattern()) || Nullable(refs, v.GetRightPattern()) case *ast.And: return Nullable(refs, v.GetLeftPattern()) && Nullable(refs, v.GetRightPattern()) case *ast.ZeroOrMore: return true case *ast.Reference: return Nullable(refs, refs[v.GetName()]) case *ast.Not: return !(Nullable(refs, v.GetPattern())) case *ast.ZAny: return true case *ast.Contains: return Nullable(refs, v.GetPattern()) case *ast.Optional: return true case *ast.Interleave: return Nullable(refs, v.GetLeftPattern()) && Nullable(refs, v.GetRightPattern()) } panic(fmt.Sprintf("unknown pattern typ %T", typ)) }
func derivReturn(refs ast.RefLookup, p *ast.Pattern, patterns []*ast.Pattern) (*ast.Pattern, []*ast.Pattern) { typ := p.GetValue() switch v := typ.(type) { case *ast.Empty: return ast.NewNot(ast.NewZAny()), patterns case *ast.ZAny: return ast.NewZAny(), patterns case *ast.TreeNode: if Nullable(refs, patterns[0]) { return ast.NewEmpty(), patterns[1:] } return ast.NewNot(ast.NewZAny()), patterns[1:] case *ast.LeafNode: if Nullable(refs, patterns[0]) { return ast.NewEmpty(), patterns[1:] } return ast.NewNot(ast.NewZAny()), patterns[1:] case *ast.Concat: l, leftRest := derivReturn(refs, v.GetLeftPattern(), patterns) leftConcat := ast.NewConcat(l, v.GetRightPattern()) if !Nullable(refs, v.GetLeftPattern()) { return leftConcat, leftRest } r, rightRest := derivReturn(refs, v.GetRightPattern(), leftRest) return ast.NewOr(leftConcat, r), rightRest case *ast.Or: l, leftRest := derivReturn(refs, v.GetLeftPattern(), patterns) r, rightRest := derivReturn(refs, v.GetRightPattern(), leftRest) return ast.NewOr(l, r), rightRest case *ast.And: l, leftRest := derivReturn(refs, v.GetLeftPattern(), patterns) r, rightRest := derivReturn(refs, v.GetRightPattern(), leftRest) return ast.NewAnd(l, r), rightRest case *ast.Interleave: l, leftRest := derivReturn(refs, v.GetLeftPattern(), patterns) r, rightRest := derivReturn(refs, v.GetRightPattern(), leftRest) return ast.NewOr(ast.NewInterleave(l, v.GetRightPattern()), ast.NewInterleave(r, v.GetLeftPattern())), rightRest case *ast.ZeroOrMore: c, rest := derivReturn(refs, v.GetPattern(), patterns) return ast.NewConcat(c, p), rest case *ast.Reference: return derivReturn(refs, refs[v.GetName()], patterns) case *ast.Not: c, rest := derivReturn(refs, v.GetPattern(), patterns) return ast.NewNot(c), rest case *ast.Contains: return derivReturn(refs, ast.NewConcat(ast.NewZAny(), ast.NewConcat(v.GetPattern(), ast.NewZAny())), patterns) case *ast.Optional: return derivReturn(refs, ast.NewOr(v.GetPattern(), ast.NewEmpty()), patterns) } panic(fmt.Sprintf("unknown pattern typ %T", typ)) }
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 derivCall(refs map[string]*ast.Pattern, getFunc func(*ast.Expr) funcs.Bool, p *ast.Pattern) []*ifExpr { typ := p.GetValue() switch v := typ.(type) { case *ast.Empty: return []*ifExpr{} case *ast.ZAny: return []*ifExpr{} case *ast.TreeNode: b := nameexpr.NameToFunc(v.GetName()) return []*ifExpr{{b, v.GetPattern(), ast.NewNot(ast.NewZAny())}} case *ast.LeafNode: b := getFunc(v.GetExpr()) return []*ifExpr{{b, ast.NewEmpty(), ast.NewNot(ast.NewZAny())}} case *ast.Concat: l := derivCall(refs, getFunc, v.GetLeftPattern()) if !interp.Nullable(refs, v.GetLeftPattern()) { return l } r := derivCall(refs, getFunc, v.GetRightPattern()) return append(l, r...) case *ast.Or: return derivCall2(refs, getFunc, v.GetLeftPattern(), v.GetRightPattern()) case *ast.And: return derivCall2(refs, getFunc, v.GetLeftPattern(), v.GetRightPattern()) case *ast.Interleave: return derivCall2(refs, getFunc, v.GetLeftPattern(), v.GetRightPattern()) case *ast.ZeroOrMore: return derivCall(refs, getFunc, v.GetPattern()) case *ast.Reference: return derivCall(refs, getFunc, refs[v.GetName()]) case *ast.Not: return derivCall(refs, getFunc, v.GetPattern()) case *ast.Contains: return derivCall(refs, getFunc, ast.NewConcat(ast.NewZAny(), ast.NewConcat(v.GetPattern(), ast.NewZAny()))) case *ast.Optional: return derivCall(refs, getFunc, ast.NewOr(v.GetPattern(), ast.NewEmpty())) } panic(fmt.Sprintf("unknown pattern typ %T", typ)) }
func simplifyAnd(refs ast.RefLookup, p1, p2 *ast.Pattern, record bool) *ast.Pattern { if isNotZany(p1) || isNotZany(p2) { return emptyset } if isZany(p1) { return p2 } if isZany(p2) { return p1 } if isEmpty(p1) { if Nullable(refs, p2) { return ast.NewEmpty() } else { return emptyset } } if isEmpty(p2) { if Nullable(refs, p1) { return ast.NewEmpty() } else { return emptyset } } if p1.GetLeafNode() != nil && p2.GetLeafNode() != nil { expr1, err1 := compose.ConvertBuiltInIntoFunction(p1.GetLeafNode().GetExpr()) expr2, err2 := compose.ConvertBuiltInIntoFunction(p2.GetLeafNode().GetExpr()) if err1 == nil && err2 == nil { return ast.NewLeafNode(ast.NewFunction("and", expr1, expr2)) } } left := getAnds(p1) right := getAnds(p2) list := append(left, right...) list = ast.Set(list) list = simplifyChildren(list, func(left, right *ast.Pattern) *ast.Pattern { return simplifyAnd(refs, left, right, record) }, record) ast.Sort(list) var p *ast.Pattern = list[0] for i := range list { if i == 0 { continue } p = ast.NewAnd(p, list[i]) } return p }
func hasRecursion(visited map[*ast.Pattern]bool, refs ast.RefLookup, p *ast.Pattern) bool { if _, ok := visited[p]; ok { return true } visited[p] = true typ := p.GetValue() switch v := typ.(type) { case *ast.Empty: return false case *ast.TreeNode: return false case *ast.LeafNode: return false case *ast.Concat: return hasRecursion(visited, refs, v.GetLeftPattern()) || hasRecursion(visited, refs, v.GetRightPattern()) case *ast.Or: return hasRecursion(visited, refs, v.GetLeftPattern()) || hasRecursion(visited, refs, v.GetRightPattern()) case *ast.And: return hasRecursion(visited, refs, v.GetLeftPattern()) || hasRecursion(visited, refs, v.GetRightPattern()) case *ast.ZeroOrMore: return hasRecursion(visited, refs, v.GetPattern()) case *ast.Reference: return hasRecursion(visited, refs, refs[v.GetName()]) case *ast.Not: return hasRecursion(visited, refs, v.GetPattern()) case *ast.ZAny: return false case *ast.Contains: return hasRecursion(visited, refs, v.GetPattern()) case *ast.Optional: return hasRecursion(visited, refs, v.GetPattern()) case *ast.Interleave: return hasRecursion(visited, refs, v.GetLeftPattern()) || hasRecursion(visited, refs, v.GetRightPattern()) } panic(fmt.Sprintf("unknown pattern typ %T", typ)) }
func (this *simplifier) simplify(p *ast.Pattern, top bool) *ast.Pattern { cRef := func(cp *ast.Pattern) *ast.Pattern { if top { return cp } return checkRef(this.refs, cp) } cachesimp := func(sp *ast.Pattern) *ast.Pattern { if _, ok := this.cache[sp]; ok { return sp } s := this.simplify(sp, false) this.cache[s] = struct{}{} return s } simp := func(sp *ast.Pattern) *ast.Pattern { return this.simplify(sp, false) } typ := p.GetValue() switch v := typ.(type) { case *ast.Empty: return p case *ast.TreeNode: child := cachesimp(v.GetPattern()) if isNotZany(child) { return emptyset } name := v.GetName() b := nameexpr.NameToFunc(v.GetName()) if funcs.IsFalse(b) { return emptyset } if funcs.IsTrue(b) { name = ast.NewAnyName() } return cRef(ast.NewTreeNode(name, child)) case *ast.LeafNode: b, err := compose.NewBool(v.GetExpr()) if err != nil { //Don't simplify if there is an error to keep this function signature simple. return p } if funcs.IsFalse(b) { return emptyset } return p case *ast.Concat: return cRef(simplifyConcat( simp(v.GetLeftPattern()), simp(v.GetRightPattern()), )) case *ast.Or: return cRef(simplifyOr(this.refs, simp(v.GetLeftPattern()), simp(v.GetRightPattern()), this.record, )) case *ast.And: return cRef(simplifyAnd(this.refs, simp(v.GetLeftPattern()), simp(v.GetRightPattern()), this.record, )) case *ast.ZeroOrMore: return cRef(simplifyZeroOrMore(simp(v.GetPattern()))) case *ast.Reference: return p case *ast.Not: return cRef(simplifyNot(simp(v.GetPattern()))) case *ast.ZAny: return p case *ast.Contains: return cRef(simplifyContains(simp(v.GetPattern()))) case *ast.Optional: return simplifyOptional(simp(v.GetPattern())) case *ast.Interleave: return cRef(simplifyInterleave(this.refs, cachesimp(v.GetLeftPattern()), cachesimp(v.GetRightPattern()), )) } panic(fmt.Sprintf("unknown pattern typ %T", typ)) }
func isNotZany(p *ast.Pattern) bool { return p.Not != nil && p.GetNot().GetPattern().ZAny != nil }
func derivCall(refs ast.RefLookup, p *ast.Pattern, label parser.Value) ([]*ast.Pattern, error) { typ := p.GetValue() switch v := typ.(type) { case *ast.Empty: return []*ast.Pattern{}, nil case *ast.ZAny: return []*ast.Pattern{}, nil case *ast.TreeNode: b := nameexpr.NameToFunc(v.GetName()) f, err := compose.NewBoolFunc(b) if err != nil { return nil, err } eval, err := f.Eval(label) if err != nil { return nil, err } if eval { return []*ast.Pattern{v.GetPattern()}, nil } return []*ast.Pattern{ast.NewNot(ast.NewZAny())}, nil case *ast.LeafNode: b, err := compose.NewBool(v.GetExpr()) if err != nil { return nil, err } f, err := compose.NewBoolFunc(b) if err != nil { return nil, err } eval, err := f.Eval(label) if err != nil { return nil, err } if eval { return []*ast.Pattern{ast.NewEmpty()}, nil } return []*ast.Pattern{ast.NewNot(ast.NewZAny())}, nil case *ast.Concat: l, err := derivCall(refs, v.GetLeftPattern(), label) if err != nil { return nil, err } if !Nullable(refs, v.GetLeftPattern()) { return l, nil } r, err := derivCall(refs, v.GetRightPattern(), label) if err != nil { return nil, err } return append(l, r...), nil case *ast.Or: return derivCall2(refs, v.GetLeftPattern(), v.GetRightPattern(), label) case *ast.And: return derivCall2(refs, v.GetLeftPattern(), v.GetRightPattern(), label) case *ast.Interleave: return derivCall2(refs, v.GetLeftPattern(), v.GetRightPattern(), label) case *ast.ZeroOrMore: return derivCall(refs, v.GetPattern(), label) case *ast.Reference: return derivCall(refs, refs[v.GetName()], label) case *ast.Not: return derivCall(refs, v.GetPattern(), label) case *ast.Contains: return derivCall(refs, ast.NewConcat(ast.NewZAny(), ast.NewConcat(v.GetPattern(), ast.NewZAny())), label) case *ast.Optional: return derivCall(refs, ast.NewOr(v.GetPattern(), ast.NewEmpty()), label) } panic(fmt.Sprintf("unknown pattern typ %T", typ)) }