-
Notifications
You must be signed in to change notification settings - Fork 19
/
array.go
155 lines (129 loc) · 3.27 KB
/
array.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
package types
import (
"encoding/json"
"strings"
"github.com/nyaruka/gocommon/jsonx"
"github.com/nyaruka/goflow/envs"
"github.com/nyaruka/goflow/utils"
)
// XArray is an array of items.
//
// @(array(1, "x", true)) -> [1, x, true]
// @(array(1, "x", true)[1]) -> x
// @(count(array(1, "x", true))) -> 3
// @(json(array(1, "x", true))) -> [1,"x",true]
//
// @type array
type XArray struct {
baseValue
data []XValue
source func() []XValue
}
// NewXArray returns a new array with the given items
func NewXArray(data ...XValue) *XArray {
if data == nil {
data = []XValue{}
}
return &XArray{data: data}
}
// NewXLazyArray returns a new lazy array with the given source function
func NewXLazyArray(source func() []XValue) *XArray {
return &XArray{
source: source,
}
}
// Get is called when this object is indexed
func (x *XArray) Get(index int) XValue {
return x.values()[index]
}
// Count is called when the length of this object is requested in an expression
func (x *XArray) Count() int {
return len(x.values())
}
// Describe returns a representation of this type for error messages
func (x *XArray) Describe() string { return "array" }
// Truthy determines truthiness for this type
func (x *XArray) Truthy() bool {
return x.Count() > 0
}
// Render returns the canonical text representation
func (x *XArray) Render() string {
parts := make([]string, x.Count())
for i, v := range x.values() {
parts[i] = Render(v)
}
return "[" + strings.Join(parts, ", ") + "]"
}
// Format returns the pretty text representation
func (x *XArray) Format(env envs.Environment) string {
parts := make([]string, x.Count())
multiline := false
for i, v := range x.values() {
parts[i] = Format(env, v)
if strings.ContainsRune(parts[i], '\n') {
multiline = true
}
}
if multiline {
for i, p := range parts {
p = utils.Indent(p, " ")
parts[i] = "-" + p[1:]
}
return strings.Join(parts, "\n")
}
return strings.Join(parts, ", ")
}
// MarshalJSON converts this type to internal JSON
func (x *XArray) MarshalJSON() ([]byte, error) {
marshaled := make([]json.RawMessage, x.Count())
for i, v := range x.values() {
asJSON, err := ToXJSON(v)
if err == nil {
marshaled[i] = json.RawMessage(asJSON.Native())
}
}
return jsonx.Marshal(marshaled)
}
// String returns the native string representation of this type
func (x *XArray) String() string {
parts := make([]string, x.Count())
for i, v := range x.values() {
parts[i] = String(v)
}
return `XArray[` + strings.Join(parts, ", ") + `]`
}
// Equals determines equality for this type
func (x *XArray) Equals(o XValue) bool {
other := o.(*XArray)
if x.Count() != other.Count() {
return false
}
for i, v := range x.values() {
if !Equals(v, other.values()[i]) {
return false
}
}
return true
}
func (x *XArray) values() []XValue {
if x.data == nil {
x.data = x.source()
}
return x.data
}
// XArrayEmpty is the empty array
var XArrayEmpty = NewXArray()
// ToXArray converts the given value to an array
func ToXArray(env envs.Environment, x XValue) (*XArray, *XError) {
if IsNil(x) {
return XArrayEmpty, nil
}
if IsXError(x) {
return XArrayEmpty, x.(*XError)
}
asArray, isArray := x.(*XArray)
if isArray {
return asArray, nil
}
return XArrayEmpty, NewXErrorf("unable to convert %s to an array", Describe(x))
}