1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 package unify
54
55 import (
56 "errors"
57 "fmt"
58 "slices"
59 )
60
61
62
63 func Unify(closures ...Closure) (Closure, error) {
64 if len(closures) == 0 {
65 return Closure{topValue, topEnv}, nil
66 }
67
68 var trace *tracer
69 if Debug.UnifyLog != nil || Debug.HTML != nil {
70 trace = &tracer{
71 logw: Debug.UnifyLog,
72 saveTree: Debug.HTML != nil,
73 }
74 }
75
76 unified := closures[0]
77 for _, c := range closures[1:] {
78 var err error
79 uf := newUnifier()
80 uf.tracer = trace
81 e := crossEnvs(unified.env, c.env)
82 unified.val, unified.env, err = unified.val.unify(c.val, e, false, uf)
83 if Debug.HTML != nil {
84 uf.writeHTML(Debug.HTML)
85 }
86 if err != nil {
87 return Closure{}, err
88 }
89 }
90
91 return unified, nil
92 }
93
94 type unifier struct {
95 *tracer
96 }
97
98 func newUnifier() *unifier {
99 return &unifier{}
100 }
101
102
103
104 var errDomains = errors.New("cannot unify domains")
105
106 func (v *Value) unify(w *Value, e envSet, swap bool, uf *unifier) (*Value, envSet, error) {
107 if swap {
108
109
110 v, w = w, v
111 }
112
113 uf.traceUnify(v, w, e)
114
115 d, e2, err := v.unify1(w, e, false, uf)
116 if err == errDomains {
117
118 d, e2, err = w.unify1(v, e, true, uf)
119 if err == errDomains {
120
121 err = fmt.Errorf("cannot unify %T (%s) and %T (%s): kind mismatch", v.Domain, v.PosString(), w.Domain, w.PosString())
122 }
123 }
124 if err != nil {
125 uf.traceDone(nil, envSet{}, err)
126 return nil, envSet{}, err
127 }
128 res := unified(d, v, w)
129 uf.traceDone(res, e2, nil)
130 if d == nil {
131
132 if !e2.isEmpty() {
133 panic("bottom Value has non-bottom environment")
134 }
135 }
136
137 return res, e2, nil
138 }
139
140 func (v *Value) unify1(w *Value, e envSet, swap bool, uf *unifier) (Domain, envSet, error) {
141
142
143 vd, wd := v.Domain, w.Domain
144
145
146 if vd == nil || wd == nil {
147 return nil, bottomEnv, nil
148 }
149
150
151 if _, ok := vd.(Top); ok {
152 return wd, e, nil
153 }
154
155
156 if vd, ok := vd.(Var); ok {
157 return vd.unify(w, e, swap, uf)
158 }
159
160
161 if vd, ok := vd.(Def); ok {
162 if wd, ok := wd.(Def); ok {
163 return vd.unify(wd, e, swap, uf)
164 }
165 }
166 if vd, ok := vd.(Tuple); ok {
167 if wd, ok := wd.(Tuple); ok {
168 return vd.unify(wd, e, swap, uf)
169 }
170 }
171
172
173 if vd, ok := vd.(String); ok {
174 if wd, ok := wd.(String); ok {
175 res := vd.unify(wd)
176 if res == nil {
177 e = bottomEnv
178 }
179 return res, e, nil
180 }
181 }
182
183 return nil, envSet{}, errDomains
184 }
185
186 func (d Def) unify(o Def, e envSet, swap bool, uf *unifier) (Domain, envSet, error) {
187 out := Def{fields: make(map[string]*Value)}
188
189
190 for key, dv := range d.All() {
191 ov, ok := o.fields[key]
192 if !ok {
193
194 out.fields[key] = dv
195 continue
196 }
197 exit := uf.enter("%s", key)
198 res, e2, err := dv.unify(ov, e, swap, uf)
199 exit.exit()
200 if err != nil {
201 return nil, envSet{}, err
202 } else if res.Domain == nil {
203
204 return nil, bottomEnv, nil
205 }
206 out.fields[key] = res
207 e = e2
208 }
209
210
211 for key, dv := range o.All() {
212 if _, ok := d.fields[key]; !ok {
213 out.fields[key] = dv
214 }
215 }
216 return out, e, nil
217 }
218
219 func (v Tuple) unify(w Tuple, e envSet, swap bool, uf *unifier) (Domain, envSet, error) {
220 if v.repeat != nil && w.repeat != nil {
221
222
223 return Tuple{repeat: concat(v.repeat, w.repeat)}, e, nil
224 }
225
226
227 tuples := make([]Tuple, 0, 2)
228 if v.repeat == nil {
229 tuples = append(tuples, v)
230 } else {
231 v2, e2 := v.doRepeat(e, len(w.vs))
232 tuples = append(tuples, v2...)
233 e = e2
234 }
235 if w.repeat == nil {
236 tuples = append(tuples, w)
237 } else {
238 w2, e2 := w.doRepeat(e, len(v.vs))
239 tuples = append(tuples, w2...)
240 e = e2
241 }
242
243
244 out := tuples[0]
245 for _, t := range tuples[1:] {
246 if len(out.vs) != len(t.vs) {
247 uf.logf("tuple length mismatch")
248 return nil, bottomEnv, nil
249 }
250 zs := make([]*Value, len(out.vs))
251 for i, v1 := range out.vs {
252 exit := uf.enter("%d", i)
253 z, e2, err := v1.unify(t.vs[i], e, swap, uf)
254 exit.exit()
255 if err != nil {
256 return nil, envSet{}, err
257 } else if z.Domain == nil {
258 return nil, bottomEnv, nil
259 }
260 zs[i] = z
261 e = e2
262 }
263 out = Tuple{vs: zs}
264 }
265
266 return out, e, nil
267 }
268
269
270
271 func (v Tuple) doRepeat(e envSet, n int) ([]Tuple, envSet) {
272 res := make([]Tuple, len(v.repeat))
273 for i, gen := range v.repeat {
274 res[i].vs = make([]*Value, n)
275 for j := range n {
276 res[i].vs[j], e = gen(e)
277 }
278 }
279 return res, e
280 }
281
282
283
284
285
286 func (v String) unify(w String) Domain {
287
288
289 if v.kind > w.kind {
290 v, w = w, v
291 }
292
293 switch v.kind {
294 case stringRegex:
295 switch w.kind {
296 case stringRegex:
297
298 return String{kind: stringRegex, re: slices.Concat(v.re, w.re)}
299 case stringExact:
300 for _, re := range v.re {
301 if !re.MatchString(w.exact) {
302 return nil
303 }
304 }
305 return w
306 }
307 case stringExact:
308 if v.exact != w.exact {
309 return nil
310 }
311 return v
312 }
313 panic("bad string kind")
314 }
315
316 func concat[T any](s1, s2 []T) []T {
317
318 if len(s1) == 0 {
319 return s2
320 }
321 return append(s1[:len(s1):len(s1)], s2...)
322 }
323
View as plain text