-
Notifications
You must be signed in to change notification settings - Fork 0
/
register.js
58 lines (57 loc) · 2.06 KB
/
register.js
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
54
55
56
57
58
const logic = require('logicjs')
const unify = logic.unify
logic.unify = function (a, b, frame) {
if (frame===false) return false
a = frame.walk(a)
b = frame.walk(b)
if (logic.is_logic_list(a) && logic.is_logic_list(b)) {
if (a.length === 0) {
if (b.length === 0) return frame
else if (has_type(b[0], 'list_spread'))
return logic.unify(logic.list(...b.slice(1)), logic.list(), logic.unify(b[0].variable, a, frame))
} else if (is_list_spread(a[0])) {
if (
a.length === 1 &&
b.length === 1 &&
is_list_spread(b[0])
)
return logic.unify(a[0].variable, b[0].variable, frame)
else if (a.length === 1)
return logic.unify(a[0].variable, b, frame)
else {
throw new Error('list spread must be at the end of the list')
// TODO if unify could return a stream of frames, there would be several solutions here:
// logic.unify(a.slice(1), b, logic.unify(a[0].variable, logic.list(), frame))
// and
// const part = logic.list(logic.lvar(), ...logic.lvar())
// logic.unify(logic.list(...part, a.slice(1)), b, logic.unify(a[0].variable, part, frame))
// TODO or support spreads not at the end iff there is only one spread in the list
}
} else {
if (b.length === 0) {
return false
} else if (is_list_spread(b[0])) {
return logic.unify(b, a, frame)
} else {
return logic.unify(logic.list(...a.slice(1)), logic.list(...b.slice(1)), logic.unify(a[0], b[0], frame))
}
}
} else return unify(a, b, frame)
}
const lvar = logic.lvar
logic.lvar = function (name) {
const variable = lvar(name)
variable[Symbol.iterator] = function*() {
yield list_spread(variable)
}
return variable
}
const list_spread = logic.list_spread = function (variable) {
return { type: 'list_spread', variable }
}
function has_type(obj, type) {
return (typeof obj==='object') && (typeof obj.type!=='undefined') && obj.type===type
}
const is_list_spread = logic.is_list_spread = function(v) {
return has_type(v, 'list_spread')
}