Merge "cmd/cue/cmd: use format for eval"
diff --git a/cmd/cue/cmd/eval.go b/cmd/cue/cmd/eval.go
index 1e58f14..81351ba 100644
--- a/cmd/cue/cmd/eval.go
+++ b/cmd/cue/cmd/eval.go
@@ -16,11 +16,7 @@
import (
"fmt"
- "io"
- "strings"
- "text/tabwriter"
- "cuelang.org/go/cue"
"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/format"
"cuelang.org/go/cue/parser"
@@ -61,19 +57,22 @@
exprs = append(exprs, expr)
}
- tw := tabwriter.NewWriter(cmd.OutOrStdout(), 0, 0, 1, ' ', 0)
- defer tw.Flush()
+ w := cmd.OutOrStdout()
+
for _, inst := range instances {
// TODO: use ImportPath or some other sanitized path.
- fmt.Fprintf(cmd.OutOrStdout(), "// %s\n", inst.Dir)
- p := evalPrinter{w: tw}
+ fmt.Fprintf(w, "// %s\n", inst.Dir)
+ opts := []format.Option{
+ format.UseSpaces(4),
+ format.TabIndent(false),
+ }
if exprs == nil {
- p.print(inst.Value())
- fmt.Fprintln(tw)
+ format.Node(w, inst.Value().Syntax(), opts...)
+ fmt.Fprintln(w)
}
for _, e := range exprs {
- p.print(inst.Eval(e))
- fmt.Fprintln(tw)
+ format.Node(w, inst.Eval(e).Syntax(), opts...)
+ fmt.Fprintln(w)
}
}
return nil
@@ -90,102 +89,3 @@
var (
expressions *[]string
)
-
-type evalPrinter struct {
- w io.Writer
- fset *token.FileSet
- indent int
- newline bool
- formfeed bool
-}
-
-type ws byte
-
-const (
- unindent = -1
- indent = 1
- newline ws = '\n'
- vtab ws = '\v'
- space ws = ' '
-
- // maxDiffLen is the maximum different in length for object keys for which
- // to still align keys and values.
- maxDiffLen = 5
-)
-
-func (p *evalPrinter) print(args ...interface{}) {
- for _, a := range args {
- if d, ok := a.(int); ok {
- p.indent += d
- continue
- }
- if p.newline {
- nl := '\n'
- if p.formfeed {
- nl = '\f'
- }
- p.w.Write([]byte{byte(nl)})
- fmt.Fprint(p.w, strings.Repeat(" ", int(p.indent)))
- p.newline = false
- }
- switch v := a.(type) {
- case ws:
- switch v {
- case newline:
- p.newline = true
- default:
- p.w.Write([]byte{byte(v)})
- }
- case string:
- fmt.Fprint(p.w, v)
- case cue.Value:
- switch v.Kind() {
- case cue.StructKind:
- iter, err := v.AllFields()
- must(err)
- lastLen := 0
- p.print("{", indent, newline)
- for iter.Next() {
- value := iter.Value()
- key := iter.Label()
- newLen := len([]rune(key)) // TODO: measure cluster length.
- if lastLen > 0 && abs(lastLen, newLen) > maxDiffLen {
- p.formfeed = true
- } else {
- k := value.Kind()
- p.formfeed = k == cue.StructKind || k == cue.ListKind
- }
- p.print(key, ":", vtab, value, newline)
- p.formfeed = false
- lastLen = newLen
- }
- p.print(unindent, "}")
- case cue.ListKind:
- list, err := v.List()
- must(err)
- p.print("[", indent, newline)
- for list.Next() {
- p.print(list.Value(), newline)
- }
- p.print(unindent, "]")
- default:
- format.Node(p.w, v.Syntax())
- }
- }
- }
-}
-
-func abs(a, b int) int {
- a -= b
- if a < 0 {
- return -a
- }
- return a
-}
-
-func max(a, b int) int {
- if a > b {
- return a
- }
- return b
-}
diff --git a/cue/export.go b/cue/export.go
index 3366d9b..4b18225 100644
--- a/cue/export.go
+++ b/cue/export.go
@@ -18,27 +18,50 @@
"fmt"
"strconv"
"strings"
+ "unicode"
"unicode/utf8"
"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/token"
)
-func export(ctx *context, v value) ast.Expr {
- e := exporter{ctx}
+type exportMode int
+
+const (
+ exportRaw exportMode = iota
+ exportEval
+)
+
+func export(ctx *context, v value, m exportMode) ast.Expr {
+ e := exporter{ctx, m}
return e.expr(v)
}
type exporter struct {
- ctx *context
+ ctx *context
+ mode exportMode
}
-func (p *exporter) label(f label) *ast.Ident {
+func (p *exporter) label(f label) ast.Label {
orig := p.ctx.labelStr(f)
str := strconv.Quote(orig)
- if len(orig)+2 == len(str) {
- str = str[1 : len(str)-1]
+ if len(orig)+2 < len(str) {
+ return &ast.BasicLit{Value: str}
}
+ for i, r := range orig {
+ if unicode.IsLetter(r) || r == '_' {
+ continue
+ }
+ if i > 0 && unicode.IsDigit(r) {
+ continue
+ }
+ return &ast.BasicLit{Value: str}
+ }
+ return &ast.Ident{Name: orig}
+}
+
+func (p *exporter) identifier(f label) *ast.Ident {
+ str := p.ctx.labelStr(f)
return &ast.Ident{Name: str}
}
@@ -50,12 +73,12 @@
switch x := v.(type) {
case *feed:
feed := &ast.ForClause{
- Value: p.label(x.fn.params.arcs[1].feature),
+ Value: p.identifier(x.fn.params.arcs[1].feature),
Source: p.expr(x.source),
}
key := x.fn.params.arcs[0]
if p.ctx.labelStr(key.feature) != "_" {
- feed.Key = p.label(key.feature)
+ feed.Key = p.identifier(key.feature)
}
return feed, x.fn.value.(yielder)
@@ -66,6 +89,10 @@
}
func (p *exporter) expr(v value) ast.Expr {
+ if p.mode == exportEval {
+ v = v.evalPartial(p.ctx)
+ }
+
// TODO: also add position information.
switch x := v.(type) {
case *builtin:
@@ -75,9 +102,9 @@
case *selectorExpr:
n := p.expr(x.x)
if n == nil {
- return p.label(x.feature)
+ return p.identifier(x.feature)
}
- return &ast.SelectorExpr{X: n, Sel: p.label(x.feature)}
+ return &ast.SelectorExpr{X: n, Sel: p.identifier(x.feature)}
case *indexExpr:
return &ast.IndexExpr{X: p.expr(x.x), Index: p.expr(x.index)}
case *sliceExpr:
@@ -130,6 +157,9 @@
case *structLit:
obj := &ast.StructLit{}
+ if p.mode == exportEval {
+ x = x.expandFields(p.ctx)
+ }
if x.emit != nil {
obj.Elts = append(obj.Elts, &ast.EmitDecl{Expr: p.expr(x.emit)})
}
@@ -144,8 +174,14 @@
next := c.clauses
for {
if yield, ok := next.(*yield); ok {
+ l := p.expr(yield.key)
+ label, ok := l.(ast.Label)
+ if !ok {
+ // TODO: add an invalid field instead?
+ continue
+ }
f := &ast.Field{
- Label: p.expr(yield.key).(ast.Label),
+ Label: label,
Value: p.expr(yield.value),
}
var decl ast.Decl = f
diff --git a/cue/export_test.go b/cue/export_test.go
index 2673305..7578f92 100644
--- a/cue/export_test.go
+++ b/cue/export_test.go
@@ -138,12 +138,12 @@
}`),
}, {
raw: true,
- in: `{ a: [1, 2], b: { "\(k)": v for k, v in a if a > 1 } }`,
+ in: `{ a: [1, 2], b: { "\(k)": v for k, v in a if v > 1 } }`,
out: unindent(`
{
a: [1, 2]
b: {
- "\(k)": v for k, v in a if a > 1
+ "\(k)": v for k, v in a if v > 1
}
}`),
}, {
@@ -186,7 +186,7 @@
v := newValueRoot(ctx, n)
buf := &bytes.Buffer{}
- err := format.Node(buf, export(ctx, v.eval(ctx)))
+ err := format.Node(buf, export(ctx, v.eval(ctx), exportRaw))
if err != nil {
log.Fatal(err)
}
diff --git a/cue/types.go b/cue/types.go
index 7cecd8c..d12f805 100644
--- a/cue/types.go
+++ b/cue/types.go
@@ -592,7 +592,7 @@
return nil
}
ctx := v.ctx()
- return export(ctx, v.eval(ctx))
+ return export(ctx, v.eval(ctx), exportEval)
}
// Decode initializes x with Value v. If x is a struct, it will validate the
diff --git a/cue/value.go b/cue/value.go
index 897af40..5c34b96 100644
--- a/cue/value.go
+++ b/cue/value.go
@@ -705,8 +705,10 @@
// TODO(perf): improve big O
arcs := make([]arc, 0, len(x.arcs)+len(newArcs))
arcs = append(arcs, x.arcs...)
+ orig := x
x = &structLit{x.baseValue, emit, template, nil, arcs, nil}
x.expanded = x
+ orig.expanded = x
outer:
for _, na := range newArcs {