1// Copyright 2021 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	"cuelang.org/go/internal/core/adt"
19)
20
21// This file contains query-related code.
22
23// getScopePrefix finds the Vertex that exists in v for the longest prefix of p.
24//
25// It is used to make the parent scopes visible when resolving expressions.
26func getScopePrefix(v Value, p Path) Value {
27	for _, sel := range p.Selectors() {
28		w := v.LookupPath(MakePath(sel))
29		if !w.Exists() {
30			break
31		}
32		v = w
33	}
34	return v
35}
36
37// LookupPath reports the value for path p relative to v.
38func (v Value) LookupPath(p Path) Value {
39	if v.v == nil {
40		return Value{}
41	}
42	n := v.v
43	parent := v.parent_
44	ctx := v.ctx()
45
46outer:
47	for _, sel := range p.path {
48		f := sel.sel.feature(v.idx)
49		for _, a := range n.Arcs {
50			if a.Label == f {
51				parent = linkParent(parent, n, a)
52				n = a
53				continue outer
54			}
55		}
56		if sel.sel.optional() {
57			x := &adt.Vertex{
58				Parent: n,
59				Label:  sel.sel.feature(ctx),
60			}
61			n.MatchAndInsert(ctx, x)
62			if len(x.Conjuncts) > 0 {
63				x.Finalize(ctx)
64				parent = linkParent(parent, n, x)
65				n = x
66				continue
67			}
68		}
69
70		var x *adt.Bottom
71		if err, ok := sel.sel.(pathError); ok {
72			x = &adt.Bottom{Err: err.Error}
73		} else {
74			// TODO: better message.
75			x = mkErr(v.idx, n, adt.NotExistError, "field %q not found", sel.sel)
76		}
77		v := makeValue(v.idx, n, parent)
78		return newErrValue(v, x)
79	}
80	return makeValue(v.idx, n, parent)
81}
82