Skip to content
This repository has been archived by the owner on Nov 18, 2021. It is now read-only.

Commit

Permalink
cue/ast/astutil: add Expr to File conversion (ToFile)
Browse files Browse the repository at this point in the history
The use of ast.File has been a bit awkward. With the
new Sanitize functionality (this package), however,
it comes in handy.

The idea is to move the entire API to a model where
the user would only care about expressions and let
calls like ToFile and Sanitize care about creating a
well-formed file.

Change-Id: Ib034c1074dc4c8c5513b22beb9c4342bae30e974
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/6303
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
  • Loading branch information
mpvl committed Jun 15, 2020
1 parent 9cf3644 commit 8bfdfe3
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 0 deletions.
38 changes: 38 additions & 0 deletions cue/ast/astutil/file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// 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 astutil

import (
"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/token"
)

// ToFile converts an expression to a File. It will create an import section for
// any of the identifiers in x that refer to an import and will unshadow
// references as appropriate.
func ToFile(x ast.Expr) (*ast.File, error) {
var f *ast.File
if st, ok := x.(*ast.StructLit); ok {
f = &ast.File{Decls: st.Elts}
} else {
ast.SetRelPos(x, token.NoSpace)
f = &ast.File{Decls: []ast.Decl{&ast.EmbedDecl{Expr: x}}}
}

if err := Sanitize(f); err != nil {
return nil, err
}
return f, nil
}
100 changes: 100 additions & 0 deletions cue/ast/astutil/file_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// 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 astutil_test

import (
"strings"
"testing"

"cuelang.org/go/cue"
"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/ast/astutil"
"cuelang.org/go/cue/format"
"cuelang.org/go/cue/token"
"github.com/google/go-cmp/cmp"
)

func TestToFile(t *testing.T) {
mat := ast.NewIdent("math")
mat.Node = ast.NewImport(nil, "math")
pi := ast.NewSel(mat, "Pi")

testCases := []struct {
desc string
expr ast.Expr
want string
}{{
desc: "add import",
expr: ast.NewBinExpr(token.ADD, ast.NewLit(token.INT, "1"), pi),
want: "4.14159265358979323846264",
}, {
desc: "resolve unresolved within struct",
expr: ast.NewStruct(
ast.NewIdent("a"), ast.NewString("foo"),
ast.NewIdent("b"), ast.NewIdent("a"),
),
want: `
a: "foo"
b: "foo"
`,
}, {
desc: "unshadow",
expr: func() ast.Expr {
ident := ast.NewIdent("a")
ref := ast.NewIdent("a")
ref.Node = ident

return ast.NewStruct(
ident, ast.NewString("bar"),
ast.NewIdent("c"), ast.NewStruct(
ast.NewIdent("a"), ast.NewString("foo"),
ast.NewIdent("b"), ref, // refers to outer `a`.
))
}(),
want: `
a: "bar"
c: {
a: "foo"
b: "bar"
}
`,
}}
for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
f, err := astutil.ToFile(tc.expr)
if err != nil {
t.Fatal(err)
}

var r cue.Runtime

inst, err := r.CompileFile(f)
if err != nil {
t.Fatal(err)
}

b, err := format.Node(inst.Value().Syntax())
if err != nil {
t.Fatal(err)
}

got := string(b)
want := strings.TrimLeft(tc.want, "\n")
if got != want {
t.Error(cmp.Diff(got, want))
}
})
}
}

0 comments on commit 8bfdfe3

Please sign in to comment.