conjure-js 0.0.12 → 0.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/dist-cli/conjure-js.mjs +9360 -5298
  2. package/dist-vite-plugin/index.mjs +9463 -5185
  3. package/package.json +3 -1
  4. package/src/bin/cli.ts +2 -2
  5. package/src/bin/nrepl-symbol.ts +150 -0
  6. package/src/bin/nrepl.ts +289 -167
  7. package/src/bin/version.ts +1 -1
  8. package/src/clojure/core.clj +757 -29
  9. package/src/clojure/core.clj.d.ts +75 -131
  10. package/src/clojure/generated/builtin-namespace-registry.ts +4 -0
  11. package/src/clojure/generated/clojure-core-source.ts +758 -29
  12. package/src/clojure/generated/clojure-set-source.ts +136 -0
  13. package/src/clojure/generated/clojure-walk-source.ts +72 -0
  14. package/src/clojure/set.clj +132 -0
  15. package/src/clojure/set.clj.d.ts +20 -0
  16. package/src/clojure/string.clj.d.ts +14 -0
  17. package/src/clojure/walk.clj +68 -0
  18. package/src/clojure/walk.clj.d.ts +7 -0
  19. package/src/core/assertions.ts +114 -6
  20. package/src/core/bootstrap.ts +337 -0
  21. package/src/core/conversions.ts +48 -31
  22. package/src/core/core-module.ts +303 -0
  23. package/src/core/env.ts +20 -6
  24. package/src/core/evaluator/apply.ts +40 -25
  25. package/src/core/evaluator/arity.ts +8 -8
  26. package/src/core/evaluator/async-evaluator.ts +565 -0
  27. package/src/core/evaluator/collections.ts +28 -5
  28. package/src/core/evaluator/destructure.ts +180 -69
  29. package/src/core/evaluator/dispatch.ts +12 -14
  30. package/src/core/evaluator/evaluate.ts +22 -20
  31. package/src/core/evaluator/expand.ts +45 -15
  32. package/src/core/evaluator/form-parsers.ts +178 -0
  33. package/src/core/evaluator/index.ts +7 -9
  34. package/src/core/evaluator/js-interop.ts +189 -0
  35. package/src/core/evaluator/quasiquote.ts +14 -8
  36. package/src/core/evaluator/recur-check.ts +6 -6
  37. package/src/core/evaluator/special-forms.ts +234 -191
  38. package/src/core/factories.ts +182 -3
  39. package/src/core/index.ts +54 -4
  40. package/src/core/module.ts +136 -0
  41. package/src/core/ns-forms.ts +107 -0
  42. package/src/core/printer.ts +371 -11
  43. package/src/core/reader.ts +84 -33
  44. package/src/core/registry.ts +209 -0
  45. package/src/core/runtime.ts +376 -0
  46. package/src/core/session.ts +253 -487
  47. package/src/core/stdlib/arithmetic.ts +528 -194
  48. package/src/core/stdlib/async-fns.ts +132 -0
  49. package/src/core/stdlib/atoms.ts +291 -56
  50. package/src/core/stdlib/errors.ts +54 -50
  51. package/src/core/stdlib/hof.ts +82 -166
  52. package/src/core/stdlib/js-namespace.ts +344 -0
  53. package/src/core/stdlib/lazy.ts +34 -0
  54. package/src/core/stdlib/maps-sets.ts +322 -0
  55. package/src/core/stdlib/meta.ts +61 -30
  56. package/src/core/stdlib/predicates.ts +325 -187
  57. package/src/core/stdlib/regex.ts +126 -98
  58. package/src/core/stdlib/seq.ts +564 -0
  59. package/src/core/stdlib/strings.ts +164 -135
  60. package/src/core/stdlib/transducers.ts +95 -100
  61. package/src/core/stdlib/utils.ts +292 -130
  62. package/src/core/stdlib/vars.ts +27 -27
  63. package/src/core/stdlib/vectors.ts +122 -0
  64. package/src/core/tokenizer.ts +2 -2
  65. package/src/core/transformations.ts +117 -9
  66. package/src/core/types.ts +98 -2
  67. package/src/host/node-host-module.ts +74 -0
  68. package/src/{vite-plugin-clj/nrepl-relay.ts → nrepl/relay.ts} +72 -11
  69. package/src/vite-plugin-clj/codegen.ts +87 -95
  70. package/src/vite-plugin-clj/index.ts +178 -23
  71. package/src/vite-plugin-clj/namespace-utils.ts +39 -0
  72. package/src/vite-plugin-clj/static-analysis.ts +211 -0
  73. package/src/clojure/demo.clj +0 -72
  74. package/src/clojure/demo.clj.d.ts +0 -0
  75. package/src/core/core-env.ts +0 -61
  76. package/src/core/stdlib/collections.ts +0 -739
  77. package/src/host/node.ts +0 -55
