blob: fe8ed523b5dd6e748df662e21b333818e3c1fed5 [file] [log] [blame]
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001// Copyright 2018 The 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
15package cue
16
17import (
18 "sort"
19
20 "cuelang.org/go/cue/token"
21 "golang.org/x/exp/errors"
22 "golang.org/x/exp/errors/fmt"
23)
24
25type errCode int
26
27const (
28 codeNone errCode = iota
29 codeFatal
30 codeNotExist
31 codeTypeError
32 codeIncomplete
33 codeCycle
34)
35
36func isIncomplete(v value) bool {
37 if err, ok := v.(*bottom); ok {
38 return err.code == codeIncomplete
39 }
40 return false
41}
42
43func recoverable(v value) bool {
44 if err, ok := v.(*bottom); ok {
45 switch err.code {
46 case codeFatal,
47 codeCycle: // only recoverable when explicitly handled and discarded
48 return false
49 }
50 }
51 return true
52}
53
54var errNotExists = &bottom{code: codeNotExist, msg: "undefined value"}
55
56func exists(v value) bool {
57 if err, ok := v.(*bottom); ok {
58 return err.code != codeNotExist
59 }
60 return true
61}
62
63// bottom is the bottom of the value lattice. It is subsumed by all values.
64type bottom struct {
65 baseValue
66
67 index *index
68 code errCode
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +020069 exprDepth int
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +010070 value value
71 offendingValue value
72 replacement evaluated // for cycle resolution
73 pos source
74 msg string
75
76 wrapped *bottom
77
78 // TODO: file at which the error was generated in the code.
79 // File positions of where the error occurred.
80}
81
82func (x *bottom) kind() kind { return bottomKind }
83
84func (x *bottom) Position() []token.Position {
85 if x.index != nil && x.index.fset != nil {
86 return appendPositions(nil, x.index.fset, x.pos)
87 }
88 return nil
89}
90
91func appendPositions(pos []token.Position, fset *token.FileSet, src source) []token.Position {
92 if src != nil {
Marcel van Lohuizen46103912019-04-26 22:23:38 +020093 if p := src.Pos(); p != token.NoPos {
94 if p >= sharedOffset {
95 fset = sharedIndex.fset
96 }
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +010097 return append(pos, fset.Position(src.Pos()))
98 }
99 if c := src.computed(); c != nil {
100 pos = appendPositions(pos, fset, c.x)
101 pos = appendPositions(pos, fset, c.y)
102 }
103 }
104 return pos
105}
106
107func (x *bottom) Error() string { return fmt.Sprint(x) }
108
Marcel van Lohuizen58b7c322018-12-28 14:46:39 +0100109func (x *bottom) FormatError(p errors.Printer) error {
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100110 p.Print(x.msg)
111 if p.Detail() && x.index != nil && x.index.fset != nil {
112 locs := appendLocations(nil, x.index.fset, x.pos)
113 sort.Strings(locs)
114 for _, l := range locs {
115 p.Printf("%s\n", l)
116 }
117 }
118 if x.wrapped != nil {
119 return x.wrapped // nil interface
120 }
121 return nil
122}
123
124func appendLocations(locs []string, fset *token.FileSet, src source) []string {
125 if src != nil {
Marcel van Lohuizen46103912019-04-26 22:23:38 +0200126 if p := src.Pos(); p != token.NoPos {
127 if p >= sharedOffset {
128 fset = sharedIndex.fset
129 }
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100130 return append(locs, fset.Position(src.Pos()).String())
131 }
132 if c := src.computed(); c != nil {
133 locs = appendLocations(locs, fset, c.x)
134 locs = appendLocations(locs, fset, c.y)
135 }
136 }
137 return locs
138}
139
140func cycleError(v evaluated) *bottom {
141 if err, ok := v.(*bottom); ok && err.code == codeCycle {
142 return err
143 }
144 return nil
145}
146
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100147func (idx *index) mkErrUnify(src source, a, b evaluated) evaluated {
148 if err := firstBottom(a, b); err != nil {
149 return err
150 }
151 e := binSrc(src.Pos(), opUnify, a, b)
152 // TODO: show string of values and show location of both values.
153 return idx.mkErr(e, "incompatible values &(%s, %s)", a.kind(), b.kind())
154}
155
156func (c *context) mkIncompatible(src source, op op, a, b evaluated) evaluated {
157 if err := firstBottom(a, b); err != nil {
158 return err
159 }
160 e := mkBin(c, src.Pos(), op, a, b)
161 return c.mkErr(e, "unsupported op %s(%s, %s)", op, a.kind(), b.kind())
162}
163
164func (idx *index) mkErr(src source, args ...interface{}) *bottom {
165 e := &bottom{baseValue: src.base(), index: idx, pos: src}
166
167 if v, ok := src.(value); ok {
168 e.value = v
169 }
170 for i, a := range args {
171 switch x := a.(type) {
172 case errCode:
173 e.code = x
174 case *bottom:
175 e.wrapped = x
176 e.offendingValue = x
177 case value:
178 e.offendingValue = x
179 case op:
180 panic("no longer using offending value and op")
181 case string:
182 e.msg += fmt.Sprintf(x, args[i+1:]...)
183 return e
184 }
185 }
186 if e.code == codeNone && e.wrapped != nil {
187 e.code = e.wrapped.code
188 }
189 return e
190}
191
192func isBottom(n value) bool {
193 return n.kind() == bottomKind
194}
195
196func firstBottom(v ...value) evaluated {
197 for _, b := range v {
198 if isBottom(b) {
199 return b.(*bottom)
200 }
201 }
202 return nil
203}
204
205func expectType(idx *index, t kind, n evaluated) value {
206 if isBottom(n) {
207 return n
208 }
209 return idx.mkErr(n, "value should of type %s, found %s", n.kind(), t)
210}
211
212// TODO: consider returning a type or subsuption error for op != opUnify