-
Notifications
You must be signed in to change notification settings - Fork 19
/
base.go
152 lines (122 loc) · 3.37 KB
/
base.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
package types
import (
"encoding/json"
"fmt"
"reflect"
"github.com/nyaruka/goflow/envs"
)
// XValue is the base interface of all excellent types
type XValue interface {
// How type is rendered in console for debugging
fmt.Stringer
// How the type JSONifies
json.Marshaler
// Describe returns a representation for use in error messages
Describe() string
// Truthy determines truthiness for this type
Truthy() bool
// Render returns the canonical text representation
Render() string
// Format returns the pretty text representation
Format(env envs.Environment) string
// Equals returns true if this value is equal to the given value
Equals(XValue) bool
// Deprecated returns whether this value is considered deprecated
Deprecated() string
// Marks this value as considered deprecated
SetDeprecated(string)
}
// XCountable is the interface for types which can be counted
type XCountable interface {
Count() int
}
// XComparable is the interface for types which can be compared
type XComparable interface {
// Compare returns -1 if this value is less, 0 if equal, +1 if greater
Compare(XValue) int
}
// Equals checks for equality between the two given values. This is only used for testing as x = y
// specifically means text(x) == text(y)
func Equals(x1 XValue, x2 XValue) bool {
// nil == nil
if IsNil(x1) && IsNil(x2) {
return true
} else if IsNil(x1) || IsNil(x2) {
return false
}
// different types aren't equal
if reflect.TypeOf(x1) != reflect.TypeOf(x2) {
return false
}
return x1.Equals(x2)
}
// Compare compares two given values
func Compare(x1 XValue, x2 XValue) int {
// nil == nil
if IsNil(x1) && IsNil(x2) {
return 0
} else if IsNil(x1) {
return -1
} else if IsNil(x2) {
return 1
}
// different types can't be compared
if !SameType(x1, x2) {
panic(fmt.Sprintf("can't compare a %T with a %T", x1, x2))
}
this, isComparable := x1.(XComparable)
if !isComparable {
panic(fmt.Sprintf("type %T is not comparable", x1))
}
return this.Compare(x2)
}
// SameType returns whether two values are of the same type
func SameType(x1 XValue, x2 XValue) bool {
return reflect.TypeOf(x1) == reflect.TypeOf(x2)
}
// Describe returns a representation of the given value for use in error messages
func Describe(x XValue) string {
if IsNil(x) {
return "null"
}
return x.Describe()
}
// Truthy determines truthiness for the given value
func Truthy(x XValue) bool {
if IsNil(x) {
return false
}
return x.Truthy()
}
// Render returns the canonical text representation
func Render(x XValue) string {
if IsNil(x) {
return ""
}
return x.Render()
}
// Format returns the pretty text representation
func Format(env envs.Environment, x XValue) string {
if IsNil(x) {
return ""
}
return x.Format(env)
}
// String returns a representation of the given value for use in debugging
func String(x XValue) string {
if IsNil(x) {
return "nil"
}
return x.String()
}
// IsNil returns whether the given value is nil... because of golang's love of autoboxing nil pointers into non-nil
// interfaces, we need to check if interface itself is nil or the underlying pointer is nil.
func IsNil(x XValue) bool {
return x == nil || reflect.ValueOf(x).IsNil()
}
// baseValue is shared by all X types
type baseValue struct {
deprecated string
}
func (x *baseValue) Deprecated() string { return x.deprecated }
func (x *baseValue) SetDeprecated(msg string) { x.deprecated = msg }