// Answer returns the filtered trace by performing a depth-first traversal on // the graph. The traversal goes from source to sink, where a sink is one of the // exits events of the top-level query. func (t *truth) Answer() (result []*topdown.Event) { byQuery := t.byQuery[t.source.event.QueryID] var sink *node for _, node := range byQuery { if node.event.Op == topdown.ExitOp { sink = node break } } if sink == nil { return nil } traversal := newTruthTraversal(t) nodes := util.DFS(traversal, t.source, sink) for _, n := range nodes { node := n.(*node) result = append(result, node.event) } return result }
// checkRecursion ensures that there are no recursive rule definitions, i.e., there are // no cycles in the RuleGraph. func (c *Compiler) checkRecursion() { for r := range c.RuleGraph { t := &ruleGraphTraveral{ graph: c.RuleGraph, visited: map[*Rule]struct{}{}, } if p := util.DFS(t, r, r); len(p) > 0 { n := []string{} for _, x := range p { n = append(n, string(x.(*Rule).Name)) } c.err(NewError(RecursionErr, r.Location, "%v: recursive reference: %v (recursion is not allowed)", r.Name, strings.Join(n, " -> "))) } } }