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

Commit

Permalink
internal/core/export: initial commit
Browse files Browse the repository at this point in the history
Change-Id: Ib388135cc653bdb21d8bc72bea0983df429ec9c2
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/6504
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
  • Loading branch information
mpvl committed Jul 19, 2020
1 parent 0cfe411 commit 0d12c33
Show file tree
Hide file tree
Showing 16 changed files with 2,091 additions and 0 deletions.
213 changes: 213 additions & 0 deletions internal/core/export/bounds.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
// 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 export

import (
"cuelang.org/go/cue/ast"
"cuelang.org/go/internal/core/adt"
"github.com/cockroachdb/apd/v2"
)

// boundSimplifier simplifies bound values into predeclared identifiers, if
// possible.
type boundSimplifier struct {
e *exporter

isInt bool
min *adt.BoundValue
minNum *adt.Num
max *adt.BoundValue
maxNum *adt.Num
}

func (s *boundSimplifier) add(v adt.Value) (used bool) {
switch x := v.(type) {
case *adt.BasicType:
switch x.K & adt.ScalarKinds {
case adt.IntKind:
s.isInt = true
return true
}

case *adt.BoundValue:
if adt.IsConcrete(x.Value) && x.Kind() == adt.IntKind {
s.isInt = true
}
switch x.Op {
case adt.GreaterThanOp:
if n, ok := x.Value.(*adt.Num); ok {
if s.min == nil || s.minNum.X.Cmp(&n.X) != 1 {
s.min = x
s.minNum = n
}
return true
}

case adt.GreaterEqualOp:
if n, ok := x.Value.(*adt.Num); ok {
if s.min == nil || s.minNum.X.Cmp(&n.X) == -1 {
s.min = x
s.minNum = n
}
return true
}

case adt.LessThanOp:
if n, ok := x.Value.(*adt.Num); ok {
if s.max == nil || s.maxNum.X.Cmp(&n.X) != -1 {
s.max = x
s.maxNum = n
}
return true
}

case adt.LessEqualOp:
if n, ok := x.Value.(*adt.Num); ok {
if s.max == nil || s.maxNum.X.Cmp(&n.X) == 1 {
s.max = x
s.maxNum = n
}
return true
}
}
}

return false
}

type builtinRange struct {
typ string
lo *apd.Decimal
hi *apd.Decimal
}

func makeDec(s string) *apd.Decimal {
d, _, err := apd.NewFromString(s)
if err != nil {
panic(err)
}
return d
}

func (s *boundSimplifier) expr(ctx *adt.OpContext) (e ast.Expr) {
if s.min == nil || s.max == nil {
return nil
}
switch {
case s.isInt:
t := s.matchRange(intRanges)
if t != "" {
e = ast.NewIdent(t)
break
}
if sign := s.minNum.X.Sign(); sign == -1 {
e = ast.NewIdent("int")

} else {
e = ast.NewIdent("uint")
if sign == 0 && s.min.Op == adt.GreaterEqualOp {
s.min = nil
break
}
}
fallthrough
default:
t := s.matchRange(floatRanges)
if t != "" {
e = wrapBin(e, ast.NewIdent(t), adt.AndOp)
}
}

if s.min != nil {
e = wrapBin(e, s.e.expr(s.min), adt.AndOp)
}
if s.max != nil {
e = wrapBin(e, s.e.expr(s.max), adt.AndOp)
}
return e
}

func (s *boundSimplifier) matchRange(ranges []builtinRange) (t string) {
for _, r := range ranges {
if !s.minNum.X.IsZero() && s.min.Op == adt.GreaterEqualOp && s.minNum.X.Cmp(r.lo) == 0 {
switch s.maxNum.X.Cmp(r.hi) {
case 0:
if s.max.Op == adt.LessEqualOp {
s.max = nil
}
s.min = nil
return r.typ
case -1:
if !s.minNum.X.IsZero() {
s.min = nil
return r.typ
}
case 1:
}
} else if s.max.Op == adt.LessEqualOp && s.maxNum.X.Cmp(r.hi) == 0 {
switch s.minNum.X.Cmp(r.lo) {
case -1:
case 0:
if s.min.Op == adt.GreaterEqualOp {
s.min = nil
}
fallthrough
case 1:
s.max = nil
return r.typ
}
}
}
return ""
}

var intRanges = []builtinRange{
{"int8", makeDec("-128"), makeDec("127")},
{"int16", makeDec("-32768"), makeDec("32767")},
{"int32", makeDec("-2147483648"), makeDec("2147483647")},
{"int64", makeDec("-9223372036854775808"), makeDec("9223372036854775807")},
{"int128", makeDec("-170141183460469231731687303715884105728"),
makeDec("170141183460469231731687303715884105727")},

{"uint8", makeDec("0"), makeDec("255")},
{"uint16", makeDec("0"), makeDec("65535")},
{"uint32", makeDec("0"), makeDec("4294967295")},
{"uint64", makeDec("0"), makeDec("18446744073709551615")},
{"uint128", makeDec("0"), makeDec("340282366920938463463374607431768211455")},

// {"rune", makeDec("0"), makeDec(strconv.Itoa(0x10FFFF))},
}

