1// Copyright 2018 The OPA Authors.  All rights reserved.
2// Use of this source code is governed by an Apache2
3// license that can be found in the LICENSE file.
4
5package ast
6
7import (
8	"fmt"
9	"io"
10	"strings"
11)
12
13// Pretty writes a pretty representation of the AST rooted at x to w.
14//
15// This is function is intended for debug purposes when inspecting ASTs.
16func Pretty(w io.Writer, x interface{}) {
17	pp := &prettyPrinter{
18		depth: -1,
19		w:     w,
20	}
21	NewBeforeAfterVisitor(pp.Before, pp.After).Walk(x)
22}
23
24type prettyPrinter struct {
25	depth int
26	w     io.Writer
27}
28
29func (pp *prettyPrinter) Before(x interface{}) bool {
30	switch x.(type) {
31	case *Term:
32	default:
33		pp.depth++
34	}
35
36	switch x := x.(type) {
37	case *Term:
38		return false
39	case Args:
40		if len(x) == 0 {
41			return false
42		}
43		pp.writeType(x)
44	case *Expr:
45		extras := []string{}
46		if x.Negated {
47			extras = append(extras, "negated")
48		}
49		extras = append(extras, fmt.Sprintf("index=%d", x.Index))
50		pp.writeIndent("%v %v", TypeName(x), strings.Join(extras, " "))
51	case Null, Boolean, Number, String, Var:
52		pp.writeValue(x)
53	default:
54		pp.writeType(x)
55	}
56	return false
57}
58
59func (pp *prettyPrinter) After(x interface{}) {
60	switch x.(type) {
61	case *Term:
62	default:
63		pp.depth--
64	}
65}
66
67func (pp *prettyPrinter) writeValue(x interface{}) {
68	pp.writeIndent(fmt.Sprint(x))
69}
70
71func (pp *prettyPrinter) writeType(x interface{}) {
72	pp.writeIndent(TypeName(x))
73}
74
75func (pp *prettyPrinter) writeIndent(f string, a ...interface{}) {
76	pad := strings.Repeat(" ", pp.depth)
77	pp.write(pad+f, a...)
78}
79
80func (pp *prettyPrinter) write(f string, a ...interface{}) {
81	fmt.Fprintf(pp.w, f+"\n", a...)
82}
83