blob: 6bcd68064d4c2193587d64888f0e45e2664a1e80 [file] [log] [blame]
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +02001// Copyright 2020 CUE Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// Package debug prints a given ADT node.
16//
17// Note that the result is not valid CUE, but instead prints the internals
18// of an ADT node in human-readable form. It uses a simple indentation algorithm
19// for improved readability and diffing.
20//
21package debug
22
23import (
24 "fmt"
25 "io"
26 "strconv"
27 "strings"
28
29 "cuelang.org/go/cue/errors"
Marcel van Lohuizenc8860942020-10-01 12:42:56 +020030 "cuelang.org/go/cue/literal"
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +020031 "cuelang.org/go/internal"
32 "cuelang.org/go/internal/core/adt"
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +020033)
34
35const (
36 openTuple = "\u3008"
37 closeTuple = "\u3009"
38)
39
40type Config struct {
Marcel van Lohuizen6be2b4f2020-06-28 11:32:33 +020041 Cwd string
42 Compact bool
43 Raw bool
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +020044}
45
46func WriteNode(w io.Writer, i adt.StringIndexer, n adt.Node, config *Config) {
47 if config == nil {
48 config = &Config{}
49 }
50 p := printer{Writer: w, index: i, cfg: config}
Marcel van Lohuizen6be2b4f2020-06-28 11:32:33 +020051 if config.Compact {
52 p := compactPrinter{p}
53 p.node(n)
54 } else {
55 p.node(n)
56 }
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +020057}
58
59func NodeString(i adt.StringIndexer, n adt.Node, config *Config) string {
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +020060 b := &strings.Builder{}
Marcel van Lohuizen6be2b4f2020-06-28 11:32:33 +020061 WriteNode(b, i, n, config)
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +020062 return b.String()
63}
64
65type printer struct {
66 io.Writer
67 index adt.StringIndexer
68 indent string
69 cfg *Config
Marcel van Lohuizen0cfe4112020-06-27 15:01:34 +020070
71 // modes:
72 // - show vertex
73 // - show original conjuncts
74 // - show unevaluated
75 // - auto
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +020076}
77
78func (w *printer) string(s string) {
79 s = strings.Replace(s, "\n", "\n"+w.indent, -1)
80 _, _ = io.WriteString(w, s)
81}
82
83func (w *printer) label(f adt.Feature) {
84 w.string(w.labelString(f))
85}
86
Marcel van Lohuizen63594ef2020-12-02 11:15:08 +010087func (w *printer) ident(f adt.Feature) {
88 w.string(f.IdentString(w.index))
89}
90
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +020091// TODO: fold into label once :: is no longer supported.
92func (w *printer) labelString(f adt.Feature) string {
Marcel van Lohuizenb4aa96d2020-10-04 18:09:37 +020093 if f.IsHidden() {
94 ident := f.IdentString(w.index)
95 if pkgName := f.PkgID(w.index); pkgName != "main" {
96 ident = fmt.Sprintf("%s(%s)", ident, pkgName)
97 }
98 return ident
99 }
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +0200100 return f.SelectorString(w.index)
101}
102
103func (w *printer) shortError(errs errors.Error) {
104 for {
105 msg, args := errs.Msg()
106 fmt.Fprintf(w, msg, args...)
107
Marcel van Lohuizen03abe872020-11-18 11:44:04 +0100108 err := errors.Unwrap(errs)
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +0200109 if err == nil {
110 break
111 }
112
113 if errs, _ = err.(errors.Error); errs != nil {
114 w.string(err.Error())
115 break
116 }
117 }
118}
119
Marcel van Lohuizen30ca0622020-08-22 14:07:59 +0200120func (w *printer) interpolation(x *adt.Interpolation) {
121 quote := `"`
122 if x.K == adt.BytesKind {
123 quote = `'`
124 }
125 w.string(quote)
126 for i := 0; i < len(x.Parts); i += 2 {
127 switch x.K {
128 case adt.StringKind:
129 if s, ok := x.Parts[i].(*adt.String); ok {
130 w.string(s.Str)
131 } else {
132 w.string("<bad string>")
133 }
134 case adt.BytesKind:
135 if s, ok := x.Parts[i].(*adt.Bytes); ok {
136 _, _ = w.Write(s.B)
137 } else {
138 w.string("<bad bytes>")
139 }
140 }
141 if i+1 < len(x.Parts) {
142 w.string(`\(`)
143 w.node(x.Parts[i+1])
144 w.string(`)`)
145 }
146 }
147 w.string(quote)
148}
149
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +0200150func (w *printer) node(n adt.Node) {
151 switch x := n.(type) {
152 case *adt.Vertex:
153 var kind adt.Kind
Marcel van Lohuizen41afc872020-11-26 20:20:58 +0100154 if x.BaseValue != nil {
155 kind = x.BaseValue.Kind()
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +0200156 }
157
158 kindStr := kind.String()
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200159
160 // TODO: replace with showing full closedness data.
161 if x.IsClosed(nil) {
162 if kind == adt.ListKind || kind == adt.StructKind {
163 kindStr = "#" + kindStr
164 }
165 }
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +0200166
167 fmt.Fprintf(w, "(%s){", kindStr)
168
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +0200169 saved := w.indent
170 w.indent += " "
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200171 defer func() { w.indent = saved }()
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +0200172
Marcel van Lohuizen41afc872020-11-26 20:20:58 +0100173 switch v := x.BaseValue.(type) {
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200174 case nil:
175 case *adt.Bottom:
176 // TODO: reuse bottom.
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +0200177 saved := w.indent
178 w.indent += "// "
179 w.string("\n")
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200180 fmt.Fprintf(w, "[%v]", v.Code)
181 if !v.ChildError {
182 msg := errors.Details(v.Err, &errors.Config{
183 Cwd: w.cfg.Cwd,
184 ToSlash: true,
185 })
186 msg = strings.TrimSpace(msg)
187 if msg != "" {
188 w.string(" ")
189 w.string(msg)
190 }
191 }
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +0200192 w.indent = saved
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200193
194 case *adt.StructMarker, *adt.ListMarker:
195 // if len(x.Arcs) == 0 {
196 // // w.string("}")
197 // // return
198 // }
199
Marcel van Lohuizen08a16522020-11-26 19:00:03 +0100200 case adt.Value:
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200201 if len(x.Arcs) == 0 {
202 w.string(" ")
Marcel van Lohuizen08a16522020-11-26 19:00:03 +0100203 w.node(v)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200204 w.string(" }")
205 return
206 }
207 w.string("\n")
Marcel van Lohuizen08a16522020-11-26 19:00:03 +0100208 w.node(v)
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +0200209 }
210
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200211 for _, a := range x.Arcs {
212 w.string("\n")
213 w.label(a.Label)
214 w.string(": ")
215 w.node(a)
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +0200216 }
217
Marcel van Lohuizen41afc872020-11-26 20:20:58 +0100218 if x.BaseValue == nil {
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +0200219 w.indent += "// "
220 w.string("// ")
221 for i, c := range x.Conjuncts {
222 if i > 0 {
223 w.string(" & ")
224 }
225 w.node(c.Expr()) // TODO: also include env?
226 }
227 }
228
229 w.indent = saved
230 w.string("\n")
231 w.string("}")
232
233 case *adt.StructMarker:
234 w.string("struct")
235
236 case *adt.ListMarker:
237 w.string("list")
238
239 case *adt.StructLit:
240 if len(x.Decls) == 0 {
241 w.string("{}")
242 break
243 }
244 w.string("{")
245 w.indent += " "
246 for _, d := range x.Decls {
247 w.string("\n")
248 w.node(d)
249 }
250 w.indent = w.indent[:len(w.indent)-2]
251 w.string("\n}")
252
253 case *adt.ListLit:
254 if len(x.Elems) == 0 {
255 w.string("[]")
256 break
257 }
258 w.string("[")
259 w.indent += " "
260 for _, d := range x.Elems {
261 w.string("\n")
262 w.node(d)
263 w.string(",")
264 }
265 w.indent = w.indent[:len(w.indent)-2]
266 w.string("\n]")
267
268 case *adt.Field:
269 s := w.labelString(x.Label)
270 w.string(s)
271 w.string(":")
272 if x.Label.IsDef() && !internal.IsDef(s) {
273 w.string(":")
274 }
275 w.string(" ")
276 w.node(x.Value)
277
278 case *adt.OptionalField:
279 s := w.labelString(x.Label)
280 w.string(s)
281 w.string("?:")
282 if x.Label.IsDef() && !internal.IsDef(s) {
283 w.string(":")
284 }
285 w.string(" ")
286 w.node(x.Value)
287
288 case *adt.BulkOptionalField:
289 w.string("[")
290 w.node(x.Filter)
291 w.string("]: ")
292 w.node(x.Value)
293
294 case *adt.DynamicField:
295 w.node(x.Key)
296 if x.IsOptional() {
297 w.string("?")
298 }
299 w.string(": ")
300 w.node(x.Value)
301
302 case *adt.Ellipsis:
303 w.string("...")
304 if x.Value != nil {
305 w.node(x.Value)
306 }
307
308 case *adt.Bottom:
309 w.string(`_|_`)
310 if x.Err != nil {
311 w.string("(")
312 w.shortError(x.Err)
313 w.string(")")
314 }
315
316 case *adt.Null:
317 w.string("null")
318
319 case *adt.Bool:
320 fmt.Fprint(w, x.B)
321
322 case *adt.Num:
323 fmt.Fprint(w, &x.X)
324
325 case *adt.String:
Marcel van Lohuizenc8860942020-10-01 12:42:56 +0200326 w.string(literal.String.Quote(x.Str))
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +0200327
328 case *adt.Bytes:
Marcel van Lohuizenc8860942020-10-01 12:42:56 +0200329 w.string(literal.Bytes.Quote(string(x.B)))
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +0200330
331 case *adt.Top:
332 w.string("_")
333
334 case *adt.BasicType:
335 fmt.Fprint(w, x.K)
336
337 case *adt.BoundExpr:
338 fmt.Fprint(w, x.Op)
339 w.node(x.Expr)
340
341 case *adt.BoundValue:
342 fmt.Fprint(w, x.Op)
343 w.node(x.Value)
344
Marcel van Lohuizen0cfe4112020-06-27 15:01:34 +0200345 case *adt.NodeLink:
346 w.string(openTuple)
347 for i, f := range x.Node.Path() {
348 if i > 0 {
349 w.string(".")
350 }
351 w.label(f)
352 }
353 w.string(closeTuple)
354
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +0200355 case *adt.FieldReference:
356 w.string(openTuple)
357 w.string(strconv.Itoa(int(x.UpCount)))
358 w.string(";")
359 w.label(x.Label)
360 w.string(closeTuple)
361
362 case *adt.LabelReference:
363 w.string(openTuple)
364 w.string(strconv.Itoa(int(x.UpCount)))
365 w.string(";-")
366 w.string(closeTuple)
367
368 case *adt.DynamicReference:
369 w.string(openTuple)
370 w.string(strconv.Itoa(int(x.UpCount)))
371 w.string(";(")
372 w.node(x.Label)
373 w.string(")")
374 w.string(closeTuple)
375
376 case *adt.ImportReference:
377 w.string(openTuple + "import;")
378 w.label(x.ImportPath)
379 w.string(closeTuple)
380
381 case *adt.LetReference:
382 w.string(openTuple)
383 w.string(strconv.Itoa(int(x.UpCount)))
384 w.string(";let ")
Marcel van Lohuizen63594ef2020-12-02 11:15:08 +0100385 w.ident(x.Label)
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +0200386 w.string(closeTuple)
387
388 case *adt.SelectorExpr:
389 w.node(x.X)
390 w.string(".")
391 w.label(x.Sel)
392
393 case *adt.IndexExpr:
394 w.node(x.X)
395 w.string("[")
396 w.node(x.Index)
397 w.string("]")
398
399 case *adt.SliceExpr:
400 w.node(x.X)
401 w.string("[")
402 if x.Lo != nil {
403 w.node(x.Lo)
404 }
405 w.string(":")
406 if x.Hi != nil {
407 w.node(x.Hi)
408 }
409 if x.Stride != nil {
410 w.string(":")
411 w.node(x.Stride)
412 }
413 w.string("]")
414
415 case *adt.Interpolation:
Marcel van Lohuizen30ca0622020-08-22 14:07:59 +0200416 w.interpolation(x)
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +0200417
418 case *adt.UnaryExpr:
419 fmt.Fprint(w, x.Op)
420 w.node(x.X)
421
422 case *adt.BinaryExpr:
423 w.string("(")
424 w.node(x.X)
425 fmt.Fprint(w, " ", x.Op, " ")
426 w.node(x.Y)
427 w.string(")")
428
429 case *adt.CallExpr:
430 w.node(x.Fun)
431 w.string("(")
432 for i, a := range x.Args {
433 if i > 0 {
434 w.string(", ")
435 }
436 w.node(a)
437 }
438 w.string(")")
439
Marcel van Lohuizen0cfe4112020-06-27 15:01:34 +0200440 case *adt.Builtin:
441 if x.Package != 0 {
442 w.label(x.Package)
443 w.string(".")
444 }
445 w.string(x.Name)
446
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +0200447 case *adt.BuiltinValidator:
Marcel van Lohuizen0cfe4112020-06-27 15:01:34 +0200448 w.node(x.Builtin)
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +0200449 w.string("(")
450 for i, a := range x.Args {
451 if i > 0 {
452 w.string(", ")
453 }
454 w.node(a)
455 }
456 w.string(")")
457
458 case *adt.DisjunctionExpr:
459 w.string("(")
460 for i, a := range x.Values {
461 if i > 0 {
462 w.string("|")
463 }
464 // Disjunct
465 if a.Default {
466 w.string("*")
467 }
468 w.node(a.Val)
469 }
470 w.string(")")
471
472 case *adt.Conjunction:
473 w.string("&(")
474 for i, c := range x.Values {
475 if i > 0 {
476 w.string(", ")
477 }
478 w.node(c)
479 }
480 w.string(")")
481
482 case *adt.Disjunction:
483 w.string("|(")
484 for i, c := range x.Values {
485 if i > 0 {
486 w.string(", ")
487 }
488 if i < x.NumDefaults {
489 w.string("*")
490 }
491 w.node(c)
492 }
493 w.string(")")
494
495 case *adt.ForClause:
496 w.string("for ")
Marcel van Lohuizen63594ef2020-12-02 11:15:08 +0100497 w.ident(x.Key)
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +0200498 w.string(", ")
Marcel van Lohuizen63594ef2020-12-02 11:15:08 +0100499 w.ident(x.Value)
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +0200500 w.string(" in ")
501 w.node(x.Src)
502 w.string(" ")
503 w.node(x.Dst)
504
505 case *adt.IfClause:
506 w.string("if ")
507 w.node(x.Condition)
508 w.string(" ")
509 w.node(x.Dst)
510
511 case *adt.LetClause:
512 w.string("let ")
Marcel van Lohuizen63594ef2020-12-02 11:15:08 +0100513 w.ident(x.Label)
Marcel van Lohuizen1f42c812020-05-01 16:00:06 +0200514 w.string(" = ")
515 w.node(x.Expr)
516 w.string(" ")
517 w.node(x.Dst)
518
519 case *adt.ValueClause:
520 w.node(x.StructLit)
521
522 default:
523 panic(fmt.Sprintf("unknown type %T", x))
524 }
525}