-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathobject.go
More file actions
145 lines (124 loc) · 2.82 KB
/
object.go
File metadata and controls
145 lines (124 loc) · 2.82 KB
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
// Copyright (c) 2022, Peter Ohler, All rights reserved.
package slip
import (
"fmt"
"time"
"unsafe"
)
// Object is the interface for all LISP entities other than nil.
type Object interface {
fmt.Stringer
// Append the object to a byte slice.
Append(b []byte) []byte
// Simplify the Object into simple go types of nil, bool, int64, float64,
// string, []any, map[string]any, or time.Time.
Simplify() any
// Equal returns true if this Object and the other are equal in value.
Equal(other Object) bool
// Hierarchy returns the class hierarchy as symbols for the instance.
Hierarchy() []Symbol
// Eval the object.
Eval(s *Scope, depth int) Object
}
// ObjectString returns the string for an Object or "nil" if nil.
func ObjectString(obj Object) string {
if IsNil(obj) {
return "nil"
}
return obj.String()
}
// ObjectAppend appends Object or "nil" if nil.
func ObjectAppend(b []byte, obj Object) []byte {
if obj == nil {
return append(b, "nil"...)
}
return obj.Append(b)
}
// ObjectEqual compares two Object for equality returning true if they are
// equal.
func ObjectEqual(x, y Object) (eq bool) {
if x == nil {
return y == nil
}
return x.Equal(y)
}
// IsNil checks for a nil value of an interface. Go values have two components
// not exposed, a type component and a value component. Further reading:
// https://research.swtch.com/interfaces. To ascertain whether the value is
// nil we ignore the type component and just check if the value component is
// set to 0.
func IsNil(v any) bool {
return (*[2]uintptr)(unsafe.Pointer(&v))[1] == 0
}
// SimpleObject creates an Object from simple data.
func SimpleObject(val any) (obj Object) {
switch tv := val.(type) {
case bool:
if tv {
obj = True
}
case int:
obj = Fixnum(tv)
case int8:
obj = Fixnum(tv)
case int16:
obj = Fixnum(tv)
case int32:
obj = Fixnum(tv)
case int64:
obj = Fixnum(tv)
case uint:
obj = Fixnum(tv)
case uint8:
obj = Octet(tv)
case uint16:
obj = Fixnum(tv)
case uint32:
obj = Fixnum(tv)
case uint64:
obj = Fixnum(tv)
case float32:
obj = SingleFloat(tv)
case float64:
obj = DoubleFloat(tv)
case string:
obj = String(tv)
case []byte:
obj = String(tv)
case time.Time:
obj = Time(tv)
case []any:
list := make(List, 0, len(tv))
for _, v := range tv {
list = append(list, SimpleObject(v))
}
obj = list
case map[string]any:
list := make(List, 0, len(tv))
for k, v2 := range tv {
list = append(list, List{String(k), Tail{Value: SimpleObject(v2)}})
}
obj = list
case *Panic:
obj = tv.Value
if obj == nil {
if tv.Condition != nil {
obj = tv.Condition
} else {
obj = String(tv.Message)
}
}
case Object:
obj = tv
case error:
obj = String(tv.Error())
}
return
}
// Simplify an Object.
func Simplify(obj Object) any {
if obj == nil {
return nil
}
return obj.Simplify()
}