-
Notifications
You must be signed in to change notification settings - Fork 0
/
types.go
255 lines (208 loc) · 5.66 KB
/
types.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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
package wdte
import (
"fmt"
"math/big"
"reflect"
"strings"
)
// A Comparer is a Func that is able to be compared to other
// functions.
type Comparer interface {
// Compare returns two values. The meaning of the first is dependent
// upon the second. If the second is true, then the first indicates
// ordering via the standard negative, positive, and zero results to
// indicate less than, greater than, and equal, respectively. If the
// second is false, then the first indicates only equality, with
// zero still meaning equal, but other values simply meaning unequal.
Compare(other Func) (int, bool)
}
// A Lenner is a Func that has a length, such as arrays and strings.
type Lenner interface {
Len() int
}
// An Atter is a Func that can be indexed, like an array or a string.
type Atter interface {
At(i Func) (Func, error)
}
// A Setter is a Func that can produce a new Func from itself with a
// key-value mapping applied in some way. For example, a scope can
// produce a subscope with a new variable added to it, or an array can
// produce a new array with an index modified.
type Setter interface {
Set(k, v Func) (Func, error)
}
// A Reflector is a Func that can determine if it can be treated as
// the named type or not. For example,
//
// s := wdte.String("example")
// return s.Reflect("string")
//
// returns true.
type Reflector interface {
Reflect(name string) bool
}
// Reflect checks if a Func can be considered to be of a given type.
// If v implements Reflector, v.Reflect(name) is used to check for
// compatability. If not, a simple string comparison is done against
// whatever Go's reflect package claims the short name of the
// underlying type to be.
func Reflect(f Func, name string) bool {
if r, ok := f.(Reflector); ok {
return r.Reflect(name)
}
return reflect.TypeOf(f).Name() == name
}
// A String is a string, as parsed from a string literal. That's about
// it. Like everything else, it's a function. It simply returns itself
// when called.
type String string
func (s String) Call(frame Frame, args ...Func) Func {
// TODO: Use the arguments for something. Probably concatenation.
return s
}
func (s String) Compare(other Func) (int, bool) {
o, ok := other.(String)
if !ok {
return -1, false
}
switch {
case s < o:
return -1, true
case s > o:
return 1, true
}
return 0, true
}
func (s String) Len() int {
return len(s)
}
func (s String) At(index Func) (Func, error) {
i := int(index.(Number))
if (i < 0) || (i >= len(s)) {
return nil, fmt.Errorf("index %v is out of range [0,%v)", i, len(s))
}
return String(s[i]), nil
}
func (s String) Reflect(name string) bool {
return name == "String"
}
// A Number is a number, as parsed from a number literal. That's about
// it. Like everything else, it's a function. It simply returns itself
// when called.
type Number float64
func (n Number) Call(frame Frame, args ...Func) Func {
// TODO: Use the arguments for something, perhaps.
return n
}
func (n Number) Compare(other Func) (int, bool) {
o, ok := other.(Number)
switch {
case !ok:
return -1, false
case n < o:
return -1, true
case n > o:
return 1, true
default:
return 0, true
}
}
func (n Number) String() string {
bn := big.NewFloat(float64(n))
if bn.IsInt() {
return bn.Text('f', -1)
}
return bn.Text('g', 10)
}
func (n Number) Reflect(name string) bool {
return name == "Number"
}
// An Array represents a WDTE array type. It's similar to a Compound,
// but when evaluated, it returns itself with its own members replaced
// with their own evaluations. This allows it to be passed around as a
// value in the same way as strings and numbers.
type Array []Func
func (a Array) Call(frame Frame, args ...Func) Func {
n := make(Array, 0, len(a))
for i := range a {
n = append(n, a[i].Call(frame))
}
return n
}
func (a Array) Len() int {
return len(a)
}
func (a Array) At(index Func) (Func, error) {
i := int(index.(Number))
if (i < 0) || (i >= len(a)) {
return nil, fmt.Errorf("index %v is out of range [0,%v)", i, len(a))
}
return a[i], nil
}
func (a Array) Set(k, v Func) (Func, error) {
i := int(k.(Number))
if (i < 0) || (i >= len(a)) {
return nil, fmt.Errorf("index %v is out of bounds [0,%v]", i, len(a))
}
c := make(Array, len(a))
copy(c, a)
c[i] = v
return c, nil
}
func (a Array) String() string {
var buf strings.Builder
buf.WriteByte('[')
var pre string
for _, f := range a {
buf.WriteString(pre)
fmt.Fprint(&buf, f)
pre = "; "
}
buf.WriteByte(']')
return buf.String()
}
func (a Array) Reflect(name string) bool {
return name == "Array"
}
//func (a Array)Compare(other Func) (int, bool) {
// TODO: Implement this. I'm not sure if it should support ordering
// or not. I'm also not sure if it should call its elements in order
// to get their underlying values. It probably should.
//}
// An Error is returned by any of the built-in functions when they run
// into an error.
type Error struct {
// Err is the error that generated the Error. In a lot of cases,
// this is just a simple error message.
Err error
// Frame is the frame of the function that the error was first
// generated in.
Frame Frame
}
func (e Error) Call(frame Frame, args ...Func) Func {
return e
}
func (e Error) Error() string {
return e.Err.Error()
}
func (e Error) Unwrap() error {
return e.Err
}
func (e Error) Reflect(name string) bool {
return name == "Error"
}
// Bool is a boolean. Like other primitive types, it simply returns
// itself when called.
type Bool bool
func (b Bool) Call(frame Frame, args ...Func) Func {
return b
}
func (b Bool) Compare(other Func) (int, bool) {
if b == other {
return 0, false
}
return -1, false
}
func (b Bool) Reflect(name string) bool {
return name == "Bool"
}