blob: c277a6a6dbf543bd4dfa19a507ad498753e21426 [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
17func (c *context) manifest(v value) evaluated {
18 evaluated := v.evalPartial(c)
Marcel van Lohuizen0e2bcd52019-04-03 22:33:14 +020019 if c.noManifest {
20 return evaluated
21 }
Marcel van Lohuizenb134a502019-05-06 11:33:05 +020022outer:
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +010023 for {
Marcel van Lohuizenb134a502019-05-06 11:33:05 +020024 switch x := evaluated.(type) {
25 case *disjunction:
26 evaluated = x.manifest(c)
27
28 case *list:
29 return x.manifest(c)
30
31 default:
32 break outer
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +010033 }
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +010034 }
35 return evaluated
36}
37
38type evaluator struct {
39 ctx *context
40 bottom []*bottom
41}
42
43const (
44 // (fmt, evaluated, orig, gotKind, wantKind)
45 // "invalid [string index] -1 (index must be non-negative)"
46 // "invalid operation: %[1]s (type %[3] does not support indexing)"
47 // msgType = "invalid %s %s (must be type %s)"
48 msgGround = "invalid non-ground value %[1]s (must be concrete %[4]s)"
49)
50
51func newEval(ctx *context, manifest bool) evaluator {
52 return evaluator{ctx: ctx}
53}
54
55func (e *evaluator) hasErr() bool {
56 return len(e.bottom) > 0
57}
58
59func (e *evaluator) mkErr(orig, eval value, code errCode, want kind, desc string, args ...interface{}) (err *bottom) {
60 args = append([]interface{}{
61 eval,
62 code,
63 desc, // format string
64 eval, // 1
65 orig, // 2
66 eval.kind(), // 3
67 want}, // 4
68 args...)
69 for i := 3; i < len(args); i++ {
70 switch v := args[i].(type) {
71 case value:
72 args[i] = debugStr(e.ctx, v)
73 }
74 }
75 err = e.ctx.mkErr(orig, args...)
76 // TODO: maybe replace with more specific type error.
77 for i, old := range e.bottom {
78 if old == eval {
79 e.bottom[i] = err
80 return err
81 }
82 }
83 e.bottom = append(e.bottom, err)
84 return err
85}
86
87func (e *evaluator) eval(v value, want kind, desc string, extraArgs ...interface{}) evaluated {
88 eval := e.ctx.manifest(v)
89
90 if isBottom(eval) {
91 e.bottom = append(e.bottom, eval.(*bottom))
92 return eval
93 }
94 got := eval.kind()
95 if got&want == bottomKind {
96 return e.mkErr(v, eval, codeTypeError, want, desc, extraArgs...)
97 }
98 if !got.isGround() {
99 return e.mkErr(v, eval, codeIncomplete, want, msgGround, extraArgs...)
100 }
101 return eval
102}
103
104func (e *evaluator) evalPartial(v value, want kind, desc string, extraArgs ...interface{}) evaluated {
105 eval := v.evalPartial(e.ctx)
106 if isBottom(eval) {
107 // handle incomplete errors separately?
108 e.bottom = append(e.bottom, eval.(*bottom))
109 return eval
110 }
111 got := eval.kind()
112 if got&want == bottomKind {
113 return e.mkErr(v, eval, codeTypeError, want, desc, extraArgs...)
114 }
115 return eval
116}
117
118func (e *evaluator) evalAllowNil(v value, want kind, desc string, extraArgs ...interface{}) evaluated {
119 if v == nil {
120 return nil
121 }
122 return e.eval(v, want, desc, extraArgs...)
123}
124
125func (e *evaluator) is(v value, want kind, desc string, args ...interface{}) bool {
126 if isBottom(v) {
127 // Even though errors are ground, we treat them as not allowed.
128 return false
129 }
130 got := v.kind()
131 if got&want == bottomKind {
132 e.mkErr(v, v, codeTypeError, want, desc, args...)
133 return false
134 }
135 // groundness must already have been checked.
136 return true
137}
138
139func (e *evaluator) err(v value) evaluated {
140 // if bottom is a fatal (not incomplete) error, return that.
141 // otherwise, try to extract a fatal error from the given value.
142 // otherwise return an incomplete error with the given value as offending.
143 for _, b := range e.bottom {
144 if b.code != codeIncomplete {
145 return b
146 }
147 }
148 return e.ctx.mkErr(v, codeIncomplete, e.bottom[0])
149}