1
2
3
4
5 package unify
6
7 import (
8 "fmt"
9 "iter"
10 "reflect"
11 "strings"
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93 type envSet struct {
94 root *envExpr
95 }
96
97 type envExpr struct {
98
99
100
101
102
103
104
105 kind envExprKind
106
107
108 id *ident
109 val *Value
110
111
112
113 operands []*envExpr
114 }
115
116 type envExprKind byte
117
118 const (
119 envZero envExprKind = iota
120 envUnit
121 envProduct
122 envSum
123 envBinding
124 )
125
126 var (
127
128 topEnv = envSet{envExprUnit}
129
130 bottomEnv = envSet{envExprZero}
131
132 envExprZero = &envExpr{kind: envZero}
133 envExprUnit = &envExpr{kind: envUnit}
134 )
135
136
137
138
139
140
141
142 func (e envSet) bind(id *ident, vals ...*Value) envSet {
143 if e.isEmpty() {
144 return bottomEnv
145 }
146
147
148
149
150
151
152 for range e.root.bindings(id) {
153 panic("id " + id.name + " already present in environment")
154 }
155
156
157 bindings := make([]*envExpr, 0, 1)
158 for _, val := range vals {
159 bindings = append(bindings, &envExpr{kind: envBinding, id: id, val: val})
160 }
161
162
163 return envSet{newEnvExprProduct(e.root, newEnvExprSum(bindings...))}
164 }
165
166 func (e envSet) isEmpty() bool {
167 return e.root.kind == envZero
168 }
169
170
171
172 func (e *envExpr) bindings(id *ident) iter.Seq[*envExpr] {
173
174
175 return func(yield func(*envExpr) bool) {
176 var rec func(e *envExpr) bool
177 rec = func(e *envExpr) bool {
178 if e.kind == envBinding && (id == nil || e.id == id) {
179 if !yield(e) {
180 return false
181 }
182 }
183 for _, o := range e.operands {
184 if !rec(o) {
185 return false
186 }
187 }
188 return true
189 }
190 rec(e)
191 }
192 }
193
194
195
196 func newEnvExprProduct(exprs ...*envExpr) *envExpr {
197 factors := make([]*envExpr, 0, 2)
198 for _, expr := range exprs {
199 switch expr.kind {
200 case envZero:
201 return envExprZero
202 case envUnit:
203
204 case envProduct:
205 factors = append(factors, expr.operands...)
206 default:
207 factors = append(factors, expr)
208 }
209 }
210
211 if len(factors) == 0 {
212 return envExprUnit
213 } else if len(factors) == 1 {
214 return factors[0]
215 }
216 return &envExpr{kind: envProduct, operands: factors}
217 }
218
219
220 func newEnvExprSum(exprs ...*envExpr) *envExpr {
221
222
223
224
225 var have smallSet[*envExpr]
226 terms := make([]*envExpr, 0, 2)
227 for _, expr := range exprs {
228 switch expr.kind {
229 case envZero:
230
231 case envSum:
232 for _, expr1 := range expr.operands {
233 if have.Add(expr1) {
234 terms = append(terms, expr1)
235 }
236 }
237 default:
238 if have.Add(expr) {
239 terms = append(terms, expr)
240 }
241 }
242 }
243
244 if len(terms) == 0 {
245 return envExprZero
246 } else if len(terms) == 1 {
247 return terms[0]
248 }
249 return &envExpr{kind: envSum, operands: terms}
250 }
251
252 func crossEnvs(env1, env2 envSet) envSet {
253
254 var ids1 smallSet[*ident]
255 for e := range env1.root.bindings(nil) {
256 ids1.Add(e.id)
257 }
258 for e := range env2.root.bindings(nil) {
259 if ids1.Has(e.id) {
260 panic(fmt.Sprintf("%s bound on both sides of cross-product", e.id.name))
261 }
262 }
263
264 return envSet{newEnvExprProduct(env1.root, env2.root)}
265 }
266
267 func unionEnvs(envs ...envSet) envSet {
268 exprs := make([]*envExpr, len(envs))
269 for i := range envs {
270 exprs[i] = envs[i].root
271 }
272 return envSet{newEnvExprSum(exprs...)}
273 }
274
275
276
277 type envPartition struct {
278 id *ident
279 value *Value
280 env envSet
281 }
282
283
284
285
286
287
288
289
290
291 func (e envSet) partitionBy(id *ident) []envPartition {
292 if e.isEmpty() {
293
294
295 panic("cannot partition empty environment set")
296 }
297
298
299 var seen smallSet[*Value]
300 var parts []envPartition
301 for n := range e.root.bindings(id) {
302 if !seen.Add(n.val) {
303
304 continue
305 }
306
307 parts = append(parts, envPartition{
308 id: id,
309 value: n.val,
310 env: envSet{e.root.substitute(id, n.val)},
311 })
312 }
313
314 return parts
315 }
316
317
318
319 func (e *envExpr) substitute(id *ident, val *Value) *envExpr {
320 switch e.kind {
321 default:
322 panic("bad kind")
323
324 case envZero, envUnit:
325 return e
326
327 case envBinding:
328 if e.id != id {
329 return e
330 } else if e.val != val {
331 return envExprZero
332 } else {
333 return envExprUnit
334 }
335
336 case envProduct, envSum:
337
338
339 var nOperands []*envExpr
340 for i, op := range e.operands {
341 nOp := op.substitute(id, val)
342 if nOperands == nil && op != nOp {
343
344 nOperands = make([]*envExpr, 0, len(e.operands))
345 nOperands = append(nOperands, e.operands[:i]...)
346 }
347 if nOperands != nil {
348 nOperands = append(nOperands, nOp)
349 }
350 }
351 if nOperands == nil {
352
353 return e
354 }
355 if e.kind == envProduct {
356 return newEnvExprProduct(nOperands...)
357 } else {
358 return newEnvExprSum(nOperands...)
359 }
360 }
361 }
362
363
364 type smallSet[T comparable] struct {
365 array [32]T
366 n int
367
368 m map[T]struct{}
369 }
370
371
372 func (s *smallSet[T]) Has(val T) bool {
373 arr := s.array[:s.n]
374 for i := range arr {
375 if arr[i] == val {
376 return true
377 }
378 }
379 _, ok := s.m[val]
380 return ok
381 }
382
383
384
385 func (s *smallSet[T]) Add(val T) bool {
386
387 if s.Has(val) {
388 return false
389 }
390
391
392 if s.n < len(s.array) {
393 s.array[s.n] = val
394 s.n++
395 } else {
396 if s.m == nil {
397 s.m = make(map[T]struct{})
398 }
399 s.m[val] = struct{}{}
400 }
401 return true
402 }
403
404 type ident struct {
405 _ [0]func()
406 name string
407 }
408
409 type Var struct {
410 id *ident
411 }
412
413 func (d Var) Exact() bool {
414
415 panic("Exact called on non-concrete Value")
416 }
417
418 func (d Var) WhyNotExact() string {
419
420 return "WhyNotExact called on non-concrete Value"
421 }
422
423 func (d Var) decode(rv reflect.Value) error {
424 return &inexactError{"var", rv.Type().String()}
425 }
426
427 func (d Var) unify(w *Value, e envSet, swap bool, uf *unifier) (Domain, envSet, error) {
428
429
430
431
432
433
434
435
436 if vd, ok := w.Domain.(Var); ok && d.id == vd.id {
437
438
439
440
441
442 return vd, e, nil
443 }
444
445
446
447
448 var nEnvs []envSet
449 envParts := e.partitionBy(d.id)
450 for i, envPart := range envParts {
451 exit := uf.enterVar(d.id, i)
452
453
454
455 res, e2, err := w.unify(envPart.value, envPart.env, swap, uf)
456 exit.exit()
457 if err != nil {
458 return nil, envSet{}, err
459 }
460 if res.Domain == nil {
461
462 continue
463 }
464 nEnv := e2.bind(d.id, res)
465 nEnvs = append(nEnvs, nEnv)
466 }
467
468 if len(nEnvs) == 0 {
469
470 return nil, bottomEnv, nil
471 }
472
473
474
475 return d, unionEnvs(nEnvs...), nil
476 }
477
478
479 type identPrinter struct {
480 ids map[*ident]string
481 idGen map[string]int
482 }
483
484 func (p *identPrinter) unique(id *ident) string {
485 if p.ids == nil {
486 p.ids = make(map[*ident]string)
487 p.idGen = make(map[string]int)
488 }
489
490 name, ok := p.ids[id]
491 if !ok {
492 gen := p.idGen[id.name]
493 p.idGen[id.name]++
494 if gen == 0 {
495 name = id.name
496 } else {
497 name = fmt.Sprintf("%s#%d", id.name, gen)
498 }
499 p.ids[id] = name
500 }
501
502 return name
503 }
504
505 func (p *identPrinter) slice(ids []*ident) string {
506 var strs []string
507 for _, id := range ids {
508 strs = append(strs, p.unique(id))
509 }
510 return fmt.Sprintf("[%s]", strings.Join(strs, ", "))
511 }
512
View as plain text