This repository has been archived by the owner on Nov 15, 2019. It is now read-only.
/
variable.go
117 lines (97 loc) · 2.19 KB
/
variable.go
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
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package term
import . "fmt"
import . "regexp"
import . "github.com/mndrix/golog/util"
var anonCounter <-chan int64
func init() {
// goroutine providing a counter for anonymous variables
c := make(chan int64)
var i int64 = 1000
go func() {
for {
c <- i
i++
}
}()
anonCounter = c
}
// A Prolog logic variable. See ISO §6.1.2(a)
type Variable struct {
Name string
id int64 // uniquely identifiers this variable
}
// Creates a new logic variable with the given name.
func NewVar(name string) *Variable {
// sanity check the variable name's syntax
isCapitalized, err := MatchString(`^[A-Z_]`, name)
maybePanic(err)
if !isCapitalized {
panic("Variable names must start with a capital letter or underscore")
}
// make sure anonymous variables are unique
var i int64
if name == "_" {
i = <-anonCounter
}
return &Variable{
Name: name,
id: i,
}
}
// Id returns a unique identifier for this variable
func (self *Variable) Id() int64 {
return self.id
}
func (self *Variable) Functor() string {
panic("Variables have no Functor()")
}
func (self *Variable) Arity() int {
panic("Variables have no Arity()")
}
func (self *Variable) Arguments() []Term {
panic("Variables have no Arguments()")
}
func (self *Variable) String() string {
if Debugging() && self.Name == "_" {
return self.Indicator()
}
return self.Name
}
func (self *Variable) Type() int {
return VariableType
}
func (self *Variable) Indicator() string {
return Sprintf("_V%d", self.id)
}
func (a *Variable) Unify(e Bindings, b Term) (Bindings, error) {
var aTerm, bTerm Term
// a variable always unifies with itself
if IsVariable(b) {
if a.Indicator() == b.Indicator() {
return e, nil
}
bTerm = e.Resolve_(b.(*Variable))
} else {
bTerm = b
}
// resolve any previous bindings
aTerm = e.Resolve_(a)
// bind unbound variables
if IsVariable(aTerm) {
return e.Bind(aTerm.(*Variable), b)
}
if IsVariable(bTerm) {
return e.Bind(bTerm.(*Variable), a)
}
// otherwise, punt
return aTerm.Unify(e, bTerm)
}
func (self *Variable) ReplaceVariables(env Bindings) Term {
return env.Resolve_(self)
}
func (self *Variable) WithNewId() *Variable {
return &Variable{
Name: self.Name,
id: <-anonCounter,
}
}