conjure-js 0.0.11 → 0.0.12
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.
- package/dist-cli/conjure-js.mjs +508 -262
- package/dist-vite-plugin/index.mjs +6177 -0
- package/package.json +7 -2
- package/src/bin/nrepl.ts +25 -3
- package/src/bin/version.ts +1 -1
- package/src/clojure/core.clj +7 -0
- package/src/clojure/core.clj.d.ts +128 -0
- package/src/clojure/demo/math.clj +5 -1
- package/src/clojure/demo.clj +10 -1
- package/src/clojure/generated/clojure-core-source.ts +7 -0
- package/src/core/core-env.ts +5 -4
- package/src/core/env.ts +25 -4
- package/src/core/errors.ts +8 -0
- package/src/core/evaluator/collections.ts +4 -1
- package/src/core/evaluator/dispatch.ts +13 -1
- package/src/core/evaluator/special-forms.ts +169 -5
- package/src/core/index.ts +1 -1
- package/src/core/positions.ts +9 -2
- package/src/core/reader.ts +48 -1
- package/src/core/session.ts +32 -13
- package/src/core/stdlib/arithmetic.ts +46 -79
- package/src/core/stdlib/atoms.ts +4 -16
- package/src/core/stdlib/collections.ts +48 -93
- package/src/core/stdlib/hof.ts +11 -26
- package/src/core/stdlib/meta.ts +67 -17
- package/src/core/stdlib/predicates.ts +4 -16
- package/src/core/stdlib/utils.ts +16 -42
- package/src/core/tokenizer.ts +11 -1
- package/src/core/types.ts +21 -5
- package/src/vite-plugin-clj/index.ts +75 -6
- package/src/vite-plugin-clj/nrepl-relay.ts +371 -0
package/dist-cli/conjure-js.mjs
CHANGED
|
@@ -47,7 +47,8 @@ var tokenKeywords = {
|
|
|
47
47
|
AnonFnStart: "AnonFnStart",
|
|
48
48
|
Deref: "Deref",
|
|
49
49
|
Regex: "Regex",
|
|
50
|
-
VarQuote: "VarQuote"
|
|
50
|
+
VarQuote: "VarQuote",
|
|
51
|
+
Meta: "Meta"
|
|
51
52
|
};
|
|
52
53
|
var tokenSymbols = {
|
|
53
54
|
Quote: "quote",
|
|
@@ -86,12 +87,18 @@ class ReaderError extends Error {
|
|
|
86
87
|
class EvaluationError extends Error {
|
|
87
88
|
context;
|
|
88
89
|
pos;
|
|
90
|
+
data;
|
|
89
91
|
constructor(message, context, pos) {
|
|
90
92
|
super(message);
|
|
91
93
|
this.name = "EvaluationError";
|
|
92
94
|
this.context = context;
|
|
93
95
|
this.pos = pos;
|
|
94
96
|
}
|
|
97
|
+
static atArg(message, context, argIndex) {
|
|
98
|
+
const err = new EvaluationError(message, context);
|
|
99
|
+
err.data = { argIndex };
|
|
100
|
+
return err;
|
|
101
|
+
}
|
|
95
102
|
}
|
|
96
103
|
|
|
97
104
|
class CljThrownSignal {
|
|
@@ -101,6 +108,72 @@ class CljThrownSignal {
|
|
|
101
108
|
}
|
|
102
109
|
}
|
|
103
110
|
|
|
111
|
+
// src/core/factories.ts
|
|
112
|
+
var cljNumber = (value) => ({ kind: "number", value });
|
|
113
|
+
var cljString = (value) => ({ kind: "string", value });
|
|
114
|
+
var cljBoolean = (value) => ({ kind: "boolean", value });
|
|
115
|
+
var cljKeyword = (name) => ({ kind: "keyword", name });
|
|
116
|
+
var cljNil = () => ({ kind: "nil", value: null });
|
|
117
|
+
var cljSymbol = (name) => ({ kind: "symbol", name });
|
|
118
|
+
var cljList = (value) => ({ kind: "list", value });
|
|
119
|
+
var cljVector = (value) => ({ kind: "vector", value });
|
|
120
|
+
var cljMap = (entries) => ({ kind: "map", entries });
|
|
121
|
+
var cljMultiArityFunction = (arities, env) => ({
|
|
122
|
+
kind: "function",
|
|
123
|
+
arities,
|
|
124
|
+
env
|
|
125
|
+
});
|
|
126
|
+
var cljNativeFunction = (name, fn) => ({ kind: "native-function", name, fn });
|
|
127
|
+
var cljNativeFunctionWithContext = (name, fn) => ({
|
|
128
|
+
kind: "native-function",
|
|
129
|
+
name,
|
|
130
|
+
fn: () => {
|
|
131
|
+
throw new EvaluationError("Native function called without context", {
|
|
132
|
+
name
|
|
133
|
+
});
|
|
134
|
+
},
|
|
135
|
+
fnWithContext: fn
|
|
136
|
+
});
|
|
137
|
+
var cljMultiArityMacro = (arities, env) => ({
|
|
138
|
+
kind: "macro",
|
|
139
|
+
arities,
|
|
140
|
+
env
|
|
141
|
+
});
|
|
142
|
+
var cljRegex = (pattern, flags = "") => ({
|
|
143
|
+
kind: "regex",
|
|
144
|
+
pattern,
|
|
145
|
+
flags
|
|
146
|
+
});
|
|
147
|
+
var cljVar = (ns, name, value, meta) => ({ kind: "var", ns, name, value, meta });
|
|
148
|
+
var cljAtom = (value) => ({ kind: "atom", value });
|
|
149
|
+
var cljReduced = (value) => ({
|
|
150
|
+
kind: "reduced",
|
|
151
|
+
value
|
|
152
|
+
});
|
|
153
|
+
var cljVolatile = (value) => ({
|
|
154
|
+
kind: "volatile",
|
|
155
|
+
value
|
|
156
|
+
});
|
|
157
|
+
var withDoc = (fn, doc, arglists) => ({
|
|
158
|
+
...fn,
|
|
159
|
+
meta: cljMap([
|
|
160
|
+
[cljKeyword(":doc"), cljString(doc)],
|
|
161
|
+
...arglists ? [
|
|
162
|
+
[
|
|
163
|
+
cljKeyword(":arglists"),
|
|
164
|
+
cljVector(arglists.map((args) => cljVector(args.map(cljSymbol))))
|
|
165
|
+
]
|
|
166
|
+
] : []
|
|
167
|
+
])
|
|
168
|
+
});
|
|
169
|
+
var cljMultiMethod = (name, dispatchFn, methods, defaultMethod) => ({
|
|
170
|
+
kind: "multi-method",
|
|
171
|
+
name,
|
|
172
|
+
dispatchFn,
|
|
173
|
+
methods,
|
|
174
|
+
defaultMethod
|
|
175
|
+
});
|
|
176
|
+
|
|
104
177
|
// src/core/env.ts
|
|
105
178
|
class EnvError extends Error {
|
|
106
179
|
context;
|
|
@@ -111,7 +184,12 @@ class EnvError extends Error {
|
|
|
111
184
|
}
|
|
112
185
|
}
|
|
113
186
|
function derefValue(val) {
|
|
114
|
-
|
|
187
|
+
if (val.kind !== "var")
|
|
188
|
+
return val;
|
|
189
|
+
if (val.dynamic && val.bindingStack && val.bindingStack.length > 0) {
|
|
190
|
+
return val.bindingStack[val.bindingStack.length - 1];
|
|
191
|
+
}
|
|
192
|
+
return val.value;
|
|
115
193
|
}
|
|
116
194
|
function makeNamespace(name) {
|
|
117
195
|
return { name, vars: new Map, aliases: new Map, readerAliases: new Map };
|
|
@@ -130,7 +208,7 @@ function lookup(name, env) {
|
|
|
130
208
|
return derefValue(raw);
|
|
131
209
|
const v = current.ns?.vars.get(name);
|
|
132
210
|
if (v !== undefined)
|
|
133
|
-
return v
|
|
211
|
+
return derefValue(v);
|
|
134
212
|
current = current.outer;
|
|
135
213
|
}
|
|
136
214
|
throw new EvaluationError(`Symbol ${name} not found`, { name });
|
|
@@ -143,11 +221,22 @@ function tryLookup(name, env) {
|
|
|
143
221
|
return derefValue(raw);
|
|
144
222
|
const v = current.ns?.vars.get(name);
|
|
145
223
|
if (v !== undefined)
|
|
146
|
-
return v
|
|
224
|
+
return derefValue(v);
|
|
147
225
|
current = current.outer;
|
|
148
226
|
}
|
|
149
227
|
return;
|
|
150
228
|
}
|
|
229
|
+
function internVar(name, value, nsEnv, meta) {
|
|
230
|
+
const ns = nsEnv.ns;
|
|
231
|
+
const existing = ns.vars.get(name);
|
|
232
|
+
if (existing) {
|
|
233
|
+
existing.value = value;
|
|
234
|
+
if (meta)
|
|
235
|
+
existing.meta = meta;
|
|
236
|
+
} else {
|
|
237
|
+
ns.vars.set(name, cljVar(ns.name, name, value, meta));
|
|
238
|
+
}
|
|
239
|
+
}
|
|
151
240
|
function lookupVar(name, env) {
|
|
152
241
|
let current = env;
|
|
153
242
|
while (current) {
|
|
@@ -195,71 +284,43 @@ function getNamespaceEnv(env) {
|
|
|
195
284
|
return getRootEnv(env);
|
|
196
285
|
}
|
|
197
286
|
|
|
198
|
-
// src/core/
|
|
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
|
-
var cljAtom = (value) => ({ kind: "atom", value });
|
|
236
|
-
var cljReduced = (value) => ({
|
|
237
|
-
kind: "reduced",
|
|
238
|
-
value
|
|
239
|
-
});
|
|
240
|
-
var cljVolatile = (value) => ({
|
|
241
|
-
kind: "volatile",
|
|
242
|
-
value
|
|
243
|
-
});
|
|
244
|
-
var withDoc = (fn, doc, arglists) => ({
|
|
245
|
-
...fn,
|
|
246
|
-
meta: cljMap([
|
|
247
|
-
[cljKeyword(":doc"), cljString(doc)],
|
|
248
|
-
...arglists ? [
|
|
249
|
-
[
|
|
250
|
-
cljKeyword(":arglists"),
|
|
251
|
-
cljVector(arglists.map((args) => cljVector(args.map(cljSymbol))))
|
|
252
|
-
]
|
|
253
|
-
] : []
|
|
254
|
-
])
|
|
255
|
-
});
|
|
256
|
-
var cljMultiMethod = (name, dispatchFn, methods, defaultMethod) => ({
|
|
257
|
-
kind: "multi-method",
|
|
258
|
-
name,
|
|
259
|
-
dispatchFn,
|
|
260
|
-
methods,
|
|
261
|
-
defaultMethod
|
|
262
|
-
});
|
|
287
|
+
// src/core/positions.ts
|
|
288
|
+
function setPos(val, pos) {
|
|
289
|
+
Object.defineProperty(val, "_pos", {
|
|
290
|
+
value: pos,
|
|
291
|
+
enumerable: false,
|
|
292
|
+
writable: true,
|
|
293
|
+
configurable: true
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
function getPos(val) {
|
|
297
|
+
return val._pos;
|
|
298
|
+
}
|
|
299
|
+
function getLineCol(source, offset) {
|
|
300
|
+
const lines = source.split(`
|
|
301
|
+
`);
|
|
302
|
+
let pos = 0;
|
|
303
|
+
for (let i = 0;i < lines.length; i++) {
|
|
304
|
+
const lineEnd = pos + lines[i].length;
|
|
305
|
+
if (offset <= lineEnd) {
|
|
306
|
+
return { line: i + 1, col: offset - pos, lineText: lines[i] };
|
|
307
|
+
}
|
|
308
|
+
pos = lineEnd + 1;
|
|
309
|
+
}
|
|
310
|
+
const last = lines[lines.length - 1];
|
|
311
|
+
return { line: lines.length, col: last.length, lineText: last };
|
|
312
|
+
}
|
|
313
|
+
function formatErrorContext(source, pos, opts) {
|
|
314
|
+
const { line, col, lineText } = getLineCol(source, pos.start);
|
|
315
|
+
const absLine = line + (opts?.lineOffset ?? 0);
|
|
316
|
+
const absCol = line === 1 ? col + (opts?.colOffset ?? 0) : col;
|
|
317
|
+
const span = Math.max(1, pos.end - pos.start);
|
|
318
|
+
const caret = " ".repeat(col) + "^".repeat(span);
|
|
319
|
+
return `
|
|
320
|
+
at line ${absLine}, col ${absCol + 1}:
|
|
321
|
+
${lineText}
|
|
322
|
+
${caret}`;
|
|
323
|
+
}
|
|
263
324
|
|
|
264
325
|
// src/core/evaluator/destructure.ts
|
|
265
326
|
function toSeqSafe(value) {
|
|
@@ -665,6 +726,16 @@ function validateForm(form, inTail) {
|
|
|
665
726
|
}
|
|
666
727
|
|
|
667
728
|
// src/core/evaluator/special-forms.ts
|
|
729
|
+
function hasDynamicMeta(meta) {
|
|
730
|
+
if (!meta)
|
|
731
|
+
return false;
|
|
732
|
+
for (const [k, v] of meta.entries) {
|
|
733
|
+
if (k.kind === "keyword" && k.name === ":dynamic" && v.kind === "boolean" && v.value === true) {
|
|
734
|
+
return true;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
return false;
|
|
738
|
+
}
|
|
668
739
|
var specialFormKeywords = {
|
|
669
740
|
quote: "quote",
|
|
670
741
|
def: "def",
|
|
@@ -680,7 +751,9 @@ var specialFormKeywords = {
|
|
|
680
751
|
defmulti: "defmulti",
|
|
681
752
|
defmethod: "defmethod",
|
|
682
753
|
try: "try",
|
|
683
|
-
var: "var"
|
|
754
|
+
var: "var",
|
|
755
|
+
binding: "binding",
|
|
756
|
+
"set!": "set!"
|
|
684
757
|
};
|
|
685
758
|
function keywordToDispatchFn(kw) {
|
|
686
759
|
return cljNativeFunction(`kw:${kw.name}`, (...args) => {
|
|
@@ -795,6 +868,27 @@ function evaluateQuote(list, _env, _ctx) {
|
|
|
795
868
|
function evalQuasiquote(list, env, ctx) {
|
|
796
869
|
return evaluateQuasiquote(list.value[1], env, new Map, ctx);
|
|
797
870
|
}
|
|
871
|
+
function buildVarMeta(symMeta, ctx, nameVal) {
|
|
872
|
+
const pos = nameVal ? getPos(nameVal) : undefined;
|
|
873
|
+
const hasPosInfo = pos && ctx.currentSource;
|
|
874
|
+
if (!symMeta && !hasPosInfo)
|
|
875
|
+
return;
|
|
876
|
+
const posEntries = [];
|
|
877
|
+
if (hasPosInfo) {
|
|
878
|
+
const { line, col } = getLineCol(ctx.currentSource, pos.start);
|
|
879
|
+
const lineOffset = ctx.currentLineOffset ?? 0;
|
|
880
|
+
const colOffset = ctx.currentColOffset ?? 0;
|
|
881
|
+
posEntries.push([cljKeyword(":line"), cljNumber(line + lineOffset)]);
|
|
882
|
+
posEntries.push([cljKeyword(":column"), cljNumber(line === 1 ? col + colOffset : col)]);
|
|
883
|
+
if (ctx.currentFile) {
|
|
884
|
+
posEntries.push([cljKeyword(":file"), cljString(ctx.currentFile)]);
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
const POS_KEYS = new Set([":line", ":column", ":file"]);
|
|
888
|
+
const baseEntries = (symMeta?.entries ?? []).filter(([k]) => !(k.kind === "keyword" && POS_KEYS.has(k.name)));
|
|
889
|
+
const allEntries = [...baseEntries, ...posEntries];
|
|
890
|
+
return allEntries.length > 0 ? cljMap(allEntries) : undefined;
|
|
891
|
+
}
|
|
798
892
|
function evaluateDef(list, env, ctx) {
|
|
799
893
|
const name = list.value[1];
|
|
800
894
|
if (name.kind !== "symbol") {
|
|
@@ -809,11 +903,20 @@ function evaluateDef(list, env, ctx) {
|
|
|
809
903
|
const nsEnv = getNamespaceEnv(env);
|
|
810
904
|
const cljNs = nsEnv.ns;
|
|
811
905
|
const newValue = ctx.evaluate(list.value[2], env);
|
|
906
|
+
const varMeta = buildVarMeta(name.meta, ctx, name);
|
|
812
907
|
const existing = cljNs.vars.get(name.name);
|
|
813
908
|
if (existing) {
|
|
814
909
|
existing.value = newValue;
|
|
910
|
+
if (varMeta) {
|
|
911
|
+
existing.meta = varMeta;
|
|
912
|
+
if (hasDynamicMeta(varMeta))
|
|
913
|
+
existing.dynamic = true;
|
|
914
|
+
}
|
|
815
915
|
} else {
|
|
816
|
-
|
|
916
|
+
const v = cljVar(cljNs.name, name.name, newValue, varMeta);
|
|
917
|
+
if (hasDynamicMeta(varMeta))
|
|
918
|
+
v.dynamic = true;
|
|
919
|
+
cljNs.vars.set(name.name, v);
|
|
817
920
|
}
|
|
818
921
|
return cljNil();
|
|
819
922
|
}
|
|
@@ -872,7 +975,7 @@ function evaluateDefmacro(list, env, _ctx) {
|
|
|
872
975
|
}
|
|
873
976
|
const arities = parseArities(list.value.slice(2), env);
|
|
874
977
|
const macro = cljMultiArityMacro(arities, env);
|
|
875
|
-
|
|
978
|
+
internVar(name.name, macro, getNamespaceEnv(env));
|
|
876
979
|
return cljNil();
|
|
877
980
|
}
|
|
878
981
|
function evaluateLoop(list, env, ctx) {
|
|
@@ -944,7 +1047,7 @@ function evaluateDefmulti(list, env, ctx) {
|
|
|
944
1047
|
dispatchFn = evaluated;
|
|
945
1048
|
}
|
|
946
1049
|
const mm = cljMultiMethod(mmName.name, dispatchFn, []);
|
|
947
|
-
|
|
1050
|
+
internVar(mmName.name, mm, getNamespaceEnv(env));
|
|
948
1051
|
return cljNil();
|
|
949
1052
|
}
|
|
950
1053
|
function evaluateDefmethod(list, env, ctx) {
|
|
@@ -973,7 +1076,12 @@ function evaluateDefmethod(list, env, ctx) {
|
|
|
973
1076
|
{ dispatchVal, fn: methodFn }
|
|
974
1077
|
]);
|
|
975
1078
|
}
|
|
976
|
-
|
|
1079
|
+
const v = lookupVar(mmName.name, env);
|
|
1080
|
+
if (v) {
|
|
1081
|
+
v.value = updated;
|
|
1082
|
+
} else {
|
|
1083
|
+
define(mmName.name, updated, getNamespaceEnv(env));
|
|
1084
|
+
}
|
|
977
1085
|
return cljNil();
|
|
978
1086
|
}
|
|
979
1087
|
function evaluateVar(list, env, _ctx) {
|
|
@@ -1008,6 +1116,66 @@ function evaluateVar(list, env, _ctx) {
|
|
|
1008
1116
|
}
|
|
1009
1117
|
return v;
|
|
1010
1118
|
}
|
|
1119
|
+
function evaluateBinding(list, env, ctx) {
|
|
1120
|
+
const bindings = list.value[1];
|
|
1121
|
+
if (!isVector(bindings)) {
|
|
1122
|
+
throw new EvaluationError("binding requires a vector of bindings", {
|
|
1123
|
+
list,
|
|
1124
|
+
env
|
|
1125
|
+
});
|
|
1126
|
+
}
|
|
1127
|
+
if (bindings.value.length % 2 !== 0) {
|
|
1128
|
+
throw new EvaluationError("binding vector must have an even number of forms", { list, env });
|
|
1129
|
+
}
|
|
1130
|
+
const body = list.value.slice(2);
|
|
1131
|
+
const boundVars = [];
|
|
1132
|
+
for (let i = 0;i < bindings.value.length; i += 2) {
|
|
1133
|
+
const sym = bindings.value[i];
|
|
1134
|
+
if (!isSymbol(sym)) {
|
|
1135
|
+
throw new EvaluationError("binding left-hand side must be a symbol", { sym });
|
|
1136
|
+
}
|
|
1137
|
+
const newVal = ctx.evaluate(bindings.value[i + 1], env);
|
|
1138
|
+
const v = lookupVar(sym.name, env);
|
|
1139
|
+
if (!v) {
|
|
1140
|
+
throw new EvaluationError(`No var found for symbol '${sym.name}' in binding form`, { sym });
|
|
1141
|
+
}
|
|
1142
|
+
if (!v.dynamic) {
|
|
1143
|
+
throw new EvaluationError(`Cannot use binding with non-dynamic var ${v.ns}/${v.name}. Mark it dynamic with (def ^:dynamic ${sym.name} ...)`, { sym });
|
|
1144
|
+
}
|
|
1145
|
+
v.bindingStack ??= [];
|
|
1146
|
+
v.bindingStack.push(newVal);
|
|
1147
|
+
boundVars.push(v);
|
|
1148
|
+
}
|
|
1149
|
+
try {
|
|
1150
|
+
return ctx.evaluateForms(body, env);
|
|
1151
|
+
} finally {
|
|
1152
|
+
for (const v of boundVars) {
|
|
1153
|
+
v.bindingStack.pop();
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
function evaluateSet(list, env, ctx) {
|
|
1158
|
+
if (list.value.length !== 3) {
|
|
1159
|
+
throw new EvaluationError(`set! requires exactly 2 arguments, got ${list.value.length - 1}`, { list, env });
|
|
1160
|
+
}
|
|
1161
|
+
const symForm = list.value[1];
|
|
1162
|
+
if (!isSymbol(symForm)) {
|
|
1163
|
+
throw new EvaluationError(`set! first argument must be a symbol, got ${symForm.kind}`, { symForm, env });
|
|
1164
|
+
}
|
|
1165
|
+
const v = lookupVar(symForm.name, env);
|
|
1166
|
+
if (!v) {
|
|
1167
|
+
throw new EvaluationError(`Unable to resolve var: ${symForm.name} in this context`, { symForm, env });
|
|
1168
|
+
}
|
|
1169
|
+
if (!v.dynamic) {
|
|
1170
|
+
throw new EvaluationError(`Cannot set! non-dynamic var ${v.ns}/${v.name}. Mark it with ^:dynamic.`, { symForm, env });
|
|
1171
|
+
}
|
|
1172
|
+
if (!v.bindingStack || v.bindingStack.length === 0) {
|
|
1173
|
+
throw new EvaluationError(`Cannot set! ${v.ns}/${v.name} — no active binding. Use set! only inside a (binding [...] ...) form.`, { symForm, env });
|
|
1174
|
+
}
|
|
1175
|
+
const newVal = ctx.evaluate(list.value[2], env);
|
|
1176
|
+
v.bindingStack[v.bindingStack.length - 1] = newVal;
|
|
1177
|
+
return newVal;
|
|
1178
|
+
}
|
|
1011
1179
|
var specialFormEvaluatorEntries = {
|
|
1012
1180
|
try: evaluateTry,
|
|
1013
1181
|
quote: evaluateQuote,
|
|
@@ -1023,7 +1191,9 @@ var specialFormEvaluatorEntries = {
|
|
|
1023
1191
|
recur: evaluateRecur,
|
|
1024
1192
|
defmulti: evaluateDefmulti,
|
|
1025
1193
|
defmethod: evaluateDefmethod,
|
|
1026
|
-
var: evaluateVar
|
|
1194
|
+
var: evaluateVar,
|
|
1195
|
+
binding: evaluateBinding,
|
|
1196
|
+
"set!": evaluateSet
|
|
1027
1197
|
};
|
|
1028
1198
|
function evaluateSpecialForm(symbol, list, env, ctx) {
|
|
1029
1199
|
const evalFn = specialFormEvaluatorEntries[symbol];
|
|
@@ -1209,10 +1379,9 @@ var arithmeticFunctions = {
|
|
|
1209
1379
|
if (nums.length === 0) {
|
|
1210
1380
|
return cljNumber(0);
|
|
1211
1381
|
}
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
});
|
|
1382
|
+
const badIdx = nums.findIndex((a) => a.kind !== "number");
|
|
1383
|
+
if (badIdx !== -1) {
|
|
1384
|
+
throw EvaluationError.atArg("+ expects all arguments to be numbers", { args: nums }, badIdx);
|
|
1216
1385
|
}
|
|
1217
1386
|
return nums.reduce((acc, arg) => {
|
|
1218
1387
|
return cljNumber(acc.value + arg.value);
|
|
@@ -1224,10 +1393,9 @@ var arithmeticFunctions = {
|
|
|
1224
1393
|
args: nums
|
|
1225
1394
|
});
|
|
1226
1395
|
}
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
});
|
|
1396
|
+
const badIdx = nums.findIndex((a) => a.kind !== "number");
|
|
1397
|
+
if (badIdx !== -1) {
|
|
1398
|
+
throw EvaluationError.atArg("- expects all arguments to be numbers", { args: nums }, badIdx);
|
|
1231
1399
|
}
|
|
1232
1400
|
return nums.slice(1).reduce((acc, arg) => {
|
|
1233
1401
|
return cljNumber(acc.value - arg.value);
|
|
@@ -1237,10 +1405,9 @@ var arithmeticFunctions = {
|
|
|
1237
1405
|
if (nums.length === 0) {
|
|
1238
1406
|
return cljNumber(1);
|
|
1239
1407
|
}
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
});
|
|
1408
|
+
const badIdx = nums.findIndex((a) => a.kind !== "number");
|
|
1409
|
+
if (badIdx !== -1) {
|
|
1410
|
+
throw EvaluationError.atArg("* expects all arguments to be numbers", { args: nums }, badIdx);
|
|
1244
1411
|
}
|
|
1245
1412
|
return nums.slice(1).reduce((acc, arg) => {
|
|
1246
1413
|
return cljNumber(acc.value * arg.value);
|
|
@@ -1252,14 +1419,15 @@ var arithmeticFunctions = {
|
|
|
1252
1419
|
args: nums
|
|
1253
1420
|
});
|
|
1254
1421
|
}
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
});
|
|
1422
|
+
const badIdx = nums.findIndex((a) => a.kind !== "number");
|
|
1423
|
+
if (badIdx !== -1) {
|
|
1424
|
+
throw EvaluationError.atArg("/ expects all arguments to be numbers", { args: nums }, badIdx);
|
|
1259
1425
|
}
|
|
1260
|
-
return nums.slice(1).reduce((acc, arg) => {
|
|
1426
|
+
return nums.slice(1).reduce((acc, arg, reduceIdx) => {
|
|
1261
1427
|
if (arg.value === 0) {
|
|
1262
|
-
|
|
1428
|
+
const err = new EvaluationError("division by zero", { args: nums });
|
|
1429
|
+
err.data = { argIndex: reduceIdx + 1 };
|
|
1430
|
+
throw err;
|
|
1263
1431
|
}
|
|
1264
1432
|
return cljNumber(acc.value / arg.value);
|
|
1265
1433
|
}, nums[0]);
|
|
@@ -1270,10 +1438,9 @@ var arithmeticFunctions = {
|
|
|
1270
1438
|
args: nums
|
|
1271
1439
|
});
|
|
1272
1440
|
}
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
});
|
|
1441
|
+
const badIdx = nums.findIndex((a) => a.kind !== "number");
|
|
1442
|
+
if (badIdx !== -1) {
|
|
1443
|
+
throw EvaluationError.atArg("> expects all arguments to be numbers", { args: nums }, badIdx);
|
|
1277
1444
|
}
|
|
1278
1445
|
for (let i = 1;i < nums.length; i++) {
|
|
1279
1446
|
if (nums[i].value >= nums[i - 1].value) {
|
|
@@ -1288,10 +1455,9 @@ var arithmeticFunctions = {
|
|
|
1288
1455
|
args: nums
|
|
1289
1456
|
});
|
|
1290
1457
|
}
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
});
|
|
1458
|
+
const badIdx = nums.findIndex((a) => a.kind !== "number");
|
|
1459
|
+
if (badIdx !== -1) {
|
|
1460
|
+
throw EvaluationError.atArg("< expects all arguments to be numbers", { args: nums }, badIdx);
|
|
1295
1461
|
}
|
|
1296
1462
|
for (let i = 1;i < nums.length; i++) {
|
|
1297
1463
|
if (nums[i].value <= nums[i - 1].value) {
|
|
@@ -1306,10 +1472,9 @@ var arithmeticFunctions = {
|
|
|
1306
1472
|
args: nums
|
|
1307
1473
|
});
|
|
1308
1474
|
}
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
});
|
|
1475
|
+
const badIdx = nums.findIndex((a) => a.kind !== "number");
|
|
1476
|
+
if (badIdx !== -1) {
|
|
1477
|
+
throw EvaluationError.atArg(">= expects all arguments to be numbers", { args: nums }, badIdx);
|
|
1313
1478
|
}
|
|
1314
1479
|
for (let i = 1;i < nums.length; i++) {
|
|
1315
1480
|
if (nums[i].value > nums[i - 1].value) {
|
|
@@ -1324,10 +1489,9 @@ var arithmeticFunctions = {
|
|
|
1324
1489
|
args: nums
|
|
1325
1490
|
});
|
|
1326
1491
|
}
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
});
|
|
1492
|
+
const badIdx = nums.findIndex((a) => a.kind !== "number");
|
|
1493
|
+
if (badIdx !== -1) {
|
|
1494
|
+
throw EvaluationError.atArg("<= expects all arguments to be numbers", { args: nums }, badIdx);
|
|
1331
1495
|
}
|
|
1332
1496
|
for (let i = 1;i < nums.length; i++) {
|
|
1333
1497
|
if (nums[i].value < nums[i - 1].value) {
|
|
@@ -1351,13 +1515,13 @@ var arithmeticFunctions = {
|
|
|
1351
1515
|
}), "Compares adjacent arguments left to right, returns true if all values are structurally equal, false otherwise.", [["&", "vals"]]),
|
|
1352
1516
|
inc: withDoc(cljNativeFunction("inc", (x) => {
|
|
1353
1517
|
if (x === undefined || x.kind !== "number") {
|
|
1354
|
-
throw
|
|
1518
|
+
throw EvaluationError.atArg(`inc expects a number${x !== undefined ? `, got ${printString(x)}` : ""}`, { x }, 0);
|
|
1355
1519
|
}
|
|
1356
1520
|
return cljNumber(x.value + 1);
|
|
1357
1521
|
}), "Returns the argument incremented by 1. Throws on non-number arguments.", [["x"]]),
|
|
1358
1522
|
dec: withDoc(cljNativeFunction("dec", (x) => {
|
|
1359
1523
|
if (x === undefined || x.kind !== "number") {
|
|
1360
|
-
throw
|
|
1524
|
+
throw EvaluationError.atArg(`dec expects a number${x !== undefined ? `, got ${printString(x)}` : ""}`, { x }, 0);
|
|
1361
1525
|
}
|
|
1362
1526
|
return cljNumber(x.value - 1);
|
|
1363
1527
|
}), "Returns the argument decremented by 1. Throws on non-number arguments.", [["x"]]),
|
|
@@ -1367,10 +1531,9 @@ var arithmeticFunctions = {
|
|
|
1367
1531
|
args: nums
|
|
1368
1532
|
});
|
|
1369
1533
|
}
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
});
|
|
1534
|
+
const badIdx = nums.findIndex((a) => a.kind !== "number");
|
|
1535
|
+
if (badIdx !== -1) {
|
|
1536
|
+
throw EvaluationError.atArg("max expects all arguments to be numbers", { args: nums }, badIdx);
|
|
1374
1537
|
}
|
|
1375
1538
|
return nums.reduce((best, arg) => arg.value > best.value ? arg : best);
|
|
1376
1539
|
}), "Returns the largest of the arguments. Throws on non-number arguments.", [["&", "nums"]]),
|
|
@@ -1380,53 +1543,54 @@ var arithmeticFunctions = {
|
|
|
1380
1543
|
args: nums
|
|
1381
1544
|
});
|
|
1382
1545
|
}
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
});
|
|
1546
|
+
const badIdx = nums.findIndex((a) => a.kind !== "number");
|
|
1547
|
+
if (badIdx !== -1) {
|
|
1548
|
+
throw EvaluationError.atArg("min expects all arguments to be numbers", { args: nums }, badIdx);
|
|
1387
1549
|
}
|
|
1388
1550
|
return nums.reduce((best, arg) => arg.value < best.value ? arg : best);
|
|
1389
1551
|
}), "Returns the smallest of the arguments. Throws on non-number arguments.", [["&", "nums"]]),
|
|
1390
1552
|
mod: withDoc(cljNativeFunction("mod", (n, d) => {
|
|
1391
1553
|
if (n === undefined || n.kind !== "number") {
|
|
1392
|
-
throw
|
|
1554
|
+
throw EvaluationError.atArg(`mod expects a number as first argument${n !== undefined ? `, got ${printString(n)}` : ""}`, { n }, 0);
|
|
1393
1555
|
}
|
|
1394
1556
|
if (d === undefined || d.kind !== "number") {
|
|
1395
|
-
throw
|
|
1557
|
+
throw EvaluationError.atArg(`mod expects a number as second argument${d !== undefined ? `, got ${printString(d)}` : ""}`, { d }, 1);
|
|
1396
1558
|
}
|
|
1397
1559
|
if (d.value === 0) {
|
|
1398
|
-
|
|
1560
|
+
const err = new EvaluationError("mod: division by zero", { n, d });
|
|
1561
|
+
err.data = { argIndex: 1 };
|
|
1562
|
+
throw err;
|
|
1399
1563
|
}
|
|
1400
1564
|
const result = n.value % d.value;
|
|
1401
1565
|
return cljNumber(result < 0 ? result + Math.abs(d.value) : result);
|
|
1402
1566
|
}), "Returns the remainder of the first argument divided by the second argument. Throws on non-number arguments or division by zero.", [["n", "d"]]),
|
|
1403
1567
|
"even?": withDoc(cljNativeFunction("even?", (n) => {
|
|
1404
1568
|
if (n === undefined || n.kind !== "number") {
|
|
1405
|
-
throw
|
|
1569
|
+
throw EvaluationError.atArg(`even? expects a number${n !== undefined ? `, got ${printString(n)}` : ""}`, { n }, 0);
|
|
1406
1570
|
}
|
|
1407
1571
|
return cljBoolean(n.value % 2 === 0);
|
|
1408
1572
|
}), "Returns true if the argument is an even number, false otherwise.", [["n"]]),
|
|
1409
1573
|
"odd?": withDoc(cljNativeFunction("odd?", (n) => {
|
|
1410
1574
|
if (n === undefined || n.kind !== "number") {
|
|
1411
|
-
throw
|
|
1575
|
+
throw EvaluationError.atArg(`odd? expects a number${n !== undefined ? `, got ${printString(n)}` : ""}`, { n }, 0);
|
|
1412
1576
|
}
|
|
1413
1577
|
return cljBoolean(Math.abs(n.value) % 2 !== 0);
|
|
1414
1578
|
}), "Returns true if the argument is an odd number, false otherwise.", [["n"]]),
|
|
1415
1579
|
"pos?": withDoc(cljNativeFunction("pos?", (n) => {
|
|
1416
1580
|
if (n === undefined || n.kind !== "number") {
|
|
1417
|
-
throw
|
|
1581
|
+
throw EvaluationError.atArg(`pos? expects a number${n !== undefined ? `, got ${printString(n)}` : ""}`, { n }, 0);
|
|
1418
1582
|
}
|
|
1419
1583
|
return cljBoolean(n.value > 0);
|
|
1420
1584
|
}), "Returns true if the argument is a positive number, false otherwise.", [["n"]]),
|
|
1421
1585
|
"neg?": withDoc(cljNativeFunction("neg?", (n) => {
|
|
1422
1586
|
if (n === undefined || n.kind !== "number") {
|
|
1423
|
-
throw
|
|
1587
|
+
throw EvaluationError.atArg(`neg? expects a number${n !== undefined ? `, got ${printString(n)}` : ""}`, { n }, 0);
|
|
1424
1588
|
}
|
|
1425
1589
|
return cljBoolean(n.value < 0);
|
|
1426
1590
|
}), "Returns true if the argument is a negative number, false otherwise.", [["n"]]),
|
|
1427
1591
|
"zero?": withDoc(cljNativeFunction("zero?", (n) => {
|
|
1428
1592
|
if (n === undefined || n.kind !== "number") {
|
|
1429
|
-
throw
|
|
1593
|
+
throw EvaluationError.atArg(`zero? expects a number${n !== undefined ? `, got ${printString(n)}` : ""}`, { n }, 0);
|
|
1430
1594
|
}
|
|
1431
1595
|
return cljBoolean(n.value === 0);
|
|
1432
1596
|
}), "Returns true if the argument is zero, false otherwise.", [["n"]])
|
|
@@ -1444,14 +1608,14 @@ var atomFunctions = {
|
|
|
1444
1608
|
return value.value;
|
|
1445
1609
|
if (isReduced(value))
|
|
1446
1610
|
return value.value;
|
|
1447
|
-
throw
|
|
1611
|
+
throw EvaluationError.atArg(`deref expects an atom, volatile, or reduced value, got ${value.kind}`, { value }, 0);
|
|
1448
1612
|
}), "Returns the wrapped value from an atom, volatile, or reduced value.", [["value"]]),
|
|
1449
1613
|
"swap!": withDoc(cljNativeFunctionWithContext("swap!", (ctx, callEnv, atomVal, fn, ...extraArgs) => {
|
|
1450
1614
|
if (!isAtom(atomVal)) {
|
|
1451
|
-
throw
|
|
1615
|
+
throw EvaluationError.atArg(`swap! expects an atom as its first argument, got ${atomVal.kind}`, { atomVal }, 0);
|
|
1452
1616
|
}
|
|
1453
1617
|
if (!isAFunction(fn)) {
|
|
1454
|
-
throw
|
|
1618
|
+
throw EvaluationError.atArg(`swap! expects a function as its second argument, got ${fn.kind}`, { fn }, 1);
|
|
1455
1619
|
}
|
|
1456
1620
|
const newVal = ctx.applyFunction(fn, [atomVal.value, ...extraArgs], callEnv);
|
|
1457
1621
|
atomVal.value = newVal;
|
|
@@ -1459,7 +1623,7 @@ var atomFunctions = {
|
|
|
1459
1623
|
}), "Applies fn to the current value of the atom, replacing the current value with the result. Returns the new value.", [["atomVal", "fn", "&", "extraArgs"]]),
|
|
1460
1624
|
"reset!": withDoc(cljNativeFunction("reset!", (atomVal, newVal) => {
|
|
1461
1625
|
if (!isAtom(atomVal)) {
|
|
1462
|
-
throw
|
|
1626
|
+
throw EvaluationError.atArg(`reset! expects an atom as its first argument, got ${atomVal.kind}`, { atomVal }, 0);
|
|
1463
1627
|
}
|
|
1464
1628
|
atomVal.value = newVal;
|
|
1465
1629
|
return newVal;
|
|
@@ -1563,7 +1727,7 @@ var collectionFunctions = {
|
|
|
1563
1727
|
if (coll.kind === "nil")
|
|
1564
1728
|
return cljNil();
|
|
1565
1729
|
if (!isSeqable(coll)) {
|
|
1566
|
-
throw
|
|
1730
|
+
throw EvaluationError.atArg(`seq expects a collection, string, or nil, got ${printString(coll)}`, { collection: coll }, 0);
|
|
1567
1731
|
}
|
|
1568
1732
|
const items = toSeq(coll);
|
|
1569
1733
|
return items.length === 0 ? cljNil() : cljList(items);
|
|
@@ -1572,9 +1736,7 @@ var collectionFunctions = {
|
|
|
1572
1736
|
if (collection.kind === "nil")
|
|
1573
1737
|
return cljNil();
|
|
1574
1738
|
if (!isSeqable(collection)) {
|
|
1575
|
-
throw
|
|
1576
|
-
collection
|
|
1577
|
-
});
|
|
1739
|
+
throw EvaluationError.atArg("first expects a collection or string", { collection }, 0);
|
|
1578
1740
|
}
|
|
1579
1741
|
const entries = toSeq(collection);
|
|
1580
1742
|
return entries.length === 0 ? cljNil() : entries[0];
|
|
@@ -1583,9 +1745,7 @@ var collectionFunctions = {
|
|
|
1583
1745
|
if (collection.kind === "nil")
|
|
1584
1746
|
return cljList([]);
|
|
1585
1747
|
if (!isSeqable(collection)) {
|
|
1586
|
-
throw
|
|
1587
|
-
collection
|
|
1588
|
-
});
|
|
1748
|
+
throw EvaluationError.atArg("rest expects a collection or string", { collection }, 0);
|
|
1589
1749
|
}
|
|
1590
1750
|
if (isList(collection)) {
|
|
1591
1751
|
if (collection.value.length === 0) {
|
|
@@ -1606,7 +1766,7 @@ var collectionFunctions = {
|
|
|
1606
1766
|
const chars = toSeq(collection);
|
|
1607
1767
|
return cljList(chars.slice(1));
|
|
1608
1768
|
}
|
|
1609
|
-
throw
|
|
1769
|
+
throw EvaluationError.atArg(`rest expects a collection or string, got ${printString(collection)}`, { collection }, 0);
|
|
1610
1770
|
}), "Returns a sequence of the given collection or string excluding the first element.", [["coll"]]),
|
|
1611
1771
|
conj: withDoc(cljNativeFunction("conj", (collection, ...args) => {
|
|
1612
1772
|
if (!collection) {
|
|
@@ -1616,7 +1776,7 @@ var collectionFunctions = {
|
|
|
1616
1776
|
return collection;
|
|
1617
1777
|
}
|
|
1618
1778
|
if (!isCollection(collection)) {
|
|
1619
|
-
throw
|
|
1779
|
+
throw EvaluationError.atArg(`conj expects a collection, got ${printString(collection)}`, { collection }, 0);
|
|
1620
1780
|
}
|
|
1621
1781
|
if (isList(collection)) {
|
|
1622
1782
|
const newItems = [];
|
|
@@ -1632,11 +1792,12 @@ var collectionFunctions = {
|
|
|
1632
1792
|
const newEntries = [...collection.entries];
|
|
1633
1793
|
for (let i = 0;i < args.length; i += 1) {
|
|
1634
1794
|
const pair = args[i];
|
|
1795
|
+
const pairArgIndex = i + 1;
|
|
1635
1796
|
if (pair.kind !== "vector") {
|
|
1636
|
-
throw
|
|
1797
|
+
throw EvaluationError.atArg(`conj on maps expects each argument to be a vector key-pair for maps, got ${printString(pair)}`, { pair }, pairArgIndex);
|
|
1637
1798
|
}
|
|
1638
1799
|
if (pair.value.length !== 2) {
|
|
1639
|
-
throw
|
|
1800
|
+
throw EvaluationError.atArg(`conj on maps expects each argument to be a vector key-pair for maps, got ${printString(pair)}`, { pair }, pairArgIndex);
|
|
1640
1801
|
}
|
|
1641
1802
|
const key = pair.value[0];
|
|
1642
1803
|
const keyIdx = newEntries.findIndex((entry) => isEqual(entry[0], key));
|
|
@@ -1652,10 +1813,10 @@ var collectionFunctions = {
|
|
|
1652
1813
|
}), "Appends args to the given collection. Lists append in reverse order to the head, vectors append to the tail.", [["collection", "&", "args"]]),
|
|
1653
1814
|
cons: withDoc(cljNativeFunction("cons", (x, xs) => {
|
|
1654
1815
|
if (!isCollection(xs)) {
|
|
1655
|
-
throw
|
|
1816
|
+
throw EvaluationError.atArg(`cons expects a collection as second argument, got ${printString(xs)}`, { xs }, 1);
|
|
1656
1817
|
}
|
|
1657
1818
|
if (isMap(xs)) {
|
|
1658
|
-
throw
|
|
1819
|
+
throw EvaluationError.atArg("cons on maps is not supported, use vectors instead", { xs }, 1);
|
|
1659
1820
|
}
|
|
1660
1821
|
const wrap = isList(xs) ? cljList : cljVector;
|
|
1661
1822
|
const newItems = [x, ...xs.value];
|
|
@@ -1672,7 +1833,7 @@ var collectionFunctions = {
|
|
|
1672
1833
|
throw new EvaluationError("assoc on lists is not supported, use vectors instead", { collection });
|
|
1673
1834
|
}
|
|
1674
1835
|
if (!isCollection(collection)) {
|
|
1675
|
-
throw
|
|
1836
|
+
throw EvaluationError.atArg(`assoc expects a collection, got ${printString(collection)}`, { collection }, 0);
|
|
1676
1837
|
}
|
|
1677
1838
|
if (args.length < 2) {
|
|
1678
1839
|
throw new EvaluationError("assoc expects at least two arguments", {
|
|
@@ -1689,10 +1850,10 @@ var collectionFunctions = {
|
|
|
1689
1850
|
for (let i = 0;i < args.length; i += 2) {
|
|
1690
1851
|
const index = args[i];
|
|
1691
1852
|
if (index.kind !== "number") {
|
|
1692
|
-
throw
|
|
1853
|
+
throw EvaluationError.atArg(`assoc on vectors expects each key argument to be a index (number), got ${printString(index)}`, { index }, i + 1);
|
|
1693
1854
|
}
|
|
1694
1855
|
if (index.value > newValues.length) {
|
|
1695
|
-
throw
|
|
1856
|
+
throw EvaluationError.atArg(`assoc index ${index.value} is out of bounds for vector of length ${newValues.length}`, { index, collection }, i + 1);
|
|
1696
1857
|
}
|
|
1697
1858
|
newValues[index.value] = args[i + 1];
|
|
1698
1859
|
}
|
|
@@ -1719,10 +1880,10 @@ var collectionFunctions = {
|
|
|
1719
1880
|
throw new EvaluationError("dissoc expects a collection as first argument", { collection });
|
|
1720
1881
|
}
|
|
1721
1882
|
if (isList(collection)) {
|
|
1722
|
-
throw
|
|
1883
|
+
throw EvaluationError.atArg("dissoc on lists is not supported, use vectors instead", { collection }, 0);
|
|
1723
1884
|
}
|
|
1724
1885
|
if (!isCollection(collection)) {
|
|
1725
|
-
throw
|
|
1886
|
+
throw EvaluationError.atArg(`dissoc expects a collection, got ${printString(collection)}`, { collection }, 0);
|
|
1726
1887
|
}
|
|
1727
1888
|
if (isVector(collection)) {
|
|
1728
1889
|
if (collection.value.length === 0) {
|
|
@@ -1732,10 +1893,10 @@ var collectionFunctions = {
|
|
|
1732
1893
|
for (let i = 0;i < args.length; i += 1) {
|
|
1733
1894
|
const index = args[i];
|
|
1734
1895
|
if (index.kind !== "number") {
|
|
1735
|
-
throw
|
|
1896
|
+
throw EvaluationError.atArg(`dissoc on vectors expects each key argument to be a index (number), got ${printString(index)}`, { index }, i + 1);
|
|
1736
1897
|
}
|
|
1737
1898
|
if (index.value >= newValues.length) {
|
|
1738
|
-
throw
|
|
1899
|
+
throw EvaluationError.atArg(`dissoc index ${index.value} is out of bounds for vector of length ${newValues.length}`, { index, collection }, i + 1);
|
|
1739
1900
|
}
|
|
1740
1901
|
newValues.splice(index.value, 1);
|
|
1741
1902
|
}
|
|
@@ -1799,7 +1960,9 @@ var collectionFunctions = {
|
|
|
1799
1960
|
if (index < 0 || index >= items.length) {
|
|
1800
1961
|
if (notFound !== undefined)
|
|
1801
1962
|
return notFound;
|
|
1802
|
-
|
|
1963
|
+
const err = new EvaluationError(`nth index ${index} is out of bounds for collection of length ${items.length}`, { coll, n });
|
|
1964
|
+
err.data = { argIndex: 1 };
|
|
1965
|
+
throw err;
|
|
1803
1966
|
}
|
|
1804
1967
|
return items[index];
|
|
1805
1968
|
}), "Returns the nth element of the given collection. If not-found is provided, it is returned if the index is out of bounds, otherwise an error is thrown.", [["coll", "n", "not-found"]]),
|
|
@@ -1838,27 +2001,27 @@ var collectionFunctions = {
|
|
|
1838
2001
|
}), "Returns the last element of the given collection.", [["coll"]]),
|
|
1839
2002
|
reverse: withDoc(cljNativeFunction("reverse", (coll) => {
|
|
1840
2003
|
if (coll === undefined || !isList(coll) && !isVector(coll)) {
|
|
1841
|
-
throw
|
|
2004
|
+
throw EvaluationError.atArg(`reverse expects a list or vector${coll !== undefined ? `, got ${printString(coll)}` : ""}`, { coll }, 0);
|
|
1842
2005
|
}
|
|
1843
2006
|
return cljList([...coll.value].reverse());
|
|
1844
2007
|
}), "Returns a new sequence with the elements of the given collection in reverse order.", [["coll"]]),
|
|
1845
2008
|
"empty?": withDoc(cljNativeFunction("empty?", (coll) => {
|
|
1846
2009
|
if (coll === undefined) {
|
|
1847
|
-
throw
|
|
2010
|
+
throw EvaluationError.atArg("empty? expects one argument", {}, 0);
|
|
1848
2011
|
}
|
|
1849
2012
|
if (coll.kind === "nil")
|
|
1850
2013
|
return cljBoolean(true);
|
|
1851
2014
|
if (!isSeqable(coll)) {
|
|
1852
|
-
throw
|
|
2015
|
+
throw EvaluationError.atArg(`empty? expects a collection, string, or nil, got ${printString(coll)}`, { coll }, 0);
|
|
1853
2016
|
}
|
|
1854
2017
|
return cljBoolean(toSeq(coll).length === 0);
|
|
1855
2018
|
}), "Returns true if coll has no items. Accepts collections, strings, and nil.", [["coll"]]),
|
|
1856
2019
|
"contains?": withDoc(cljNativeFunction("contains?", (coll, key) => {
|
|
1857
2020
|
if (coll === undefined) {
|
|
1858
|
-
throw
|
|
2021
|
+
throw EvaluationError.atArg("contains? expects a collection as first argument", {}, 0);
|
|
1859
2022
|
}
|
|
1860
2023
|
if (key === undefined) {
|
|
1861
|
-
throw
|
|
2024
|
+
throw EvaluationError.atArg("contains? expects a key as second argument", {}, 1);
|
|
1862
2025
|
}
|
|
1863
2026
|
if (coll.kind === "nil")
|
|
1864
2027
|
return cljBoolean(false);
|
|
@@ -1870,11 +2033,11 @@ var collectionFunctions = {
|
|
|
1870
2033
|
return cljBoolean(false);
|
|
1871
2034
|
return cljBoolean(key.value >= 0 && key.value < coll.value.length);
|
|
1872
2035
|
}
|
|
1873
|
-
throw
|
|
2036
|
+
throw EvaluationError.atArg(`contains? expects a map, vector, or nil, got ${printString(coll)}`, { coll }, 0);
|
|
1874
2037
|
}), "Returns true if key is present in coll. For maps checks key existence (including keys with nil values). For vectors checks index bounds.", [["coll", "key"]]),
|
|
1875
2038
|
repeat: withDoc(cljNativeFunction("repeat", (n, x) => {
|
|
1876
2039
|
if (n === undefined || n.kind !== "number") {
|
|
1877
|
-
throw
|
|
2040
|
+
throw EvaluationError.atArg(`repeat expects a number as first argument${n !== undefined ? `, got ${printString(n)}` : ""}`, { n }, 0);
|
|
1878
2041
|
}
|
|
1879
2042
|
return cljList(Array(n.value).fill(x));
|
|
1880
2043
|
}), "Returns a sequence of n copies of x.", [["n", "x"]]),
|
|
@@ -1882,8 +2045,9 @@ var collectionFunctions = {
|
|
|
1882
2045
|
if (args.length === 0 || args.length > 3) {
|
|
1883
2046
|
throw new EvaluationError("range expects 1, 2, or 3 arguments: (range n), (range start end), or (range start end step)", { args });
|
|
1884
2047
|
}
|
|
1885
|
-
|
|
1886
|
-
|
|
2048
|
+
const badIdx = args.findIndex((a) => a.kind !== "number");
|
|
2049
|
+
if (badIdx !== -1) {
|
|
2050
|
+
throw EvaluationError.atArg("range expects number arguments", { args }, badIdx);
|
|
1887
2051
|
}
|
|
1888
2052
|
let start;
|
|
1889
2053
|
let end;
|
|
@@ -1902,7 +2066,7 @@ var collectionFunctions = {
|
|
|
1902
2066
|
step = args[2].value;
|
|
1903
2067
|
}
|
|
1904
2068
|
if (step === 0) {
|
|
1905
|
-
throw
|
|
2069
|
+
throw EvaluationError.atArg("range step cannot be zero", { args }, args.length - 1);
|
|
1906
2070
|
}
|
|
1907
2071
|
const result = [];
|
|
1908
2072
|
if (step > 0) {
|
|
@@ -1918,13 +2082,13 @@ var collectionFunctions = {
|
|
|
1918
2082
|
}), "Returns a sequence of numbers from start (inclusive) to end (exclusive), incrementing by step. If step is positive, the sequence is generated from start to end, otherwise it is generated from end to start.", [["n"], ["start", "end"], ["start", "end", "step"]]),
|
|
1919
2083
|
keys: withDoc(cljNativeFunction("keys", (m) => {
|
|
1920
2084
|
if (m === undefined || !isMap(m)) {
|
|
1921
|
-
throw
|
|
2085
|
+
throw EvaluationError.atArg(`keys expects a map${m !== undefined ? `, got ${printString(m)}` : ""}`, { m }, 0);
|
|
1922
2086
|
}
|
|
1923
2087
|
return cljVector(m.entries.map(([k]) => k));
|
|
1924
2088
|
}), "Returns a vector of the keys of the given map.", [["m"]]),
|
|
1925
2089
|
vals: withDoc(cljNativeFunction("vals", (m) => {
|
|
1926
2090
|
if (m === undefined || !isMap(m)) {
|
|
1927
|
-
throw
|
|
2091
|
+
throw EvaluationError.atArg(`vals expects a map${m !== undefined ? `, got ${printString(m)}` : ""}`, { m }, 0);
|
|
1928
2092
|
}
|
|
1929
2093
|
return cljVector(m.entries.map(([, v]) => v));
|
|
1930
2094
|
}), "Returns a vector of the values of the given map.", [["m"]]),
|
|
@@ -1935,9 +2099,7 @@ var collectionFunctions = {
|
|
|
1935
2099
|
valueKeywords.map,
|
|
1936
2100
|
valueKeywords.string
|
|
1937
2101
|
].includes(countable.kind)) {
|
|
1938
|
-
throw
|
|
1939
|
-
countable
|
|
1940
|
-
});
|
|
2102
|
+
throw EvaluationError.atArg(`count expects a countable value, got ${printString(countable)}`, { countable }, 0);
|
|
1941
2103
|
}
|
|
1942
2104
|
switch (countable.kind) {
|
|
1943
2105
|
case valueKeywords.list:
|
|
@@ -2006,7 +2168,7 @@ var errorFunctions = {
|
|
|
2006
2168
|
var hofFunctions = {
|
|
2007
2169
|
reduce: withDoc(cljNativeFunctionWithContext("reduce", (ctx, callEnv, fn, ...rest) => {
|
|
2008
2170
|
if (fn === undefined || !isAFunction(fn)) {
|
|
2009
|
-
throw
|
|
2171
|
+
throw EvaluationError.atArg(`reduce expects a function as first argument${fn !== undefined ? `, got ${printString(fn)}` : ""}`, { fn }, 0);
|
|
2010
2172
|
}
|
|
2011
2173
|
if (rest.length === 0 || rest.length > 2) {
|
|
2012
2174
|
throw new EvaluationError("reduce expects 2 or 3 arguments: (reduce f coll) or (reduce f init coll)", { fn });
|
|
@@ -2021,7 +2183,7 @@ var hofFunctions = {
|
|
|
2021
2183
|
return init;
|
|
2022
2184
|
}
|
|
2023
2185
|
if (!isSeqable(collection)) {
|
|
2024
|
-
throw
|
|
2186
|
+
throw EvaluationError.atArg(`reduce expects a collection or string, got ${printString(collection)}`, { collection }, rest.length);
|
|
2025
2187
|
}
|
|
2026
2188
|
const items = toSeq(collection);
|
|
2027
2189
|
if (!hasInit) {
|
|
@@ -2053,7 +2215,7 @@ var hofFunctions = {
|
|
|
2053
2215
|
]),
|
|
2054
2216
|
apply: withDoc(cljNativeFunctionWithContext("apply", (ctx, callEnv, fn, ...rest) => {
|
|
2055
2217
|
if (fn === undefined || !isCallable(fn)) {
|
|
2056
|
-
throw
|
|
2218
|
+
throw EvaluationError.atArg(`apply expects a callable as first argument${fn !== undefined ? `, got ${printString(fn)}` : ""}`, { fn }, 0);
|
|
2057
2219
|
}
|
|
2058
2220
|
if (rest.length === 0) {
|
|
2059
2221
|
throw new EvaluationError("apply expects at least 2 arguments", {
|
|
@@ -2062,7 +2224,7 @@ var hofFunctions = {
|
|
|
2062
2224
|
}
|
|
2063
2225
|
const lastArg = rest[rest.length - 1];
|
|
2064
2226
|
if (!isNil(lastArg) && !isSeqable(lastArg)) {
|
|
2065
|
-
throw
|
|
2227
|
+
throw EvaluationError.atArg(`apply expects a collection or string as last argument, got ${printString(lastArg)}`, { lastArg }, rest.length);
|
|
2066
2228
|
}
|
|
2067
2229
|
const args = [
|
|
2068
2230
|
...rest.slice(0, -1),
|
|
@@ -2075,7 +2237,7 @@ var hofFunctions = {
|
|
|
2075
2237
|
]),
|
|
2076
2238
|
partial: withDoc(cljNativeFunction("partial", (fn, ...preArgs) => {
|
|
2077
2239
|
if (fn === undefined || !isCallable(fn)) {
|
|
2078
|
-
throw
|
|
2240
|
+
throw EvaluationError.atArg(`partial expects a callable as first argument${fn !== undefined ? `, got ${printString(fn)}` : ""}`, { fn }, 0);
|
|
2079
2241
|
}
|
|
2080
2242
|
const capturedFn = fn;
|
|
2081
2243
|
return cljNativeFunctionWithContext("partial", (ctx, callEnv, ...moreArgs) => {
|
|
@@ -2086,8 +2248,9 @@ var hofFunctions = {
|
|
|
2086
2248
|
if (fns.length === 0) {
|
|
2087
2249
|
return cljNativeFunction("identity", (x) => x);
|
|
2088
2250
|
}
|
|
2089
|
-
|
|
2090
|
-
|
|
2251
|
+
const badIdx = fns.findIndex((f) => !isCallable(f));
|
|
2252
|
+
if (badIdx !== -1) {
|
|
2253
|
+
throw EvaluationError.atArg("comp expects functions or other callable values (keywords, maps)", { fns }, badIdx);
|
|
2091
2254
|
}
|
|
2092
2255
|
const capturedFns = fns;
|
|
2093
2256
|
return cljNativeFunctionWithContext("composed", (ctx, callEnv, ...args) => {
|
|
@@ -2100,7 +2263,7 @@ var hofFunctions = {
|
|
|
2100
2263
|
}), "Returns the composition of fns, applied right-to-left. (comp f g) is equivalent to (fn [x] (f (g x))). Accepts any callable: functions, keywords, and maps.", [[], ["f"], ["f", "g"], ["f", "g", "&", "fns"]]),
|
|
2101
2264
|
identity: withDoc(cljNativeFunction("identity", (x) => {
|
|
2102
2265
|
if (x === undefined) {
|
|
2103
|
-
throw
|
|
2266
|
+
throw EvaluationError.atArg("identity expects one argument", {}, 0);
|
|
2104
2267
|
}
|
|
2105
2268
|
return x;
|
|
2106
2269
|
}), "Returns its single argument unchanged.", [["x"]])
|
|
@@ -2110,31 +2273,51 @@ var hofFunctions = {
|
|
|
2110
2273
|
var metaFunctions = {
|
|
2111
2274
|
meta: withDoc(cljNativeFunction("meta", (val) => {
|
|
2112
2275
|
if (val === undefined) {
|
|
2113
|
-
throw
|
|
2276
|
+
throw EvaluationError.atArg("meta expects one argument", {}, 0);
|
|
2114
2277
|
}
|
|
2115
|
-
if (val.kind === "function" || val.kind === "native-function") {
|
|
2278
|
+
if (val.kind === "function" || val.kind === "native-function" || val.kind === "var" || val.kind === "list" || val.kind === "vector" || val.kind === "map" || val.kind === "symbol" || val.kind === "atom") {
|
|
2116
2279
|
return val.meta ?? cljNil();
|
|
2117
2280
|
}
|
|
2118
|
-
if (val.kind === "var")
|
|
2119
|
-
return val.meta ?? cljNil();
|
|
2120
2281
|
return cljNil();
|
|
2121
2282
|
}), "Returns the metadata map of a value, or nil if the value has no metadata.", [["val"]]),
|
|
2122
2283
|
"with-meta": withDoc(cljNativeFunction("with-meta", (val, m) => {
|
|
2123
2284
|
if (val === undefined) {
|
|
2124
|
-
throw
|
|
2285
|
+
throw EvaluationError.atArg("with-meta expects two arguments", {}, 0);
|
|
2125
2286
|
}
|
|
2126
2287
|
if (m === undefined) {
|
|
2127
|
-
throw
|
|
2288
|
+
throw EvaluationError.atArg("with-meta expects two arguments", {}, 1);
|
|
2128
2289
|
}
|
|
2129
2290
|
if (m.kind !== "map" && m.kind !== "nil") {
|
|
2130
|
-
throw
|
|
2291
|
+
throw EvaluationError.atArg(`with-meta expects a map as second argument, got ${printString(m)}`, { m }, 1);
|
|
2131
2292
|
}
|
|
2132
|
-
|
|
2133
|
-
|
|
2293
|
+
const metaSupported = val.kind === "function" || val.kind === "native-function" || val.kind === "list" || val.kind === "vector" || val.kind === "map" || val.kind === "symbol";
|
|
2294
|
+
if (!metaSupported) {
|
|
2295
|
+
throw EvaluationError.atArg(`with-meta does not support ${val.kind}, got ${printString(val)}`, { val }, 0);
|
|
2134
2296
|
}
|
|
2135
2297
|
const meta = m.kind === "nil" ? undefined : m;
|
|
2136
2298
|
return { ...val, meta };
|
|
2137
|
-
}), "Returns a new value with the metadata map m applied to val.", [["val", "m"]])
|
|
2299
|
+
}), "Returns a new value with the metadata map m applied to val.", [["val", "m"]]),
|
|
2300
|
+
"alter-meta!": withDoc(cljNativeFunctionWithContext("alter-meta!", (ctx, callEnv, ref, f, ...args) => {
|
|
2301
|
+
if (ref === undefined) {
|
|
2302
|
+
throw EvaluationError.atArg("alter-meta! expects at least two arguments", {}, 0);
|
|
2303
|
+
}
|
|
2304
|
+
if (f === undefined) {
|
|
2305
|
+
throw EvaluationError.atArg("alter-meta! expects at least two arguments", {}, 1);
|
|
2306
|
+
}
|
|
2307
|
+
if (ref.kind !== "var" && ref.kind !== "atom") {
|
|
2308
|
+
throw EvaluationError.atArg(`alter-meta! expects a Var or Atom as first argument, got ${ref.kind}`, {}, 0);
|
|
2309
|
+
}
|
|
2310
|
+
if (!isAFunction(f)) {
|
|
2311
|
+
throw EvaluationError.atArg(`alter-meta! expects a function as second argument, got ${f.kind}`, {}, 1);
|
|
2312
|
+
}
|
|
2313
|
+
const currentMeta = ref.meta ?? cljNil();
|
|
2314
|
+
const newMeta = ctx.applyCallable(f, [currentMeta, ...args], callEnv);
|
|
2315
|
+
if (newMeta.kind !== "map" && newMeta.kind !== "nil") {
|
|
2316
|
+
throw new EvaluationError(`alter-meta! function must return a map or nil, got ${newMeta.kind}`, {});
|
|
2317
|
+
}
|
|
2318
|
+
ref.meta = newMeta.kind === "nil" ? undefined : newMeta;
|
|
2319
|
+
return newMeta;
|
|
2320
|
+
}), "Applies f to ref's current metadata (with optional args), sets the result as the new metadata, and returns it.", [["ref", "f", "&", "args"]])
|
|
2138
2321
|
};
|
|
2139
2322
|
|
|
2140
2323
|
// src/core/evaluator/apply.ts
|
|
@@ -2233,45 +2416,12 @@ function macroExpandAllWithContext(form, env, ctx) {
|
|
|
2233
2416
|
return expanded.every((e, i) => e === form.value[i]) ? form : cljList(expanded);
|
|
2234
2417
|
}
|
|
2235
2418
|
|
|
2236
|
-
// src/core/positions.ts
|
|
2237
|
-
function setPos(val, pos) {
|
|
2238
|
-
Object.defineProperty(val, "_pos", {
|
|
2239
|
-
value: pos,
|
|
2240
|
-
enumerable: false,
|
|
2241
|
-
writable: true,
|
|
2242
|
-
configurable: true
|
|
2243
|
-
});
|
|
2244
|
-
}
|
|
2245
|
-
function getPos(val) {
|
|
2246
|
-
return val._pos;
|
|
2247
|
-
}
|
|
2248
|
-
function getLineCol(source, offset) {
|
|
2249
|
-
const lines = source.split(`
|
|
2250
|
-
`);
|
|
2251
|
-
let pos = 0;
|
|
2252
|
-
for (let i = 0;i < lines.length; i++) {
|
|
2253
|
-
const lineEnd = pos + lines[i].length;
|
|
2254
|
-
if (offset <= lineEnd) {
|
|
2255
|
-
return { line: i + 1, col: offset - pos, lineText: lines[i] };
|
|
2256
|
-
}
|
|
2257
|
-
pos = lineEnd + 1;
|
|
2258
|
-
}
|
|
2259
|
-
const last = lines[lines.length - 1];
|
|
2260
|
-
return { line: lines.length, col: last.length, lineText: last };
|
|
2261
|
-
}
|
|
2262
|
-
function formatErrorContext(source, pos) {
|
|
2263
|
-
const { line, col, lineText } = getLineCol(source, pos.start);
|
|
2264
|
-
const span = Math.max(1, pos.end - pos.start);
|
|
2265
|
-
const caret = " ".repeat(col) + "^".repeat(span);
|
|
2266
|
-
return `
|
|
2267
|
-
at line ${line}, col ${col + 1}:
|
|
2268
|
-
${lineText}
|
|
2269
|
-
${caret}`;
|
|
2270
|
-
}
|
|
2271
|
-
|
|
2272
2419
|
// src/core/evaluator/collections.ts
|
|
2273
2420
|
function evaluateVector(vector, env, ctx) {
|
|
2274
|
-
|
|
2421
|
+
const evaluated = vector.value.map((v) => ctx.evaluate(v, env));
|
|
2422
|
+
if (vector.meta)
|
|
2423
|
+
return { kind: "vector", value: evaluated, meta: vector.meta };
|
|
2424
|
+
return cljVector(evaluated);
|
|
2275
2425
|
}
|
|
2276
2426
|
function evaluateMap(map, env, ctx) {
|
|
2277
2427
|
let entries = [];
|
|
@@ -2280,6 +2430,8 @@ function evaluateMap(map, env, ctx) {
|
|
|
2280
2430
|
const evaluatedValue = ctx.evaluate(value, env);
|
|
2281
2431
|
entries.push([evaluatedKey, evaluatedValue]);
|
|
2282
2432
|
}
|
|
2433
|
+
if (map.meta)
|
|
2434
|
+
return { kind: "map", entries, meta: map.meta };
|
|
2283
2435
|
return cljMap(entries);
|
|
2284
2436
|
}
|
|
2285
2437
|
|
|
@@ -2311,7 +2463,19 @@ function evaluateList(list, env, ctx) {
|
|
|
2311
2463
|
throw new EvaluationError(`${name} is not callable`, { list, env });
|
|
2312
2464
|
}
|
|
2313
2465
|
const args = list.value.slice(1).map((v) => ctx.evaluate(v, env));
|
|
2314
|
-
|
|
2466
|
+
try {
|
|
2467
|
+
return ctx.applyCallable(evaledFirst, args, env);
|
|
2468
|
+
} catch (e) {
|
|
2469
|
+
if (e instanceof EvaluationError && e.data?.argIndex !== undefined && !e.pos) {
|
|
2470
|
+
const argForm = list.value[e.data.argIndex + 1];
|
|
2471
|
+
if (argForm) {
|
|
2472
|
+
const pos = getPos(argForm);
|
|
2473
|
+
if (pos)
|
|
2474
|
+
e.pos = pos;
|
|
2475
|
+
}
|
|
2476
|
+
}
|
|
2477
|
+
throw e;
|
|
2478
|
+
}
|
|
2315
2479
|
}
|
|
2316
2480
|
|
|
2317
2481
|
// src/core/evaluator/evaluate.ts
|
|
@@ -2447,13 +2611,13 @@ var predicateFunctions = {
|
|
|
2447
2611
|
"coll?": withDoc(cljNativeFunction("coll?", (x) => cljBoolean(x !== undefined && isCollection(x))), "Returns true if the value is a collection, false otherwise.", [["x"]]),
|
|
2448
2612
|
some: withDoc(cljNativeFunction("some", (pred, coll) => {
|
|
2449
2613
|
if (pred === undefined || !isAFunction(pred)) {
|
|
2450
|
-
throw
|
|
2614
|
+
throw EvaluationError.atArg(`some expects a function as first argument${pred !== undefined ? `, got ${printString(pred)}` : ""}`, { pred }, 0);
|
|
2451
2615
|
}
|
|
2452
2616
|
if (coll === undefined) {
|
|
2453
2617
|
return cljNil();
|
|
2454
2618
|
}
|
|
2455
2619
|
if (!isSeqable(coll)) {
|
|
2456
|
-
throw
|
|
2620
|
+
throw EvaluationError.atArg(`some expects a collection or string as second argument, got ${printString(coll)}`, { coll }, 1);
|
|
2457
2621
|
}
|
|
2458
2622
|
for (const item of toSeq(coll)) {
|
|
2459
2623
|
const result = applyFunction(pred, [item]);
|
|
@@ -2465,10 +2629,10 @@ var predicateFunctions = {
|
|
|
2465
2629
|
}), "Returns the first truthy result of applying pred to each item in coll, or nil if no item satisfies pred.", [["pred", "coll"]]),
|
|
2466
2630
|
"every?": withDoc(cljNativeFunction("every?", (pred, coll) => {
|
|
2467
2631
|
if (pred === undefined || !isAFunction(pred)) {
|
|
2468
|
-
throw
|
|
2632
|
+
throw EvaluationError.atArg(`every? expects a function as first argument${pred !== undefined ? `, got ${printString(pred)}` : ""}`, { pred }, 0);
|
|
2469
2633
|
}
|
|
2470
2634
|
if (coll === undefined || !isSeqable(coll)) {
|
|
2471
|
-
throw
|
|
2635
|
+
throw EvaluationError.atArg(`every? expects a collection or string as second argument${coll !== undefined ? `, got ${printString(coll)}` : ""}`, { coll }, 1);
|
|
2472
2636
|
}
|
|
2473
2637
|
for (const item of toSeq(coll)) {
|
|
2474
2638
|
if (isFalsy(applyFunction(pred, [item]))) {
|
|
@@ -2875,13 +3039,13 @@ var utilFunctions = {
|
|
|
2875
3039
|
}), "Returns a concatenated string representation of the given values.", [["&", "args"]]),
|
|
2876
3040
|
subs: withDoc(cljNativeFunction("subs", (s, start, end) => {
|
|
2877
3041
|
if (s === undefined || s.kind !== "string") {
|
|
2878
|
-
throw
|
|
3042
|
+
throw EvaluationError.atArg(`subs expects a string as first argument${s !== undefined ? `, got ${printString(s)}` : ""}`, { s }, 0);
|
|
2879
3043
|
}
|
|
2880
3044
|
if (start === undefined || start.kind !== "number") {
|
|
2881
|
-
throw
|
|
3045
|
+
throw EvaluationError.atArg(`subs expects a number as second argument${start !== undefined ? `, got ${printString(start)}` : ""}`, { start }, 1);
|
|
2882
3046
|
}
|
|
2883
3047
|
if (end !== undefined && end.kind !== "number") {
|
|
2884
|
-
throw
|
|
3048
|
+
throw EvaluationError.atArg(`subs expects a number as optional third argument${end !== undefined ? `, got ${printString(end)}` : ""}`, { end }, 2);
|
|
2885
3049
|
}
|
|
2886
3050
|
const from = start.value;
|
|
2887
3051
|
const to = end?.value;
|
|
@@ -2921,7 +3085,7 @@ var utilFunctions = {
|
|
|
2921
3085
|
}
|
|
2922
3086
|
const prefix = args[0];
|
|
2923
3087
|
if (prefix !== undefined && prefix.kind !== "string") {
|
|
2924
|
-
throw
|
|
3088
|
+
throw EvaluationError.atArg(`gensym prefix must be a string${prefix !== undefined ? `, got ${printString(prefix)}` : ""}`, { prefix }, 0);
|
|
2925
3089
|
}
|
|
2926
3090
|
const p = prefix?.kind === "string" ? prefix.value : "G";
|
|
2927
3091
|
return cljSymbol(makeGensym(p));
|
|
@@ -2932,9 +3096,8 @@ var utilFunctions = {
|
|
|
2932
3096
|
form
|
|
2933
3097
|
});
|
|
2934
3098
|
}
|
|
2935
|
-
const
|
|
2936
|
-
|
|
2937
|
-
return ctx.evaluate(expanded, rootEnv);
|
|
3099
|
+
const expanded = ctx.expandAll(form, callEnv);
|
|
3100
|
+
return ctx.evaluate(expanded, callEnv);
|
|
2938
3101
|
}), "Evaluates the given form in the global environment and returns the result.", [["form"]]),
|
|
2939
3102
|
"macroexpand-1": withDoc(cljNativeFunctionWithContext("macroexpand-1", (ctx, callEnv, form) => {
|
|
2940
3103
|
if (!isList(form) || form.value.length === 0)
|
|
@@ -2942,7 +3105,7 @@ var utilFunctions = {
|
|
|
2942
3105
|
const head = form.value[0];
|
|
2943
3106
|
if (!isSymbol(head))
|
|
2944
3107
|
return form;
|
|
2945
|
-
const macroValue = tryLookup(head.name,
|
|
3108
|
+
const macroValue = tryLookup(head.name, callEnv);
|
|
2946
3109
|
if (macroValue === undefined)
|
|
2947
3110
|
return form;
|
|
2948
3111
|
if (!isMacro(macroValue))
|
|
@@ -2950,7 +3113,6 @@ var utilFunctions = {
|
|
|
2950
3113
|
return ctx.applyMacro(macroValue, form.value.slice(1));
|
|
2951
3114
|
}), "If the head of the form is a macro, expands it and returns the resulting forms. Otherwise, returns the form unchanged.", [["form"]]),
|
|
2952
3115
|
macroexpand: withDoc(cljNativeFunctionWithContext("macroexpand", (ctx, callEnv, form) => {
|
|
2953
|
-
const rootEnv = getRootEnv(callEnv);
|
|
2954
3116
|
let current = form;
|
|
2955
3117
|
while (true) {
|
|
2956
3118
|
if (!isList(current) || current.value.length === 0)
|
|
@@ -2958,7 +3120,7 @@ var utilFunctions = {
|
|
|
2958
3120
|
const head = current.value[0];
|
|
2959
3121
|
if (!isSymbol(head))
|
|
2960
3122
|
return current;
|
|
2961
|
-
const macroValue = tryLookup(head.name,
|
|
3123
|
+
const macroValue = tryLookup(head.name, callEnv);
|
|
2962
3124
|
if (macroValue === undefined)
|
|
2963
3125
|
return current;
|
|
2964
3126
|
if (!isMacro(macroValue))
|
|
@@ -2970,7 +3132,7 @@ var utilFunctions = {
|
|
|
2970
3132
|
"",
|
|
2971
3133
|
"Note neither macroexpand-1 nor macroexpand will expand macros in sub-forms"
|
|
2972
3134
|
]), [["form"]]),
|
|
2973
|
-
"macroexpand-all": withDoc(cljNativeFunctionWithContext("macroexpand-all", (ctx, callEnv, form) => ctx.expandAll(form,
|
|
3135
|
+
"macroexpand-all": withDoc(cljNativeFunctionWithContext("macroexpand-all", (ctx, callEnv, form) => ctx.expandAll(form, callEnv)), joinLines([
|
|
2974
3136
|
"Fully expands all macros in a form recursively — including in sub-forms.",
|
|
2975
3137
|
"",
|
|
2976
3138
|
"Unlike macroexpand, this descends into every sub-expression.",
|
|
@@ -2978,7 +3140,7 @@ var utilFunctions = {
|
|
|
2978
3140
|
]), [["form"]]),
|
|
2979
3141
|
namespace: withDoc(cljNativeFunction("namespace", (x) => {
|
|
2980
3142
|
if (x === undefined) {
|
|
2981
|
-
throw
|
|
3143
|
+
throw EvaluationError.atArg("namespace expects an argument", { x }, 0);
|
|
2982
3144
|
}
|
|
2983
3145
|
let raw;
|
|
2984
3146
|
if (isKeyword(x)) {
|
|
@@ -2986,7 +3148,7 @@ var utilFunctions = {
|
|
|
2986
3148
|
} else if (isSymbol(x)) {
|
|
2987
3149
|
raw = x.name;
|
|
2988
3150
|
} else {
|
|
2989
|
-
throw
|
|
3151
|
+
throw EvaluationError.atArg(`namespace expects a keyword or symbol, got ${printString(x)}`, { x }, 0);
|
|
2990
3152
|
}
|
|
2991
3153
|
const slashIdx = raw.indexOf("/");
|
|
2992
3154
|
if (slashIdx <= 0)
|
|
@@ -2995,7 +3157,7 @@ var utilFunctions = {
|
|
|
2995
3157
|
}), "Returns the namespace string of a qualified keyword or symbol, or nil if the argument is not qualified.", [["x"]]),
|
|
2996
3158
|
name: withDoc(cljNativeFunction("name", (x) => {
|
|
2997
3159
|
if (x === undefined) {
|
|
2998
|
-
throw
|
|
3160
|
+
throw EvaluationError.atArg("name expects an argument", { x }, 0);
|
|
2999
3161
|
}
|
|
3000
3162
|
let raw;
|
|
3001
3163
|
if (isKeyword(x)) {
|
|
@@ -3005,7 +3167,7 @@ var utilFunctions = {
|
|
|
3005
3167
|
} else if (x.kind === "string") {
|
|
3006
3168
|
return x;
|
|
3007
3169
|
} else {
|
|
3008
|
-
throw
|
|
3170
|
+
throw EvaluationError.atArg(`name expects a keyword, symbol, or string, got ${printString(x)}`, { x }, 0);
|
|
3009
3171
|
}
|
|
3010
3172
|
const slashIdx = raw.indexOf("/");
|
|
3011
3173
|
return cljString(slashIdx >= 0 ? raw.slice(slashIdx + 1) : raw);
|
|
@@ -3017,13 +3179,13 @@ var utilFunctions = {
|
|
|
3017
3179
|
});
|
|
3018
3180
|
}
|
|
3019
3181
|
if (args[0].kind !== "string") {
|
|
3020
|
-
throw
|
|
3182
|
+
throw EvaluationError.atArg(`keyword expects a string, got ${printString(args[0])}`, { args }, 0);
|
|
3021
3183
|
}
|
|
3022
3184
|
if (args.length === 1) {
|
|
3023
3185
|
return cljKeyword(`:${args[0].value}`);
|
|
3024
3186
|
}
|
|
3025
3187
|
if (args[1].kind !== "string") {
|
|
3026
|
-
throw
|
|
3188
|
+
throw EvaluationError.atArg(`keyword second argument must be a string, got ${printString(args[1])}`, { args }, 1);
|
|
3027
3189
|
}
|
|
3028
3190
|
return cljKeyword(`:${args[0].value}/${args[1].value}`);
|
|
3029
3191
|
}), joinLines([
|
|
@@ -3078,14 +3240,14 @@ var nativeFunctions = {
|
|
|
3078
3240
|
};
|
|
3079
3241
|
function loadCoreFunctions(env, output) {
|
|
3080
3242
|
for (const [key, value] of Object.entries(nativeFunctions)) {
|
|
3081
|
-
|
|
3243
|
+
internVar(key, value, env);
|
|
3082
3244
|
}
|
|
3083
3245
|
const emit = output ?? ((text) => console.log(text));
|
|
3084
|
-
|
|
3246
|
+
internVar("println", cljNativeFunction("println", (...args) => {
|
|
3085
3247
|
emit(args.map(valueToString).join(" "));
|
|
3086
3248
|
return cljNil();
|
|
3087
3249
|
}), env);
|
|
3088
|
-
|
|
3250
|
+
internVar("print", cljNativeFunction("print", (...args) => {
|
|
3089
3251
|
emit(args.map(valueToString).join(" "));
|
|
3090
3252
|
return cljNil();
|
|
3091
3253
|
}), env);
|
|
@@ -3201,7 +3363,8 @@ var isNumber = (char) => {
|
|
|
3201
3363
|
var isDot = (char) => char === ".";
|
|
3202
3364
|
var isKeywordStart = (char) => char === ":";
|
|
3203
3365
|
var isHash = (char) => char === "#";
|
|
3204
|
-
var
|
|
3366
|
+
var isCaret = (char) => char === "^";
|
|
3367
|
+
var isDelimiter = (char) => isLParen(char) || isRParen(char) || isLBracket(char) || isRBracket(char) || isLBrace(char) || isRBrace(char) || isBacktick(char) || isSingleQuote(char) || isAt(char) || isCaret(char);
|
|
3205
3368
|
var parseWhitespace = (ctx) => {
|
|
3206
3369
|
const scanner = ctx.scanner;
|
|
3207
3370
|
const start = scanner.position();
|
|
@@ -3347,6 +3510,12 @@ var parseDerefToken = (ctx) => {
|
|
|
3347
3510
|
scanner.advance();
|
|
3348
3511
|
return { kind: "Deref", start, end: scanner.position() };
|
|
3349
3512
|
};
|
|
3513
|
+
var parseMetaToken = (ctx) => {
|
|
3514
|
+
const scanner = ctx.scanner;
|
|
3515
|
+
const start = scanner.position();
|
|
3516
|
+
scanner.advance();
|
|
3517
|
+
return { kind: "Meta", start, end: scanner.position() };
|
|
3518
|
+
};
|
|
3350
3519
|
var parseRegexLiteral = (ctx, start) => {
|
|
3351
3520
|
const scanner = ctx.scanner;
|
|
3352
3521
|
scanner.advance();
|
|
@@ -3463,6 +3632,7 @@ var tokenParseEntries = [
|
|
|
3463
3632
|
],
|
|
3464
3633
|
[isTilde, parseTilde],
|
|
3465
3634
|
[isAt, parseDerefToken],
|
|
3635
|
+
[isCaret, parseMetaToken],
|
|
3466
3636
|
[isHash, parseDispatch]
|
|
3467
3637
|
];
|
|
3468
3638
|
function parseNextToken(ctx) {
|
|
@@ -3612,6 +3782,35 @@ var readUnquote = (ctx) => {
|
|
|
3612
3782
|
}
|
|
3613
3783
|
return { kind: valueKeywords.list, value: [cljSymbol("unquote"), value] };
|
|
3614
3784
|
};
|
|
3785
|
+
var readMeta = (ctx) => {
|
|
3786
|
+
const scanner = ctx.scanner;
|
|
3787
|
+
const token = scanner.peek();
|
|
3788
|
+
if (!token) {
|
|
3789
|
+
throw new ReaderError("Unexpected end of input while parsing metadata", scanner.position());
|
|
3790
|
+
}
|
|
3791
|
+
scanner.advance();
|
|
3792
|
+
const metaForm = readForm(ctx);
|
|
3793
|
+
const target = readForm(ctx);
|
|
3794
|
+
let metaEntries;
|
|
3795
|
+
if (metaForm.kind === "keyword") {
|
|
3796
|
+
metaEntries = [[metaForm, cljBoolean(true)]];
|
|
3797
|
+
} else if (metaForm.kind === "map") {
|
|
3798
|
+
metaEntries = metaForm.entries;
|
|
3799
|
+
} else if (metaForm.kind === "symbol") {
|
|
3800
|
+
metaEntries = [[cljKeyword(":tag"), metaForm]];
|
|
3801
|
+
} else {
|
|
3802
|
+
throw new ReaderError("Metadata must be a keyword, map, or symbol", token);
|
|
3803
|
+
}
|
|
3804
|
+
if (target.kind === "symbol" || target.kind === "list" || target.kind === "vector" || target.kind === "map") {
|
|
3805
|
+
const existingEntries = target.meta ? target.meta.entries : [];
|
|
3806
|
+
const result = { ...target, meta: cljMap([...existingEntries, ...metaEntries]) };
|
|
3807
|
+
const pos = getPos(target);
|
|
3808
|
+
if (pos)
|
|
3809
|
+
setPos(result, pos);
|
|
3810
|
+
return result;
|
|
3811
|
+
}
|
|
3812
|
+
return target;
|
|
3813
|
+
};
|
|
3615
3814
|
var readVarQuote = (ctx) => {
|
|
3616
3815
|
const scanner = ctx.scanner;
|
|
3617
3816
|
const token = scanner.peek();
|
|
@@ -3945,6 +4144,8 @@ function readForm(ctx) {
|
|
|
3945
4144
|
return readDeref(ctx);
|
|
3946
4145
|
case tokenKeywords.VarQuote:
|
|
3947
4146
|
return readVarQuote(ctx);
|
|
4147
|
+
case tokenKeywords.Meta:
|
|
4148
|
+
return readMeta(ctx);
|
|
3948
4149
|
case tokenKeywords.Regex:
|
|
3949
4150
|
return readRegex(ctx);
|
|
3950
4151
|
default:
|
|
@@ -3979,6 +4180,13 @@ var clojure_coreSource = `(ns clojure.core)
|
|
|
3979
4180
|
\`(def ~name (with-meta (fn ~@rest-decl) {:doc ~doc :arglists '~arglists}))
|
|
3980
4181
|
\`(def ~name (with-meta (fn ~@rest-decl) {:arglists '~arglists})))))
|
|
3981
4182
|
|
|
4183
|
+
|
|
4184
|
+
(defn vary-meta
|
|
4185
|
+
"Returns an object of the same type and value as obj, with
|
|
4186
|
+
(apply f (meta obj) args) as its metadata."
|
|
4187
|
+
[obj f & args]
|
|
4188
|
+
(with-meta obj (apply f (meta obj) args)))
|
|
4189
|
+
|
|
3982
4190
|
(defn next
|
|
3983
4191
|
"Returns a seq of the items after the first. Calls seq on its
|
|
3984
4192
|
argument. If there are no more items, returns nil."
|
|
@@ -5009,11 +5217,11 @@ function buildSessionApi(state, options) {
|
|
|
5009
5217
|
const coreEnv = registry.get("clojure.core");
|
|
5010
5218
|
coreEnv.resolveNs = (name) => registry.get(name) ?? null;
|
|
5011
5219
|
const emitFn = options?.output ?? ((text) => console.log(text));
|
|
5012
|
-
|
|
5220
|
+
internVar("println", cljNativeFunction("println", (...args) => {
|
|
5013
5221
|
emitFn(args.map(valueToString).join(" "));
|
|
5014
5222
|
return cljNil();
|
|
5015
5223
|
}), coreEnv);
|
|
5016
|
-
|
|
5224
|
+
internVar("print", cljNativeFunction("print", (...args) => {
|
|
5017
5225
|
emitFn(args.map(valueToString).join(" "));
|
|
5018
5226
|
return cljNil();
|
|
5019
5227
|
}), coreEnv);
|
|
@@ -5063,14 +5271,14 @@ function buildSessionApi(state, options) {
|
|
|
5063
5271
|
function getNsEnv(name) {
|
|
5064
5272
|
return registry.get(name) ?? null;
|
|
5065
5273
|
}
|
|
5066
|
-
|
|
5274
|
+
internVar("require", cljNativeFunction("require", (...args) => {
|
|
5067
5275
|
const currentEnv = registry.get(currentNs);
|
|
5068
5276
|
for (const arg of args) {
|
|
5069
5277
|
processRequireSpec(arg, currentEnv, registry, resolveNamespace);
|
|
5070
5278
|
}
|
|
5071
5279
|
return cljNil();
|
|
5072
5280
|
}), coreEnv);
|
|
5073
|
-
|
|
5281
|
+
internVar("resolve", cljNativeFunction("resolve", (sym) => {
|
|
5074
5282
|
if (!isSymbol(sym))
|
|
5075
5283
|
return cljNil();
|
|
5076
5284
|
const slashIdx = sym.name.indexOf("/");
|
|
@@ -5093,16 +5301,25 @@ function buildSessionApi(state, options) {
|
|
|
5093
5301
|
}
|
|
5094
5302
|
}
|
|
5095
5303
|
}
|
|
5096
|
-
function loadFile(source, nsName) {
|
|
5304
|
+
function loadFile(source, nsName, filePath) {
|
|
5097
5305
|
const tokens = tokenize(source);
|
|
5098
5306
|
const targetNs = extractNsNameFromTokens(tokens) ?? nsName ?? "user";
|
|
5099
5307
|
const aliasMap = extractAliasMapFromTokens(tokens);
|
|
5100
5308
|
const forms = readForms(tokens, targetNs, aliasMap);
|
|
5101
5309
|
const env = ensureNs(targetNs);
|
|
5310
|
+
ctx.currentSource = source;
|
|
5311
|
+
ctx.currentFile = filePath;
|
|
5312
|
+
ctx.currentLineOffset = 0;
|
|
5313
|
+
ctx.currentColOffset = 0;
|
|
5102
5314
|
processNsRequires(forms, env);
|
|
5103
|
-
|
|
5104
|
-
const
|
|
5105
|
-
|
|
5315
|
+
try {
|
|
5316
|
+
for (const form of forms) {
|
|
5317
|
+
const expanded = ctx.expandAll(form, env);
|
|
5318
|
+
ctx.evaluate(expanded, env);
|
|
5319
|
+
}
|
|
5320
|
+
} finally {
|
|
5321
|
+
ctx.currentSource = undefined;
|
|
5322
|
+
ctx.currentFile = undefined;
|
|
5106
5323
|
}
|
|
5107
5324
|
return targetNs;
|
|
5108
5325
|
}
|
|
@@ -5115,7 +5332,11 @@ function buildSessionApi(state, options) {
|
|
|
5115
5332
|
getNs,
|
|
5116
5333
|
loadFile,
|
|
5117
5334
|
addSourceRoot,
|
|
5118
|
-
evaluate(source) {
|
|
5335
|
+
evaluate(source, opts) {
|
|
5336
|
+
ctx.currentSource = source;
|
|
5337
|
+
ctx.currentFile = opts?.file;
|
|
5338
|
+
ctx.currentLineOffset = opts?.lineOffset ?? 0;
|
|
5339
|
+
ctx.currentColOffset = opts?.colOffset ?? 0;
|
|
5119
5340
|
try {
|
|
5120
5341
|
const tokens = tokenize(source);
|
|
5121
5342
|
const declaredNs = extractNsNameFromTokens(tokens);
|
|
@@ -5149,9 +5370,15 @@ function buildSessionApi(state, options) {
|
|
|
5149
5370
|
});
|
|
5150
5371
|
}
|
|
5151
5372
|
if ((e instanceof EvaluationError || e instanceof ReaderError) && e.pos) {
|
|
5152
|
-
e.message += formatErrorContext(source, e.pos
|
|
5373
|
+
e.message += formatErrorContext(source, e.pos, {
|
|
5374
|
+
lineOffset: ctx.currentLineOffset,
|
|
5375
|
+
colOffset: ctx.currentColOffset
|
|
5376
|
+
});
|
|
5153
5377
|
}
|
|
5154
5378
|
throw e;
|
|
5379
|
+
} finally {
|
|
5380
|
+
ctx.currentSource = undefined;
|
|
5381
|
+
ctx.currentFile = undefined;
|
|
5155
5382
|
}
|
|
5156
5383
|
},
|
|
5157
5384
|
evaluateForms(forms) {
|
|
@@ -5431,7 +5658,7 @@ class BDecoderStream extends stream.Transform {
|
|
|
5431
5658
|
}
|
|
5432
5659
|
|
|
5433
5660
|
// src/bin/version.ts
|
|
5434
|
-
var VERSION = "0.0.
|
|
5661
|
+
var VERSION = "0.0.12";
|
|
5435
5662
|
|
|
5436
5663
|
// src/host/node.ts
|
|
5437
5664
|
import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync } from "node:fs";
|
|
@@ -5534,8 +5761,10 @@ function handleEval(msg, managed, encoder) {
|
|
|
5534
5761
|
const id = msg["id"] ?? "";
|
|
5535
5762
|
const code = msg["code"] ?? "";
|
|
5536
5763
|
managed.currentMsgId = id;
|
|
5764
|
+
const lineOffset = typeof msg["line"] === "number" ? msg["line"] - 1 : 0;
|
|
5765
|
+
const colOffset = typeof msg["column"] === "number" ? msg["column"] - 1 : 0;
|
|
5537
5766
|
try {
|
|
5538
|
-
const result = managed.session.evaluate(code);
|
|
5767
|
+
const result = managed.session.evaluate(code, { lineOffset, colOffset });
|
|
5539
5768
|
done(encoder, id, managed.id, {
|
|
5540
5769
|
value: printString(result),
|
|
5541
5770
|
ns: managed.session.currentNs
|
|
@@ -5565,7 +5794,7 @@ function handleLoadFile(msg, managed, encoder) {
|
|
|
5565
5794
|
}
|
|
5566
5795
|
}
|
|
5567
5796
|
const nsHint = fileName.replace(/\.clj$/, "").replace(/\//g, ".") || undefined;
|
|
5568
|
-
const loadedNs = managed.session.loadFile(source, nsHint);
|
|
5797
|
+
const loadedNs = managed.session.loadFile(source, nsHint, filePath || undefined);
|
|
5569
5798
|
if (filePath && loadedNs) {
|
|
5570
5799
|
managed.nsToFile.set(loadedNs, filePath);
|
|
5571
5800
|
}
|
|
@@ -5705,13 +5934,30 @@ function handleInfo(msg, managed, encoder) {
|
|
|
5705
5934
|
}
|
|
5706
5935
|
const meta = extractMeta(resolved.value);
|
|
5707
5936
|
const file = managed.nsToFile.get(resolved.resolvedNs);
|
|
5937
|
+
let varLine;
|
|
5938
|
+
let varColumn;
|
|
5939
|
+
let varFile;
|
|
5940
|
+
if (resolved.value.kind === "var" && resolved.value.meta) {
|
|
5941
|
+
for (const [k, v] of resolved.value.meta.entries) {
|
|
5942
|
+
if (k.kind !== "keyword")
|
|
5943
|
+
continue;
|
|
5944
|
+
if (k.name === ":line" && v.kind === "number")
|
|
5945
|
+
varLine = v.value;
|
|
5946
|
+
if (k.name === ":column" && v.kind === "number")
|
|
5947
|
+
varColumn = v.value;
|
|
5948
|
+
if (k.name === ":file" && v.kind === "string")
|
|
5949
|
+
varFile = v.value;
|
|
5950
|
+
}
|
|
5951
|
+
}
|
|
5708
5952
|
done(encoder, id, managed.id, {
|
|
5709
5953
|
ns: resolved.resolvedNs,
|
|
5710
5954
|
name: resolved.localName,
|
|
5711
5955
|
doc: meta.doc,
|
|
5712
5956
|
"arglists-str": meta.arglistsStr,
|
|
5713
5957
|
type: meta.type,
|
|
5714
|
-
...file ? { file } : {}
|
|
5958
|
+
...varFile ?? file ? { file: varFile ?? file } : {},
|
|
5959
|
+
...varLine !== undefined ? { line: varLine } : {},
|
|
5960
|
+
...varColumn !== undefined ? { column: varColumn } : {}
|
|
5715
5961
|
});
|
|
5716
5962
|
}
|
|
5717
5963
|
function handleLookup(msg, managed, encoder) {
|