blob: 31e137fcb70c7f2e98c5a0328c58058907c0c763 [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 adt
// Default returns the default value or itself if there is no default.
func Default(v Value) Value {
switch x := v.(type) {
case *Vertex:
return x.Default()
case *Disjunction:
return x.Default()
default:
return v
}
}
func (d *Disjunction) Default() Value {
switch d.NumDefaults {
case 0:
if d.HasDefaults {
// empty disjunction
return &Bottom{}
}
return d
case 1:
return d.Values[0]
default:
return &Disjunction{
Src: d.Src,
Values: d.Values[:d.NumDefaults],
NumDefaults: 0,
}
}
}
// Default returns the default value or itself if there is no default.
//
// It also closes a list, representing its default value.
func (v *Vertex) Default() *Vertex {
switch d := v.BaseValue.(type) {
default:
return v
case *Disjunction:
var w *Vertex
switch d.NumDefaults {
case 0:
if d.HasDefaults {
v = &Vertex{
Parent: v.Parent,
status: Finalized,
BaseValue: &Bottom{},
}
}
return v
case 1:
w = d.Values[0]
default:
x := *v
x.state = nil
x.BaseValue = &Disjunction{
Src: d.Src,
Values: d.Values[:d.NumDefaults],
NumDefaults: 0,
}
w = &x
}
w.Conjuncts = nil
for _, c := range v.Conjuncts {
// TODO: preserve field information.
expr, _ := stripNonDefaults(c.Expr())
w.Conjuncts = append(w.Conjuncts, MakeRootConjunct(c.Env, expr))
}
return w
case *ListMarker:
m := *d
m.IsOpen = false
w := *v
w.BaseValue = &m
w.state = nil
return &w
}
}
// TODO: this should go: record preexpanded disjunctions in Vertex.
func stripNonDefaults(expr Expr) (r Expr, stripped bool) {
switch x := expr.(type) {
case *DisjunctionExpr:
if !x.HasDefaults {
return x, false
}
d := *x
d.Values = []Disjunct{}
for _, v := range x.Values {
if v.Default {
d.Values = append(d.Values, v)
}
}
if len(d.Values) == 1 {
return d.Values[0].Val, true
}
return &d, true
case *BinaryExpr:
if x.Op != AndOp {
return x, false
}
a, sa := stripNonDefaults(x.X)
b, sb := stripNonDefaults(x.Y)
if sa || sb {
bin := *x
bin.X = a
bin.Y = b
return &bin, true
}
return x, false
default:
return x, false
}
}