@@ -0,0 +1,34 @@
1
+ import { is } from '../assertions'
2
+ import { v } from '../factories'
3
+ import { realizeDelay, realizeLazySeq } from '../transformations'
4
+ import type { CljValue } from '../types'
5
+
6
+ export const lazyFunctions = {
7
+ force: v
8
+ .nativeFn('force', function force(value: CljValue) {
9
+ if (is.delay(value)) return realizeDelay(value)
10
+ if (is.lazySeq(value)) return realizeLazySeq(value)
11
+ return value
12
+ })
13
+ .doc(
14
+ 'If x is a Delay or LazySeq, forces and returns the realized value. Otherwise returns x.',
15
+ [['x']]
16
+ ),
17
+ 'delay?': v
18
+ .nativeFn('delay?', function isDelayPred(value: CljValue) {
19
+ return v.boolean(is.delay(value))
20
+ })
21
+ .doc('Returns true if x is a Delay.', [['x']]),
22
+ 'lazy-seq?': v
23
+ .nativeFn('lazy-seq?', function isLazySeqPred(value: CljValue) {
24
+ return v.boolean(is.lazySeq(value))
25
+ })
26
+ .doc('Returns true if x is a LazySeq.', [['x']]),
27
+ 'realized?': v
28
+ .nativeFn('realized?', function isRealized(value: CljValue) {
29
+ if (is.delay(value)) return v.boolean(value.realized)
30
+ if (is.lazySeq(value)) return v.boolean(value.realized)
31
+ return v.boolean(false)
32
+ })
33
+ .doc('Returns true if a Delay or LazySeq has been realized.', [['x']]),
34
+ }
@@ -0,0 +1,322 @@
1
+ // Associative and set operations: hash-map, assoc, dissoc, keys, vals, zipmap,
2
+ // hash-set, set, set?, disj
3
+ //
4
+ // assoc and dissoc handle both maps and vectors (by numeric index). They live
5
+ // here because their primary semantic is associative (key→value update/remove);
6
+ // the vector branch is an edge case within the same dispatch.
7
+
8
+ import { is } from '../assertions'
9
+ import { EvaluationError } from '../errors'
10
+ import { v } from '../factories'
11
+ import { printString } from '../printer'
12
+ import { toSeq } from '../transformations'
13
+ import { type CljNumber, type CljValue } from '../types'
14
+
15
+ export const mapsSetsFunctions: Record<string, CljValue> = {
16
+ 'hash-map': v
17
+ .nativeFn('hash-map', function hashMapImpl(...kvals: CljValue[]) {
18
+ if (kvals.length === 0) {
19
+ return v.map([])
20
+ }
21
+ if (kvals.length % 2 !== 0) {
22
+ throw new EvaluationError(
23
+ `hash-map expects an even number of arguments, got ${kvals.length}`,
24
+ { args: kvals }
25
+ )
26
+ }
27
+ const entries: [CljValue, CljValue][] = []
28
+ for (let i = 0; i < kvals.length; i += 2) {
29
+ const key = kvals[i]
30
+ const value = kvals[i + 1]
31
+ entries.push([key, value])
32
+ }
33
+ return v.map(entries)
34
+ })
35
+ .doc('Returns a new hash-map containing the given key-value pairs.', [
36
+ ['&', 'kvals'],
37
+ ]),
38
+
39
+ assoc: v
40
+ .nativeFn(
41
+ 'assoc',
42
+ function assocImpl(collection: CljValue, ...args: CljValue[]) {
43
+ if (!collection) {
44
+ throw new EvaluationError(
45
+ 'assoc expects a collection as first argument',
46
+ { collection }
47
+ )
48
+ }
49
+ // nil is treated as an empty map, matching Clojure: (assoc nil :k v) => {:k v}
50
+ if (is.nil(collection)) {
51
+ collection = v.map([])
52
+ }
53
+ if (is.list(collection)) {
54
+ throw new EvaluationError(
55
+ 'assoc on lists is not supported, use vectors instead',
56
+ { collection }
57
+ )
58
+ }
59
+ if (!is.collection(collection)) {
60
+ throw EvaluationError.atArg(
61
+ `assoc expects a collection, got ${printString(collection)}`,
62
+ { collection },
63
+ 0
64
+ )
65
+ }
66
+ if (args.length < 2) {
67
+ throw new EvaluationError('assoc expects at least two arguments', {
68
+ args,
69
+ })
70
+ }
71
+ if (args.length % 2 !== 0) {
72
+ throw new EvaluationError(
73
+ 'assoc expects an even number of binding arguments',
74
+ {
75
+ args,
76
+ }
77
+ )
78
+ }
79
+ if (is.vector(collection)) {
80
+ const newValues = [...collection.value]
81
+ for (let i = 0; i < args.length; i += 2) {
82
+ const index = args[i]
83
+ if (index.kind !== 'number') {
84
+ throw EvaluationError.atArg(
85
+ `assoc on vectors expects each key argument to be a index (number), got ${printString(index)}`,
86
+ { index },
87
+ i + 1
88
+ )
89
+ }
90
+ if (index.value > newValues.length) {
91
+ throw EvaluationError.atArg(
92
+ `assoc index ${index.value} is out of bounds for vector of length ${newValues.length}`,
93
+ { index, collection },
94
+ i + 1
95
+ )
96
+ }
97
+ newValues[(index as CljNumber).value] = args[i + 1]
98
+ }
99
+ return v.vector(newValues)
100
+ }
101
+ if (is.map(collection)) {
102
+ const newEntries: [CljValue, CljValue][] = [...collection.entries]
103
+ // need to find the entry with the same key and replace it, if it doesn't exist, add it
104
+ for (let i = 0; i < args.length; i += 2) {
105
+ const key = args[i]
106
+ const value = args[i + 1]
107
+ const entryIdx = newEntries.findIndex(
108
+ function findEntryByKey(entry) {
109
+ return is.equal(entry[0], key)
110
+ }
111
+ )
112
+ if (entryIdx === -1) {
113
+ newEntries.push([key, value])
114
+ } else {
115
+ newEntries[entryIdx] = [key, value]
116
+ }
117
+ }
118
+ return v.map(newEntries)
119
+ }
120
+ throw new EvaluationError(
121
+ `unhandled collection type, got ${printString(collection)}`,
122
+ { collection }
123
+ )
124
+ }
125
+ )
126
+ .doc(
127
+ 'Associates the value val with the key k in collection. If collection is a map, returns a new map with the same mappings, otherwise returns a vector with the new value at index k.',
128
+ [['collection', '&', 'kvals']]
129
+ ),
130
+
131
+ dissoc: v
132
+ .nativeFn(
133
+ 'dissoc',
134
+ function dissocImpl(collection: CljValue, ...args: CljValue[]) {
135
+ if (!collection) {
136
+ throw new EvaluationError(
137
+ 'dissoc expects a collection as first argument',
138
+ { collection }
139
+ )
140
+ }
141
+ if (is.list(collection)) {
142
+ throw EvaluationError.atArg(
143
+ 'dissoc on lists is not supported, use vectors instead',
144
+ { collection },
145
+ 0
146
+ )
147
+ }
148
+ if (!is.collection(collection)) {
149
+ throw EvaluationError.atArg(
150
+ `dissoc expects a collection, got ${printString(collection)}`,
151
+ { collection },
152
+ 0
153
+ )
154
+ }
155
+ if (is.vector(collection)) {
156
+ if (collection.value.length === 0) {
157
+ return collection // return the empty vector
158
+ }
159
+ const newValues = [...collection.value]
160
+ for (let i = 0; i < args.length; i += 1) {
161
+ const index = args[i]
162
+ if (index.kind !== 'number') {
163
+ throw EvaluationError.atArg(
164
+ `dissoc on vectors expects each key argument to be a index (number), got ${printString(index)}`,
165
+ { index },
166
+ i + 1
167
+ )
168
+ }
169
+ if (index.value >= newValues.length) {
170
+ throw EvaluationError.atArg(
171
+ `dissoc index ${index.value} is out of bounds for vector of length ${newValues.length}`,
172
+ { index, collection },
173
+ i + 1
174
+ )
175
+ }
176
+ newValues.splice(index.value, 1)
177
+ }
178
+ return v.vector(newValues)
179
+ }
180
+ if (is.map(collection)) {
181
+ if (collection.entries.length === 0) {
182
+ return collection // return the empty map
183
+ }
184
+ const newEntries: [CljValue, CljValue][] = [...collection.entries]
185
+ for (let i = 0; i < args.length; i += 1) {
186
+ const key = args[i]
187
+ const entryIdx = newEntries.findIndex(
188
+ function findEntryByKey(entry) {
189
+ return is.equal(entry[0], key)
190
+ }
191
+ )
192
+ if (entryIdx === -1) {
193
+ return collection // not found, unchanged
194
+ }
195
+ newEntries.splice(entryIdx, 1)
196
+ }
197
+ return v.map(newEntries)
198
+ }
199
+ throw new EvaluationError(
200
+ `unhandled collection type, got ${printString(collection)}`,
201
+ { collection }
202
+ )
203
+ }
204
+ )
205
+ .doc(
206
+ 'Dissociates the key k from collection. If collection is a map, returns a new map with the same mappings, otherwise returns a vector with the value at index k removed.',
207
+ [['collection', '&', 'keys']]
208
+ ),
209
+
210
+ zipmap: v
211
+ .nativeFn('zipmap', function zipmapImpl(ks: CljValue, vs: CljValue) {
212
+ if (ks === undefined || !is.seqable(ks)) {
213
+ throw new EvaluationError(
214
+ `zipmap expects a collection or string as first argument${ks !== undefined ? `, got ${printString(ks)}` : ''}`,
215
+ { ks }
216
+ )
217
+ }
218
+ if (vs === undefined || !is.seqable(vs)) {
219
+ throw new EvaluationError(
220
+ `zipmap expects a collection or string as second argument${vs !== undefined ? `, got ${printString(vs)}` : ''}`,
221
+ { vs }
222
+ )
223
+ }
224
+ const keys = toSeq(ks)
225
+ const vals = toSeq(vs)
226
+ const len = Math.min(keys.length, vals.length)
227
+ const entries: [CljValue, CljValue][] = []
228
+ for (let i = 0; i < len; i++) {
229
+ entries.push([keys[i], vals[i]])
230
+ }
231
+ return v.map(entries)
232
+ })
233
+ .doc(
234
+ 'Returns a new map with the keys and values of the given collections.',
235
+ [['ks', 'vs']]
236
+ ),
237
+
238
+ keys: v
239
+ .nativeFn('keys', function keysImpl(m: CljValue) {
240
+ if (m === undefined || !is.map(m)) {
241
+ throw EvaluationError.atArg(
242
+ `keys expects a map${m !== undefined ? `, got ${printString(m)}` : ''}`,
243
+ { m },
244
+ 0
245
+ )
246
+ }
247
+ return v.vector(
248
+ m.entries.map(function extractKey([k]) {
249
+ return k
250
+ })
251
+ )
252
+ })
253
+ .doc('Returns a vector of the keys of the given map.', [['m']]),
254
+
255
+ vals: v
256
+ .nativeFn('vals', function valsImpl(m: CljValue) {
257
+ if (m === undefined || !is.map(m)) {
258
+ throw EvaluationError.atArg(
259
+ `vals expects a map${m !== undefined ? `, got ${printString(m)}` : ''}`,
260
+ { m },
261
+ 0
262
+ )
263
+ }
264
+ return v.vector(
265
+ m.entries.map(function extractVal([, v]) {
266
+ return v
267
+ })
268
+ )
269
+ })
270
+ .doc('Returns a vector of the values of the given map.', [['m']]),
271
+
272
+ 'hash-set': v
273
+ .nativeFn('hash-set', function hashSetImpl(...args: CljValue[]) {
274
+ const deduped: CljValue[] = []
275
+ for (const v of args) {
276
+ if (!deduped.some((existing) => is.equal(existing, v))) {
277
+ deduped.push(v)
278
+ }
279
+ }
280
+ return v.set(deduped)
281
+ })
282
+ .doc('Returns a set containing the given values.', [['&', 'xs']]),
283
+
284
+ set: v
285
+ .nativeFn('set', function setImpl(coll: CljValue) {
286
+ if (coll === undefined || coll.kind === 'nil') return v.set([])
287
+ const items = toSeq(coll)
288
+ const deduped: CljValue[] = []
289
+ for (const v of items) {
290
+ if (!deduped.some((existing) => is.equal(existing, v))) {
291
+ deduped.push(v)
292
+ }
293
+ }
294
+ return v.set(deduped)
295
+ })
296
+ .doc('Returns a set of the distinct elements of the given collection.', [
297
+ ['coll'],
298
+ ]),
299
+
300
+ 'set?': v
301
+ .nativeFn('set?', function setPredicateImpl(x: CljValue) {
302
+ return v.boolean(x !== undefined && x.kind === 'set')
303
+ })
304
+ .doc('Returns true if x is a set.', [['x']]),
305
+
306
+ disj: v
307
+ .nativeFn('disj', function disjImpl(s: CljValue, ...items: CljValue[]) {
308
+ if (s === undefined || s.kind === 'nil') return v.set([])
309
+ if (s.kind !== 'set') {
310
+ throw EvaluationError.atArg(
311
+ `disj expects a set, got ${printString(s)}`,
312
+ { s },
313
+ 0
314
+ )
315
+ }
316
+ const newValues = s.values.filter(
317
+ (v) => !items.some((item) => is.equal(item, v))
318
+ )
319
+ return v.set(newValues)
320
+ })
321
+ .doc('Returns a set with the given items removed.', [['s', '&', 'items']]),
322
+ }
@@ -1,13 +1,19 @@
1
1
  // Metadata: with-meta, meta, alter-meta!