var floatRanges = []builtinRange{
// 2**127 * (2**24 - 1) / 2**23
{"float32",
makeDec("-3.40282346638528859811704183484516925440e+38"),
makeDec("3.40282346638528859811704183484516925440e+38")},

// 2**1023 * (2**53 - 1) / 2**52
{"float64",
makeDec("-1.797693134862315708145274237317043567981e+308"),
makeDec("1.797693134862315708145274237317043567981e+308")},
}

func wrapBin(a, b ast.Expr, op adt.Op) ast.Expr {
if a == nil {
return b
}
if b == nil {
return a
}
return ast.NewBinExpr(op.Token(), a, b)
}
184 changes: 184 additions & 0 deletions internal/core/export/export.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
// 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 export

import (
"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/ast/astutil"
"cuelang.org/go/cue/errors"
"cuelang.org/go/internal/core/adt"
"cuelang.org/go/internal/core/eval"
)

type Profile struct {
Simplify bool

// TODO:
// IncludeDocs
}

var Simplified = &Profile{
Simplify: true,
}

var Raw = &Profile{}

// Concrete

// Def exports v as a definition.
func Def(r adt.Runtime, v *adt.Vertex) (*ast.File, errors.Error) {
p := Profile{}
return p.Def(r, v)
}

// Def exports v as a definition.
func (p *Profile) Def(r adt.Runtime, v *adt.Vertex) (*ast.File, errors.Error) {
e := newExporter(p, r, v)
expr := e.expr(v)
return e.toFile(expr)
}

// // TODO: remove: must be able to fall back to arcs if there are no
// // conjuncts.
// func Conjuncts(conjuncts ...adt.Conjunct) (*ast.File, errors.Error) {
// var e Exporter
// // for now just collect and turn into an big conjunction.
// var a []ast.Expr
// for _, c := range conjuncts {
// a = append(a, e.expr(c.Expr()))
// }
// return e.toFile(ast.NewBinExpr(token.AND, a...))
// }

func Expr(r adt.Runtime, n adt.Expr) (ast.Expr, errors.Error) {
return Simplified.Expr(r, n)
}

func (p *Profile) Expr(r adt.Runtime, n adt.Expr) (ast.Expr, errors.Error) {
e := newExporter(p, r, nil)
return e.expr(n), nil
}

func (e *exporter) toFile(x ast.Expr) (*ast.File, errors.Error) {
f := &ast.File{}

switch st := x.(type) {
case nil:
panic("null input")

case *ast.StructLit:
f.Decls = st.Elts

default:
f.Decls = append(f.Decls, &ast.EmbedDecl{Expr: x})
}

if err := astutil.Sanitize(f); err != nil {
err := errors.Promote(err, "export")
return f, errors.Append(e.errs, err)
}

return f, nil
}

// File

func Vertex(r adt.Runtime, n *adt.Vertex) (*ast.File, errors.Error) {
return Simplified.Vertex(r, n)
}

func (p *Profile) Vertex(r adt.Runtime, n *adt.Vertex) (*ast.File, errors.Error) {
e := exporter{
cfg: p,
index: r,
}
v := e.value(n, n.Conjuncts...)

return e.toFile(v)
}

func Value(r adt.Runtime, n adt.Value) (ast.Expr, errors.Error) {
return Simplified.Value(r, n)
}

func (p *Profile) Value(r adt.Runtime, n adt.Value) (ast.Expr, errors.Error) {
e := exporter{
cfg: p,
index: r,
}
v := e.value(n)
return v, e.errs
}

type exporter struct {
cfg *Profile
errs errors.Error
concrete bool

ctx *adt.OpContext

index adt.StringIndexer

// For resolving up references.
stack []frame
}

func newExporter(p *Profile, r adt.Runtime, v *adt.Vertex) *exporter {
return &exporter{
cfg: p,
ctx: eval.NewContext(r, v),
index: r,
}
}

type completeFunc func(scope *ast.StructLit, m adt.Node)

type frame struct {
scope *ast.StructLit
todo []completeFunc

// field to new field
mapped map[adt.Node]ast.Node
}

// func (e *Exporter) pushFrame(d *adt.StructLit, s *ast.StructLit) (saved []frame) {
// saved := e.stack
// e.stack = append(e.stack, frame{scope: s, mapped: map[adt.Node]ast.Node{}})
// return saved
// }

// func (e *Exporter) popFrame(saved []frame) {
// f := e.stack[len(e.stack)-1]

// for _, f

// e.stack = saved
// }

// func (e *Exporter) promise(upCount int32, f completeFunc) {
// e.todo = append(e.todo, f)
// }

func (e *exporter) errf(format string, args ...interface{}) *ast.BottomLit {
err := &exporterError{}
e.errs = errors.Append(e.errs, err)
return &ast.BottomLit{}
}

type errTODO errors.Error

type exporterError struct {
errTODO
}

0 comments on commit 0d12c33

Please sign in to comment.