blob: 81c73c340f76bb66148e8ad16565cd9a19a32623 [file] [log] [blame]
Marcel van Lohuizencea55b22020-12-18 12:09:05 +01001// Copyright 2020 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 adt
16
17// MatchAndInsert finds matching optional parts for a given Arc and adds its
18// conjuncts. Bulk fields are only applied if no fields match, and additional
19// constraints are only added if neither regular nor bulk fields match.
20func (o *StructInfo) MatchAndInsert(c *OpContext, arc *Vertex) {
21 env := o.Env
22
23 // Match normal fields
24 matched := false
25outer:
26 for _, f := range o.Fields {
27 if f.Label == arc.Label {
28 for _, e := range f.Optional {
29 arc.AddConjunct(MakeConjunct(env, e, o.CloseInfo))
30 }
31 matched = true
32 break outer
33 }
34 }
35
36 if !arc.Label.IsRegular() {
37 return
38 }
39
40 bulkEnv := *env
41 bulkEnv.DynamicLabel = arc.Label
42 bulkEnv.Deref = nil
43 bulkEnv.Cycles = nil
44
45 // match bulk optional fields / pattern properties
46 for _, b := range o.Bulk {
47 // if matched && f.additional {
48 // continue
49 // }
50 if matchBulk(c, env, b, arc.Label) {
51 matched = true
52 arc.AddConjunct(MakeConjunct(&bulkEnv, b, o.CloseInfo))
53 }
54 }
55 if matched {
56 return
57 }
58
59 addEnv := *env
60 addEnv.Deref = nil
61 addEnv.Cycles = nil
62
63 // match others
64 for _, x := range o.Additional {
65 arc.AddConjunct(MakeConjunct(&addEnv, x, o.CloseInfo))
66 }
67}
68
69func matchBulk(c *OpContext, env *Environment, x *BulkOptionalField, f Feature) bool {
70 v, ok := c.Evaluate(env, x.Filter)
71 if !ok {
72 // TODO: handle dynamically
73 return false
74 }
75
76 m := getMatcher(c, env, v)
77 if m == nil {
78 return false
79 }
80 return m.Match(c, env, f)
81}
82
83func getMatcher(c *OpContext, env *Environment, v Value) fieldMatcher {
84 switch f := v.(type) {
85 case *Top:
86 return typeMatcher(TopKind)
87
88 case *BasicType:
89 return typeMatcher(f.K)
90
91 default:
92 return newPatternMatcher(c, env, v)
93 }
94}
95
96type fieldMatcher interface {
97 Match(c *OpContext, env *Environment, f Feature) bool
98}
99
100type typeMatcher Kind
101
102func (m typeMatcher) Match(c *OpContext, env *Environment, f Feature) bool {
103 switch f.Typ() {
104 case StringLabel:
105 return Kind(m)&StringKind != 0
106
107 case IntLabel:
108 return Kind(m)&IntKind != 0
109 }
110 return false
111}
112
113type dynamicMatcher struct {
114 expr Expr
115}
116
117func (m dynamicMatcher) Match(c *OpContext, env *Environment, f Feature) bool {
118 if !f.IsRegular() || !f.IsString() {
119 return false
120 }
121 v, ok := c.Evaluate(env, m.expr)
122 if !ok {
123 return false
124 }
125 s, ok := v.(*String)
126 if !ok {
127 return false
128 }
129 label := f.StringValue(c)
130 return label == s.Str
131}
132
133type patternMatcher Conjunct
134
135func (m patternMatcher) Match(c *OpContext, env *Environment, f Feature) bool {
136 v := Vertex{}
137 v.AddConjunct(Conjunct(m))
138 label := f.ToValue(c)
139 v.AddConjunct(MakeRootConjunct(m.Env, label))
140 v.Finalize(c)
141 b, _ := v.BaseValue.(*Bottom)
142 return b == nil
143}
144
145func newPatternMatcher(ctx *OpContext, env *Environment, x Value) fieldMatcher {
146 c := MakeRootConjunct(env, x)
147 return patternMatcher(c)
148}