blob: 6a390aaeb6860550337af41094f6467b318e6bf7 [file] [log] [blame]
// Copyright 2020 CUE Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package debug prints a given ADT node.
//
// Note that the result is not valid CUE, but instead prints the internals
// of an ADT node in human-readable form. It uses a simple indentation algorithm
// for improved readability and diffing.
//
package debug
import (
"fmt"
"cuelang.org/go/cue/literal"
"cuelang.org/go/internal/core/adt"
)
type compactPrinter struct {
printer
}
func (w *compactPrinter) node(n adt.Node) {
switch x := n.(type) {
case *adt.Vertex:
if x.BaseValue == nil || (w.cfg.Raw && !x.IsData()) {
for i, c := range x.Conjuncts {
if i > 0 {
w.string(" & ")
}
w.node(c.Expr())
}
return
}
switch v := x.BaseValue.(type) {
case *adt.StructMarker:
w.string("{")
for i, a := range x.Arcs {
if i > 0 {
w.string(",")
}
w.label(a.Label)
w.string(":")
w.node(a)
}
w.string("}")
case *adt.ListMarker:
w.string("[")
for i, a := range x.Arcs {
if i > 0 {
w.string(",")
}
w.node(a)
}
w.string("]")
case adt.Value:
w.node(v)
}
case *adt.StructMarker:
w.string("struct")
case *adt.ListMarker:
w.string("list")
case *adt.StructLit:
w.string("{")
for i, d := range x.Decls {
if i > 0 {
w.string(",")
}
w.node(d)
}
w.string("}")
case *adt.ListLit:
w.string("[")
for i, d := range x.Elems {
if i > 0 {
w.string(",")
}
w.node(d)
}
w.string("]")
case *adt.Field:
s := w.labelString(x.Label)
w.string(s)
w.string(":")
w.node(x.Value)
case *adt.OptionalField:
s := w.labelString(x.Label)
w.string(s)
w.string("?:")
w.node(x.Value)
case *adt.BulkOptionalField:
w.string("[")
w.node(x.Filter)
w.string("]:")
w.node(x.Value)
case *adt.DynamicField:
w.node(x.Key)
if x.IsOptional() {
w.string("?")
}
w.string(":")
w.node(x.Value)
case *adt.Ellipsis:
w.string("...")
if x.Value != nil {
w.node(x.Value)
}
case *adt.Bottom:
w.string(`_|_`)
if x.Err != nil {
w.string("(")
w.string(x.Err.Error())
w.string(")")
}
case *adt.Null:
w.string("null")
case *adt.Bool:
fmt.Fprint(w, x.B)
case *adt.Num:
fmt.Fprint(w, &x.X)
case *adt.String:
w.string(literal.String.Quote(x.Str))
case *adt.Bytes:
w.string(literal.Bytes.Quote(string(x.B)))
case *adt.Top:
w.string("_")
case *adt.BasicType:
fmt.Fprint(w, x.K)
case *adt.BoundExpr:
fmt.Fprint(w, x.Op)
w.node(x.Expr)
case *adt.BoundValue:
fmt.Fprint(w, x.Op)
w.node(x.Value)
case *adt.NodeLink:
w.string(openTuple)
for i, f := range x.Node.Path() {
if i > 0 {
w.string(".")
}
w.label(f)
}
w.string(closeTuple)
case *adt.FieldReference:
w.label(x.Label)
case *adt.LabelReference:
if x.Src == nil {
w.string("LABEL")
} else {
w.string(x.Src.Name)
}
case *adt.DynamicReference:
w.node(x.Label)
case *adt.ImportReference:
w.label(x.ImportPath)
case *adt.LetReference:
w.ident(x.Label)
case *adt.SelectorExpr:
w.node(x.X)
w.string(".")
w.label(x.Sel)
case *adt.IndexExpr:
w.node(x.X)
w.string("[")
w.node(x.Index)
w.string("]")
case *adt.SliceExpr:
w.node(x.X)
w.string("[")
if x.Lo != nil {
w.node(x.Lo)
}
w.string(":")
if x.Hi != nil {
w.node(x.Hi)
}
if x.Stride != nil {
w.string(":")
w.node(x.Stride)
}
w.string("]")
case *adt.Interpolation:
w.interpolation(x)
case *adt.UnaryExpr:
fmt.Fprint(w, x.Op)
w.node(x.X)
case *adt.BinaryExpr:
w.string("(")
w.node(x.X)
fmt.Fprint(w, " ", x.Op, " ")
w.node(x.Y)
w.string(")")
case *adt.CallExpr:
w.node(x.Fun)
w.string("(")
for i, a := range x.Args {
if i > 0 {
w.string(", ")
}
w.node(a)
}
w.string(")")
case *adt.Builtin:
if x.Package != 0 {
w.label(x.Package)
w.string(".")
}
w.string(x.Name)
case *adt.BuiltinValidator:
w.node(x.Builtin)
w.string("(")
for i, a := range x.Args {
if i > 0 {
w.string(", ")
}
w.node(a)
}
w.string(")")
case *adt.DisjunctionExpr:
w.string("(")
for i, a := range x.Values {
if i > 0 {
w.string("|")
}
// Disjunct
if a.Default {
w.string("*")
}
w.node(a.Val)
}
w.string(")")
case *adt.Conjunction:
for i, c := range x.Values {
if i > 0 {
w.string(" & ")
}
w.node(c)
}
case *adt.Disjunction:
for i, c := range x.Values {
if i > 0 {
w.string(" | ")
}
if i < x.NumDefaults {
w.string("*")
}
w.node(c)
}
case *adt.ForClause:
w.string("for ")
w.ident(x.Key)
w.string(", ")
w.ident(x.Value)
w.string(" in ")
w.node(x.Src)
w.string(" ")
w.node(x.Dst)
case *adt.IfClause:
w.string("if ")
w.node(x.Condition)
w.string(" ")
w.node(x.Dst)
case *adt.LetClause:
w.string("let ")
w.ident(x.Label)
w.string(" = ")
w.node(x.Expr)
w.string(" ")
w.node(x.Dst)
case *adt.ValueClause:
w.node(x.StructLit)
default:
panic(fmt.Sprintf("unknown type %T", x))
}
}