This repository has been archived by the owner on Aug 23, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
value.go
397 lines (340 loc) · 9.65 KB
/
value.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
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
package goal
//go:generate stringer -type=TokenType,astTokenType,opcode -output stringer.go
import (
"unsafe"
)
// V contains a boxed or unboxed value.
type V struct {
kind valueKind // valInt, valFloat, valBoxed, ...
uv int64 // unboxed integer or float value
bv BV // boxed value
}
// valueKind represents the kinds of values.
type valueKind int8
const (
valNil valueKind = iota
valInt // unboxed int64 (uv field)
valFloat // unboxed float64 (uv field)
valVariadic // unboxed int32 (uv field)
valLambda // unboxed int32 (uv field)
valBoxed // boxed value (bv field)
valPanic // boxed value (bv field)
)
// BV is the interface satisfied by all boxed values.
type BV interface {
// Matches returns true if the value matches another (in the sense of
// the ~ operator).
Matches(BV) bool
// Append appends a unique program representation of the value to dst,
// and returns the extended buffer. It should not store the returned
// buffer elsewhere, so that it's possible to safely convert it to
// string without allocations.
Append(ctx *Context, dst []byte) []byte
// Type returns the name of the value's type. It may be used by LessT to
// sort non-comparable values using lexicographic order. This means
// Type should return different values for non-comparable values.
Type() string
// LessT returns true if the value should be orderer before the given
// one. It is used for sorting values, but not for element-wise
// comparison with < and >. It should produce a strict total order,
// that is, irreflexive (~x<x), asymmetric (if x<y then ~y<x),
// transitive, connected (different values are comparable, except
// NaNs).
LessT(BV) bool
}
// newVariadic returns a new variadic value.
func newVariadic(v variadic) V {
return V{kind: valVariadic, uv: int64(v)}
}
// lambda represents an user defined function by ID.
type lambda int32
// newLambda returns a new lambda value.
func newLambda(v lambda) V {
return V{kind: valLambda, uv: int64(v)}
}
// NewError returns a new recoverable error value.
func NewError(x V) V {
return V{kind: valBoxed, bv: &errV{V: x}}
}
// NewI returns a new unboxed int64 value.
func NewI(i int64) V {
return V{kind: valInt, uv: i}
}
// NewF returns a new unboxed float64 value.
func NewF(f float64) V {
i := *(*int64)(unsafe.Pointer(&f))
return V{kind: valFloat, uv: i}
}
// NewS returns a new string value.
func NewS(s string) V {
return V{kind: valBoxed, bv: S(s)}
}
// NewV returns a new boxed value.
func NewV(x BV) V {
return V{kind: valBoxed, bv: x}
}
// variadic retrieves the variadic value from uv field. It assumes kind is
// IntVariadic.
func (x V) variadic() variadic {
return variadic(x.uv)
}
// Variadic retrieves the lambda value from uv field. It assumes kind is
// IntLambda.
func (x V) lambda() lambda {
return lambda(x.uv)
}
// Error retrieves the error value. It assumes x.IsError().
func (x V) Error() V {
return x.bv.(*errV).V
}
// I retrieves the unboxed integer value from uv field. It assumes x.IsI().
func (x V) I() int64 {
return x.uv
}
// F retrieves the unboxed float64 value. It assumes x.IsF().
func (x V) F() float64 {
i := x.uv
f := *(*float64)(unsafe.Pointer(&i))
return f
}
// BV retrieves the boxed value, or nil if the value is not boxed. You can
// check whether the value is boxed with IsBV(v).
func (x V) BV() BV {
return x.bv
}
// Type returns the name of the value's type.
func (x V) Type() string {
switch x.kind {
case valNil:
return "nil"
case valInt:
return "i"
case valFloat:
return "n"
case valVariadic:
return "f"
case valLambda:
return "f"
case valBoxed:
return x.bv.Type()
default:
return ""
}
}
// IsI returns true if the value is an integer.
func (x V) IsI() bool {
return x.kind == valInt
}
// IsF returns true if the value is a float.
func (x V) IsF() bool {
return x.kind == valFloat
}
// IsPanic returns true if the value is a fatal error.
func (x V) IsPanic() bool {
return x.kind == valPanic
}
// Panic returns the panic string. It assumes x.IsPanic().
func (x V) Panic() string {
if x.IsPanic() {
return string(x.bv.(panicV))
}
return ""
}
// IsError returns true if the value is a recoverable error.
func (x V) IsError() bool {
if x.kind != valBoxed {
return false
}
_, ok := x.bv.(*errV)
return ok
}
// IsBV returns true if the value is a boxed value satisfying the BV interface.
// You can then get the value with the BV method.
func (x V) IsBV() bool {
return x.kind == valBoxed
}
// IsFunction returns true if the value is some kind of function.
func (x V) IsFunction() bool {
switch x.kind {
case valVariadic, valLambda:
return true
case valBoxed:
_, ok := x.bv.(function)
return ok
default:
return false
}
}
// IsCallable returns true if the value can be called with one or more
// arguments. This is true for functions, arrays, strings and regexps, for
// example.
func (x V) IsCallable() bool {
switch x.kind {
case valVariadic, valLambda:
return true
case valBoxed:
_, ok := x.bv.(callable)
return ok
default:
return false
}
}
// Rank returns the default rank of the value, that is the number of arguments
// it normally takes. It returns 0 for non-function values. This default rank
// is used when a function is used in an adverbial expression that has
// different semantics depending on the function arity. Currently, ranks are as
// follows:
//
// variadic 2
// lambda number of arguments
// projections number of gaps
// derived verb depends on the verb and adverb
func (x V) Rank(ctx *Context) int {
switch x.kind {
case valVariadic:
return 2
case valLambda:
return ctx.lambdas[x.uv].Rank
case valBoxed:
if xf, ok := x.bv.(function); ok {
return xf.rank(ctx)
}
return 0
default:
return 0
}
}
// errV represents a recoverable error. It may contain some goal value of any
// kind.
type errV struct {
V V
}
func (e *errV) Matches(y BV) bool {
switch yv := y.(type) {
case *errV:
return e.V.Matches(yv.V)
default:
return false
}
}
func (e *errV) Type() string { return "e" }
// panicV represents a fatal error string.
type panicV string
func (e panicV) Matches(y BV) bool {
switch yv := y.(type) {
case panicV:
return e == yv
default:
return false
}
}
func (e panicV) Type() string { return "panic" }
// S represents (immutable) strings of bytes.
type S string
func (s S) Matches(y BV) bool {
switch yv := y.(type) {
case S:
return s == yv
default:
return false
}
}
// Type retuns "s" for string atoms.
func (s S) Type() string { return "s" }
// derivedVerb represents values modified by an adverb. This kind value is not
// manipulable within the program, as it is only produced as an intermediary
// value in adverb trains and only appears as an adverb argument.
type derivedVerb struct {
Fun variadic
Arg V
}
// projection represents a partial application of a function. Because variadic
// verbs do not have a fixed arity, it is possible to produce a projection of
// arbitrary arity.
type projection struct {
Fun V
Args []V
}
// projectionFirst represents a monadic projection fixing the first argument of
// a function with rank greater than 2.
type projectionFirst struct {
Fun V // function with rank >= 2
Arg V // first argument x
}
// projectionMonad represents a monadic projection of a function of any rank.
type projectionMonad struct {
Fun V
}
func (p *projection) Type() string { return "f" }
func (p *projectionFirst) Type() string { return "f" }
func (p *projectionMonad) Type() string { return "f" }
func (r *derivedVerb) Type() string { return "f" }
// function interface is satisfied by the different kind of functions. A
// function is a value thas has a default rank. The default rank is used in
// situations where an adverb or function has different meanings depending on
// the arity of the function that is passed to it.
// Note that arrays do also have a “rank” but do not implement this interface.
type function interface {
BV
rank(ctx *Context) int
stype() string
}
// Rank for a projection is the number of nil arguments.
func (p *projection) rank(ctx *Context) int { return countNils(p.Args) }
// Rank for a 1-arg projection is 1.
func (p *projectionFirst) rank(ctx *Context) int { return 1 }
// Rank for a curryfied function is 1.
func (p *projectionMonad) rank(ctx *Context) int { return 1 }
// Rank returns the rank of a derived verb.
func (r *derivedVerb) rank(ctx *Context) int {
switch r.Fun {
case vEach:
// f' has same rank as f
return maxInt(1, r.Arg.Rank(ctx))
default:
// f/ and f\ have rank derived from f, except that by default
// it's one less, because we consider as default case the
// non-seeded case.
return maxInt(1, r.Arg.Rank(ctx)-1)
}
}
func (p *projection) stype() string { return "p" }
func (p *projectionFirst) stype() string { return "pf" }
func (p *projectionMonad) stype() string { return "pm" }
func (r *derivedVerb) stype() string { return "r" }
func (p *projection) Matches(x BV) bool {
xp, ok := x.(*projection)
if !ok || !p.Fun.Matches(xp.Fun) {
return false
}
if len(p.Args) != len(xp.Args) {
return false
}
for i, arg := range p.Args {
if !arg.Matches(xp.Args[i]) {
return false
}
}
return true
}
func (p *projectionFirst) Matches(x BV) bool {
xp, ok := x.(*projectionFirst)
return ok && p.Fun.Matches(xp.Fun) && p.Arg.Matches(xp.Arg)
}
func (p *projectionMonad) Matches(x BV) bool {
xp, ok := x.(*projectionMonad)
return ok && p.Fun.Matches(xp.Fun)
}
func (r *derivedVerb) Matches(x BV) bool {
xr, ok := x.(*derivedVerb)
return ok && r.Fun == xr.Fun && r.Arg.Matches(xr.Arg)
}
type integer interface {
signed | unsigned
}
type number interface {
~float64 | integer
}
type ordered interface {
~float64 | ~string | integer
}