2
- import { isAFunction } from '../assertions'
2
+ import { is } from '../assertions'
3
3
  import { EvaluationError } from '../errors'
4
- import { cljNativeFunction, cljNativeFunctionWithContext, cljNil, withDoc } from '../factories'
4
+ import { v } from '../factories'
5
5
  import { printString } from '../printer'
6
- import type { CljAtom, CljMap, CljValue, Env, EvaluationContext } from '../types'
6
+ import type {
7
+ CljAtom,
8
+ CljMap,
9
+ CljValue,
10
+ Env,
11
+ EvaluationContext,
12
+ } from '../types'
7
13
 
8
14
  export const metaFunctions: Record<string, CljValue> = {
9
- meta: withDoc(
10
- cljNativeFunction('meta', (val: CljValue) => {
15
+ meta: v
16
+ .nativeFn('meta', function metaImpl(val: CljValue) {
11
17
  if (val === undefined) {
12
18
  throw EvaluationError.atArg('meta expects one argument', {}, 0)
13
19
  }
@@ -21,16 +27,17 @@ export const metaFunctions: Record<string, CljValue> = {
21
27
  val.kind === 'symbol' ||
22
28
  val.kind === 'atom'
23
29
  ) {
24
- return val.meta ?? cljNil()
30
+ return val.meta ?? v.nil()
25
31
  }
26
- return cljNil()
27
- }),
28
- 'Returns the metadata map of a value, or nil if the value has no metadata.',
29
- [['val']]
30
- ),
32
+ return v.nil()
33
+ })
34
+ .doc(
35
+ 'Returns the metadata map of a value, or nil if the value has no metadata.',
36
+ [['val']]
37
+ ),
31
38
 
32
- 'with-meta': withDoc(
33
- cljNativeFunction('with-meta', (val: CljValue, m: CljValue) => {
39
+ 'with-meta': v
40
+ .nativeFn('with-meta', function withMetaImpl(val: CljValue, m: CljValue) {
34
41
  if (val === undefined) {
35
42
  throw EvaluationError.atArg('with-meta expects two arguments', {}, 0)
36
43
  }
@@ -38,7 +45,11 @@ export const metaFunctions: Record<string, CljValue> = {
38
45
  throw EvaluationError.atArg('with-meta expects two arguments', {}, 1)
39
46
  }
40
47
  if (m.kind !== 'map' && m.kind !== 'nil') {
41
- throw EvaluationError.atArg(`with-meta expects a map as second argument, got ${printString(m)}`, { m }, 1)
48
+ throw EvaluationError.atArg(
49
+ `with-meta expects a map as second argument, got ${printString(m)}`,
50
+ { m },
51
+ 1
52
+ )
42
53
  }
43
54
  const metaSupported =
44
55
  val.kind === 'function' ||
@@ -48,24 +59,42 @@ export const metaFunctions: Record<string, CljValue> = {
48
59
  val.kind === 'map' ||
49
60
  val.kind === 'symbol'
50
61
  if (!metaSupported) {
51
- throw EvaluationError.atArg(`with-meta does not support ${val.kind}, got ${printString(val)}`, { val }, 0)
62
+ throw EvaluationError.atArg(
63
+ `with-meta does not support ${val.kind}, got ${printString(val)}`,
64
+ { val },
65
+ 0
66
+ )
52
67
  }
53
68
  const meta = m.kind === 'nil' ? undefined : (m as CljMap)
54
69
  return { ...val, meta }
55
- }),
56
- 'Returns a new value with the metadata map m applied to val.',
57
- [['val', 'm']]
58
- ),
70
+ })
71
+ .doc('Returns a new value with the metadata map m applied to val.', [
72
+ ['val', 'm'],
73
+ ]),
59
74
 
60
- 'alter-meta!': withDoc(
61
- cljNativeFunctionWithContext(
75
+ 'alter-meta!': v
76
+ .nativeFnCtx(
62
77
  'alter-meta!',
63
- (ctx: EvaluationContext, callEnv: Env, ref: CljValue, f: CljValue, ...args: CljValue[]) => {
78
+ function alterMetaImpl(
79
+ ctx: EvaluationContext,
80
+ callEnv: Env,
81
+ ref: CljValue,
82
+ f: CljValue,
83
+ ...args: CljValue[]
84
+ ) {
64
85
  if (ref === undefined) {
65
- throw EvaluationError.atArg('alter-meta! expects at least two arguments', {}, 0)
86
+ throw EvaluationError.atArg(
87
+ 'alter-meta! expects at least two arguments',
88
+ {},
89
+ 0
90
+ )
66
91
  }
67
92
  if (f === undefined) {
68
- throw EvaluationError.atArg('alter-meta! expects at least two arguments', {}, 1)
93
+ throw EvaluationError.atArg(
94
+ 'alter-meta! expects at least two arguments',
95
+ {},
96
+ 1
97
+ )
69
98
  }
70
99
  if (ref.kind !== 'var' && ref.kind !== 'atom') {
71
100
  throw EvaluationError.atArg(
@@ -74,14 +103,14 @@ export const metaFunctions: Record<string, CljValue> = {
74
103
  0
75
104
  )
76
105
  }
77
- if (!isAFunction(f)) {
106
+ if (!is.aFunction(f)) {
78
107
  throw EvaluationError.atArg(
79
108
  `alter-meta! expects a function as second argument, got ${f.kind}`,
80
109
  {},
81
110
  1
82
111
  )
83
112
  }
84
- const currentMeta: CljValue = ref.meta ?? cljNil()
113
+ const currentMeta: CljValue = ref.meta ?? v.nil()
85
114
  const newMeta = ctx.applyCallable(f, [currentMeta, ...args], callEnv)
86
115
  if (newMeta.kind !== 'map' && newMeta.kind !== 'nil') {
87
116
  throw new EvaluationError(
@@ -89,11 +118,13 @@ export const metaFunctions: Record<string, CljValue> = {
89
118
  {}
90
119
  )
91
120
  }
92
- ;(ref as CljAtom).meta = newMeta.kind === 'nil' ? undefined : (newMeta as CljMap)
121
+ ;(ref as CljAtom).meta =
122
+ newMeta.kind === 'nil' ? undefined : (newMeta as CljMap)
93
123
  return newMeta
94
124
  }
125
+ )
126
+ .doc(
127
+ "Applies f to ref's current metadata (with optional args), sets the result as the new metadata, and returns it.",
128
+ [['ref', 'f', '&', 'args']]
95
129
  ),
96
- "Applies f to ref's current metadata (with optional args), sets the result as the new metadata, and returns it.",
97
- [['ref', 'f', '&', 'args']]
98
- ),
99
130
  }