funcity 0.2.0 → 0.4.0

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/index.cjs CHANGED
@@ -1,19 +1,227 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const emptyLocation = {
4
+ line: 0,
5
+ column: 0
6
+ };
7
+ const emptyRange = {
8
+ start: emptyLocation,
9
+ end: emptyLocation
10
+ };
11
+ const specialFunctionMarker = /* @__PURE__ */ Symbol("$$special$$");
12
+ const makeFunCityFunction = (f) => {
13
+ f[specialFunctionMarker] = true;
14
+ return f;
15
+ };
16
+ const isFunCityFunction = (f) => {
17
+ var _a;
18
+ return (_a = f[specialFunctionMarker]) != null ? _a : false;
19
+ };
20
+ const isConditionalTrue = (v) => {
21
+ if (v === void 0 || v === null) {
22
+ return false;
23
+ }
24
+ switch (typeof v) {
25
+ case "boolean":
26
+ return v;
27
+ case "number":
28
+ case "bigint":
29
+ return v !== 0;
30
+ default:
31
+ return true;
32
+ }
33
+ };
34
+ const asIterable = (v) => {
35
+ if (typeof v[Symbol.iterator] === "function") {
36
+ return v;
37
+ } else {
38
+ return void 0;
39
+ }
40
+ };
41
+ const combineVariables = (...variablesList) => {
42
+ const variables = /* @__PURE__ */ new Map();
43
+ const appendVariables = (vs) => vs.forEach((v, k) => variables.set(k, v));
44
+ const appendRecord = (vs) => Object.keys(vs).forEach((k) => variables.set(k, vs[k]));
45
+ variablesList.forEach((vs) => {
46
+ if (vs["forEach"] !== void 0) {
47
+ appendVariables(vs);
48
+ } else {
49
+ appendRecord(vs);
50
+ }
51
+ });
52
+ return variables;
53
+ };
54
+ const fromError = (error) => {
55
+ var _a;
56
+ if (error.message) {
57
+ return error.message;
58
+ } else if (typeof error.toString === "function") {
59
+ return (_a = error.toString()) != null ? _a : "unknown";
60
+ } else {
61
+ return "unknown";
62
+ }
63
+ };
64
+ const widerRange = (...ranges) => {
65
+ let start = emptyRange.start;
66
+ let end = emptyRange.end;
67
+ for (const range of ranges) {
68
+ if (range.start.line >= 1 && range.start.column >= 1) {
69
+ if (start.line === 0 || start.column === 0) {
70
+ start = range.start;
71
+ } else if (range.start.line < start.line) {
72
+ start = range.start;
73
+ } else if (range.start.line === start.line && range.start.column < start.column) {
74
+ start = range.start;
75
+ }
76
+ if (end.line === 0 || end.column === 0) {
77
+ end = range.end;
78
+ } else if (range.end.line > end.line) {
79
+ end = range.end;
80
+ } else if (range.end.line === end.line && range.end.column > end.column) {
81
+ end = range.end;
82
+ }
83
+ }
84
+ }
85
+ return { start, end };
86
+ };
87
+ const locationEquals = (lhs, rhs) => lhs.line === rhs.line && lhs.column === rhs.column;
88
+ const getLocationString = (range) => locationEquals(range.start, range.end) ? `${range.start.line}:${range.start.column}` : `${range.start.line}:${range.start.column}:${range.end.line}:${range.end.column}`;
89
+ const printErrorString = (path, error) => {
90
+ switch (error.type) {
91
+ case "warning":
92
+ console.warn(
93
+ `${path}:${getLocationString(error.range)}: warning: ${error.description}`
94
+ );
95
+ break;
96
+ case "error":
97
+ console.error(
98
+ `${path}:${getLocationString(error.range)}: error: ${error.description}`
99
+ );
100
+ return true;
101
+ }
102
+ return false;
103
+ };
104
+ const outputErrors = (path, errors) => {
105
+ let isError = false;
106
+ for (const error of errors) {
107
+ const result = printErrorString(path, error);
108
+ isError || (isError = result);
109
+ }
110
+ return isError;
111
+ };
112
+ const funcIds = /* @__PURE__ */ new WeakMap();
113
+ let nextId = 1;
114
+ const getFuncId = (fn) => {
115
+ const cached = funcIds.get(fn);
116
+ if (cached) {
117
+ return cached;
118
+ }
119
+ const id = nextId++;
120
+ funcIds.set(fn, id);
121
+ return id;
122
+ };
123
+ const convertToString = (v) => {
124
+ switch (v) {
125
+ case void 0:
126
+ return "(undefined)";
127
+ case null:
128
+ return "(null)";
129
+ default:
130
+ switch (typeof v) {
131
+ case "string":
132
+ return v;
133
+ case "boolean":
134
+ return v ? "true" : "false";
135
+ case "number":
136
+ case "bigint":
137
+ case "symbol":
138
+ return v.toString();
139
+ case "function":
140
+ if (v.name) {
141
+ return `fun<${v.name}:#${getFuncId(v)}>`;
142
+ } else {
143
+ return `fun<#${getFuncId(v)}>`;
144
+ }
145
+ default:
146
+ if (Array.isArray(v)) {
147
+ return JSON.stringify(v);
148
+ }
149
+ const iterable = asIterable(v);
150
+ if (iterable) {
151
+ const arr = Array.from(iterable);
152
+ return JSON.stringify(arr);
153
+ } else if (v instanceof Date) {
154
+ return v.toISOString();
155
+ } else if (v instanceof Error) {
156
+ return `${v.name}: ${v.message}`;
157
+ } else if (v instanceof URL) {
158
+ return v.origin;
159
+ } else {
160
+ return JSON.stringify(v);
161
+ }
162
+ }
163
+ }
164
+ };
165
+ const stringEscapeMap = {
166
+ f: "\f",
167
+ n: "\n",
168
+ r: "\r",
169
+ t: " ",
170
+ v: "\v",
171
+ "0": "\0",
172
+ "'": "'",
173
+ "\\": "\\"
174
+ };
3
175
  const tokenizeString = (context) => {
4
176
  const start = context.cursor.location("start");
5
177
  context.cursor.skip(1);
6
- let value = context.cursor.getUntil("'");
7
- if (value !== void 0) {
178
+ let value = "";
179
+ let closed = false;
180
+ while (!context.cursor.eot()) {
181
+ const ch = context.cursor.getChar();
182
+ if (ch === "'") {
183
+ context.cursor.skip(1);
184
+ closed = true;
185
+ break;
186
+ }
187
+ if (ch === "\\") {
188
+ const escapeStart = context.cursor.location("start");
189
+ context.cursor.skip(1);
190
+ if (context.cursor.eot()) {
191
+ context.errors.push({
192
+ type: "error",
193
+ description: "invalid escape sequence: \\\\",
194
+ range: { start: escapeStart, end: context.cursor.location("end") }
195
+ });
196
+ value += "\\";
197
+ break;
198
+ }
199
+ const escape = context.cursor.getChar();
200
+ const mapped = stringEscapeMap[escape];
201
+ if (mapped !== void 0) {
202
+ value += mapped;
203
+ context.cursor.skip(1);
204
+ continue;
205
+ }
206
+ context.cursor.skip(1);
207
+ context.errors.push({
208
+ type: "error",
209
+ description: `invalid escape sequence: \\${escape}`,
210
+ range: { start: escapeStart, end: context.cursor.location("end") }
211
+ });
212
+ value += `\\${escape}`;
213
+ continue;
214
+ }
215
+ value += ch;
8
216
  context.cursor.skip(1);
9
- } else {
217
+ }
218
+ if (!closed) {
10
219
  const location = context.cursor.location("start");
11
220
  context.errors.push({
12
221
  type: "error",
13
222
  description: "string close quote is not found",
14
223
  range: { start: location, end: location }
15
224
  });
16
- value = "";
17
225
  }
18
226
  return {
19
227
  kind: "string",
@@ -94,16 +302,8 @@ const tokenizeIdentity = (context) => {
94
302
  range: { start, end: context.cursor.location("end") }
95
303
  };
96
304
  };
97
- const tokenizeCodeBlock = (context) => {
98
- const openStart = context.cursor.location("start");
99
- context.cursor.skip(2);
100
- const tokens = [
101
- {
102
- kind: "open",
103
- symbol: "{{",
104
- range: { start: openStart, end: context.cursor.location("end") }
105
- }
106
- ];
305
+ const tokenizeCodeTokens = (context, stopOnClose, finalizeUnknownOnEot) => {
306
+ const tokens = [];
107
307
  let unknownStartLocation;
108
308
  const finalizeUnknown = () => {
109
309
  if (unknownStartLocation) {
@@ -119,20 +319,21 @@ const tokenizeCodeBlock = (context) => {
119
319
  }
120
320
  };
121
321
  while (!context.cursor.eot()) {
122
- if (context.cursor.assert("}}")) {
322
+ if (stopOnClose && context.cursor.assert("}}")) {
123
323
  finalizeUnknown();
124
- const location = context.cursor.location("start");
125
- context.cursor.skip(2);
126
- tokens.push({
127
- kind: "close",
128
- symbol: "}}",
129
- range: { start: location, end: context.cursor.location("end") }
130
- });
131
- return tokens;
324
+ return { tokens, closed: true };
132
325
  }
133
326
  const ch = context.cursor.getChar();
134
327
  if (ch === "\\") {
135
328
  const next = context.cursor.getChar(1);
329
+ if (next === "\n") {
330
+ context.cursor.skip(2);
331
+ continue;
332
+ }
333
+ if (next === "\r" && context.cursor.getChar(2) === "\n") {
334
+ context.cursor.skip(3);
335
+ continue;
336
+ }
136
337
  if (next === "{" || next === "}") {
137
338
  context.cursor.skip(2);
138
339
  continue;
@@ -197,12 +398,41 @@ const tokenizeCodeBlock = (context) => {
197
398
  } else if (ch === " ") {
198
399
  finalizeUnknown();
199
400
  context.cursor.skip(1);
200
- } else if (!unknownStartLocation) {
201
- unknownStartLocation = context.cursor.location("start");
401
+ } else {
402
+ if (!unknownStartLocation) {
403
+ unknownStartLocation = context.cursor.location("start");
404
+ }
202
405
  context.cursor.skip(1);
203
406
  }
204
407
  context.cursor.skipChars(" ");
205
408
  }
409
+ if (finalizeUnknownOnEot) {
410
+ finalizeUnknown();
411
+ }
412
+ return { tokens, closed: false };
413
+ };
414
+ const tokenizeCodeBlock = (context) => {
415
+ const openStart = context.cursor.location("start");
416
+ context.cursor.skip(2);
417
+ const tokens = [
418
+ {
419
+ kind: "open",
420
+ symbol: "{{",
421
+ range: { start: openStart, end: context.cursor.location("end") }
422
+ }
423
+ ];
424
+ const result = tokenizeCodeTokens(context, true, false);
425
+ tokens.push(...result.tokens);
426
+ if (result.closed) {
427
+ const location = context.cursor.location("start");
428
+ context.cursor.skip(2);
429
+ tokens.push({
430
+ kind: "close",
431
+ symbol: "}}",
432
+ range: { start: location, end: context.cursor.location("end") }
433
+ });
434
+ return tokens;
435
+ }
206
436
  const causeLocation = context.cursor.location("start");
207
437
  context.errors.push({
208
438
  type: "error",
@@ -227,9 +457,12 @@ const createTokenizerCursor = (script) => {
227
457
  const ch = script[currentIndex];
228
458
  if (ch === "\r") {
229
459
  rawColumn = 0;
230
- } else if (ch === "\n" && lastch !== "\r") {
231
- rawColumn = 0;
232
460
  rawLine++;
461
+ } else if (ch === "\n") {
462
+ rawColumn = 0;
463
+ if (lastch !== "\r") {
464
+ rawLine++;
465
+ }
233
466
  } else {
234
467
  rawColumn++;
235
468
  }
@@ -306,6 +539,14 @@ const createTokenizerCursor = (script) => {
306
539
  location
307
540
  };
308
541
  };
542
+ const runCodeTokenizer = (script, errors) => {
543
+ const context = {
544
+ cursor: createTokenizerCursor(script),
545
+ errors
546
+ };
547
+ const result = tokenizeCodeTokens(context, false, true);
548
+ return result.tokens;
549
+ };
309
550
  const runTokenizer = (script, errors) => {
310
551
  const context = {
311
552
  cursor: createTokenizerCursor(script),
@@ -350,115 +591,6 @@ const runTokenizer = (script, errors) => {
350
591
  }
351
592
  return tokens;
352
593
  };
353
- const emptyLocation = {
354
- line: 0,
355
- column: 0
356
- };
357
- const emptyRange = {
358
- start: emptyLocation,
359
- end: emptyLocation
360
- };
361
- const specialFunctionMarker = /* @__PURE__ */ Symbol("$$special$$");
362
- const makeSpecialFunction = (f) => {
363
- f[specialFunctionMarker] = true;
364
- return f;
365
- };
366
- const isSpecialFunction = (f) => {
367
- var _a;
368
- return (_a = f[specialFunctionMarker]) != null ? _a : false;
369
- };
370
- const isConditionalTrue = (v) => {
371
- if (v === void 0 || v === null) {
372
- return false;
373
- }
374
- switch (typeof v) {
375
- case "boolean":
376
- return v;
377
- case "number":
378
- case "bigint":
379
- return v !== 0;
380
- default:
381
- return true;
382
- }
383
- };
384
- const asIterable = (v) => {
385
- if (typeof v[Symbol.iterator] === "function") {
386
- return v;
387
- } else {
388
- return void 0;
389
- }
390
- };
391
- const combineVariables = (...variablesList) => {
392
- const variables = /* @__PURE__ */ new Map();
393
- const appendVariables = (vs) => vs.forEach((v, k) => variables.set(k, v));
394
- const appendRecord = (vs) => Object.keys(vs).forEach((k) => variables.set(k, vs[k]));
395
- variablesList.forEach((vs) => {
396
- if (vs["forEach"] !== void 0) {
397
- appendVariables(vs);
398
- } else {
399
- appendRecord(vs);
400
- }
401
- });
402
- return variables;
403
- };
404
- const fromError = (error) => {
405
- var _a;
406
- if (error.message) {
407
- return error.message;
408
- } else if (typeof error.toString === "function") {
409
- return (_a = error.toString()) != null ? _a : "unknown";
410
- } else {
411
- return "unknown";
412
- }
413
- };
414
- const widerRange = (...ranges) => {
415
- let start = emptyRange.start;
416
- let end = emptyRange.end;
417
- for (const range of ranges) {
418
- if (range.start.line >= 1 && range.start.column >= 1) {
419
- if (start.line === 0 || start.column === 0) {
420
- start = range.start;
421
- } else if (range.start.line < start.line) {
422
- start = range.start;
423
- } else if (range.start.line === start.line && range.start.column < start.column) {
424
- start = range.start;
425
- }
426
- if (end.line === 0 || end.column === 0) {
427
- end = range.end;
428
- } else if (range.end.line > end.line) {
429
- end = range.end;
430
- } else if (range.end.line === end.line && range.end.column > end.column) {
431
- end = range.end;
432
- }
433
- }
434
- }
435
- return { start, end };
436
- };
437
- const locationEquals = (lhs, rhs) => lhs.line === rhs.line && lhs.column === rhs.column;
438
- const getLocationString = (range) => locationEquals(range.start, range.end) ? `${range.start.line}:${range.start.column}` : `${range.start.line}:${range.start.column}:${range.end.line}:${range.end.column}`;
439
- const printErrorString = (path, error) => {
440
- switch (error.type) {
441
- case "warning":
442
- console.warn(
443
- `${path}:${getLocationString(error.range)}: warning: ${error.description}`
444
- );
445
- break;
446
- case "error":
447
- console.error(
448
- `${path}:${getLocationString(error.range)}: error: ${error.description}`
449
- );
450
- return true;
451
- }
452
- return false;
453
- };
454
- const outputErrors = (path, errors) => {
455
- let isError = false;
456
- for (const error of errors) {
457
- const result = printErrorString(path, error);
458
- isError || (isError = result);
459
- }
460
- return isError;
461
- };
462
594
  const parseNumber = (cursor, _errors) => {
463
595
  const token = cursor.takeToken();
464
596
  return {
@@ -546,6 +678,9 @@ const parseLambdaExpression = (cursor, errors) => {
546
678
  };
547
679
  const parsePartialExpression = (cursor, errors) => {
548
680
  const token = cursor.peekToken();
681
+ if (!token) {
682
+ return void 0;
683
+ }
549
684
  switch (token.kind) {
550
685
  case "number": {
551
686
  const node = parseNumber(cursor);
@@ -930,14 +1065,15 @@ const extractParameterArguments = (namesNode, errors) => {
930
1065
  }
931
1066
  }
932
1067
  };
933
- const parseBlock = (cursor, errors) => {
1068
+ const parseBlockCore = (cursor, errors, mode) => {
934
1069
  const rootState = {
935
1070
  kind: "root",
936
1071
  startRange: emptyRange,
937
1072
  branch: createBranchState()
938
1073
  };
939
1074
  const statementStates = [rootState];
940
- let isInExpressionBlock = false;
1075
+ const isCodeMode = mode === "code";
1076
+ let isInExpressionBlock = isCodeMode;
941
1077
  while (true) {
942
1078
  const token = drainEndOfLineAndPeek(cursor);
943
1079
  if (!token) {
@@ -964,14 +1100,16 @@ const parseBlock = (cursor, errors) => {
964
1100
  case "open": {
965
1101
  if (token.symbol === "{{") {
966
1102
  cursor.skipToken();
967
- if (isInExpressionBlock) {
968
- errors.push({
969
- type: "error",
970
- description: `Already opened expression block`,
971
- range: token.range
972
- });
1103
+ if (!isCodeMode) {
1104
+ if (isInExpressionBlock) {
1105
+ errors.push({
1106
+ type: "error",
1107
+ description: `Already opened expression block`,
1108
+ range: token.range
1109
+ });
1110
+ }
1111
+ isInExpressionBlock = true;
973
1112
  }
974
- isInExpressionBlock = true;
975
1113
  } else {
976
1114
  const node = parseExpression(cursor, errors);
977
1115
  if (node) {
@@ -982,6 +1120,10 @@ const parseBlock = (cursor, errors) => {
982
1120
  }
983
1121
  case "close": {
984
1122
  cursor.skipToken();
1123
+ if (token.symbol === "}}" && isCodeMode) {
1124
+ flushCurrentBranch(statementStates);
1125
+ break;
1126
+ }
985
1127
  if (!isInExpressionBlock) {
986
1128
  errors.push({
987
1129
  type: "error",
@@ -990,6 +1132,14 @@ const parseBlock = (cursor, errors) => {
990
1132
  });
991
1133
  break;
992
1134
  }
1135
+ if (isCodeMode) {
1136
+ errors.push({
1137
+ type: "error",
1138
+ description: `Mismatched close bracket`,
1139
+ range: token.range
1140
+ });
1141
+ break;
1142
+ }
993
1143
  flushCurrentBranch(statementStates);
994
1144
  isInExpressionBlock = false;
995
1145
  break;
@@ -1199,38 +1349,6 @@ const parseBlock = (cursor, errors) => {
1199
1349
  }
1200
1350
  break;
1201
1351
  }
1202
- case "set": {
1203
- cursor.skipToken();
1204
- const args = parseStatementArguments(cursor, errors);
1205
- if (args.length !== 2) {
1206
- errors.push({
1207
- type: "error",
1208
- description: "Required `set` bind identity and expression",
1209
- range: widerRange(
1210
- token.range,
1211
- ...args.map((node) => node.range)
1212
- )
1213
- });
1214
- break;
1215
- }
1216
- const bindNode = args[0];
1217
- if (bindNode.kind !== "variable") {
1218
- errors.push({
1219
- type: "error",
1220
- description: "Required `set` bind identity",
1221
- range: bindNode.range
1222
- });
1223
- break;
1224
- }
1225
- const exprNode = args[1];
1226
- pushNode(statementStates, {
1227
- kind: "set",
1228
- name: bindNode,
1229
- expr: exprNode,
1230
- range: widerRange(token.range, bindNode.range, exprNode.range)
1231
- });
1232
- break;
1233
- }
1234
1352
  default: {
1235
1353
  const node = parseExpression(cursor, errors);
1236
1354
  if (node) {
@@ -1268,6 +1386,9 @@ const parseBlock = (cursor, errors) => {
1268
1386
  }
1269
1387
  return rootState.branch.blocks;
1270
1388
  };
1389
+ const parseBlock = (cursor, errors) => {
1390
+ return parseBlockCore(cursor, errors, "script");
1391
+ };
1271
1392
  const createParserCursor = (tokens) => {
1272
1393
  let index = 0;
1273
1394
  const peekToken = () => {
@@ -1293,6 +1414,10 @@ const createParserCursor = (tokens) => {
1293
1414
  skipToken
1294
1415
  };
1295
1416
  };
1417
+ const parseExpressions = (tokens, errors) => {
1418
+ const cursor = createParserCursor(tokens);
1419
+ return parseBlockCore(cursor, errors, "code");
1420
+ };
1296
1421
  const runParser = (tokens, errors) => {
1297
1422
  const cursor = createParserCursor(tokens);
1298
1423
  const blockNodes = parseBlock(cursor, errors);
@@ -1373,6 +1498,7 @@ const fromLambda = (context, lambda) => {
1373
1498
  };
1374
1499
  };
1375
1500
  const reduceExpressionNode = async (context, node) => {
1501
+ var _a;
1376
1502
  switch (node.kind) {
1377
1503
  case "number":
1378
1504
  case "string": {
@@ -1382,6 +1508,7 @@ const reduceExpressionNode = async (context, node) => {
1382
1508
  return traverseVariable(context, node);
1383
1509
  }
1384
1510
  case "apply": {
1511
+ (_a = context.abortSignal) == null ? void 0 : _a.throwIfAborted();
1385
1512
  const func = await reduceExpressionNode(context, node.func);
1386
1513
  if (typeof func !== "function") {
1387
1514
  context.appendError({
@@ -1391,28 +1518,26 @@ const reduceExpressionNode = async (context, node) => {
1391
1518
  });
1392
1519
  return void 0;
1393
1520
  }
1521
+ const args = isFunCityFunction(func) ? node.args : await Promise.all(
1522
+ node.args.map(async (argNode) => {
1523
+ const arg = await reduceExpressionNode(context, argNode);
1524
+ return arg;
1525
+ })
1526
+ );
1394
1527
  const thisProxy = context.createFunctionContext(node);
1395
- if (isSpecialFunction(func)) {
1396
- const value = await func.call(thisProxy, ...node.args);
1397
- return value;
1398
- } else {
1399
- const args = await Promise.all(
1400
- node.args.map(async (argNode) => {
1401
- try {
1402
- const arg = await reduceExpressionNode(context, argNode);
1403
- return arg;
1404
- } catch (e) {
1405
- context.appendError({
1406
- type: "error",
1407
- description: fromError(e),
1408
- range: argNode.range
1409
- });
1410
- return void 0;
1411
- }
1412
- })
1413
- );
1528
+ try {
1414
1529
  const value = await func.call(thisProxy, ...args);
1415
1530
  return value;
1531
+ } catch (e) {
1532
+ if (e instanceof Error && e.name === "AbortError") {
1533
+ throw e;
1534
+ }
1535
+ context.appendError({
1536
+ type: "error",
1537
+ description: fromError(e),
1538
+ range: node.range
1539
+ });
1540
+ return void 0;
1416
1541
  }
1417
1542
  }
1418
1543
  case "lambda": {
@@ -1424,11 +1549,6 @@ const reduceExpressionNode = async (context, node) => {
1424
1549
  );
1425
1550
  return results;
1426
1551
  }
1427
- case "set": {
1428
- const expr = await reduceExpressionNode(context, node.expr);
1429
- context.setValue(node.name.name, expr);
1430
- return void 0;
1431
- }
1432
1552
  case "scope": {
1433
1553
  if (node.nodes.length === 0) {
1434
1554
  return [];
@@ -1510,32 +1630,76 @@ const reduceNode = async (context, node) => {
1510
1630
  }
1511
1631
  }
1512
1632
  };
1513
- const createReducerContext = (variables, errors) => {
1514
- let vs = variables;
1515
- let mvs;
1516
- let variablesProxy;
1633
+ const createScopedReducerContext = (parent) => {
1634
+ let thisVars;
1635
+ let thisContext;
1636
+ const getValue = (name) => {
1637
+ var _a;
1638
+ (_a = parent.abortSignal) == null ? void 0 : _a.throwIfAborted();
1639
+ if (thisVars == null ? void 0 : thisVars.has(name)) {
1640
+ return { value: thisVars.get(name), isFound: true };
1641
+ } else {
1642
+ return parent.getValue(name);
1643
+ }
1644
+ };
1645
+ const setValue = (name, value) => {
1646
+ var _a;
1647
+ (_a = parent.abortSignal) == null ? void 0 : _a.throwIfAborted();
1648
+ if (!thisVars) {
1649
+ thisVars = /* @__PURE__ */ new Map();
1650
+ }
1651
+ thisVars.set(name, value);
1652
+ };
1653
+ const createFunctionContext = (thisNode) => {
1654
+ const newContext = {
1655
+ thisNode,
1656
+ abortSignal: parent.abortSignal,
1657
+ getValue,
1658
+ setValue,
1659
+ isFailed: parent.isFailed,
1660
+ appendError: parent.appendError,
1661
+ reduce: (node) => {
1662
+ var _a;
1663
+ (_a = parent.abortSignal) == null ? void 0 : _a.throwIfAborted();
1664
+ return reduceExpressionNode(thisContext, node);
1665
+ }
1666
+ };
1667
+ return newContext;
1668
+ };
1669
+ thisContext = {
1670
+ abortSignal: parent.abortSignal,
1671
+ getValue,
1672
+ setValue,
1673
+ isFailed: parent.isFailed,
1674
+ appendError: parent.appendError,
1675
+ newScope: () => {
1676
+ var _a;
1677
+ (_a = parent.abortSignal) == null ? void 0 : _a.throwIfAborted();
1678
+ return createScopedReducerContext(thisContext);
1679
+ },
1680
+ createFunctionContext
1681
+ };
1682
+ return thisContext;
1683
+ };
1684
+ const createReducerContext = (variables, errors, signal) => {
1685
+ let thisVars;
1686
+ let thisContext;
1517
1687
  const getValue = (name) => {
1518
- if (vs.has(name)) {
1519
- return { value: vs.get(name), isFound: true };
1688
+ signal == null ? void 0 : signal.throwIfAborted();
1689
+ if (thisVars == null ? void 0 : thisVars.has(name)) {
1690
+ return { value: thisVars.get(name), isFound: true };
1691
+ } else if (variables.has(name)) {
1692
+ return { value: variables.get(name), isFound: true };
1520
1693
  } else {
1521
1694
  return { value: void 0, isFound: false };
1522
1695
  }
1523
1696
  };
1524
1697
  const setValue = (name, value) => {
1525
- if (!mvs) {
1526
- mvs = new Map(vs);
1527
- vs = mvs;
1528
- }
1529
- mvs.set(name, value);
1530
- if (variablesProxy !== void 0) {
1531
- Object.defineProperty(variablesProxy, name, {
1532
- get() {
1533
- return vs.get(name);
1534
- },
1535
- configurable: true,
1536
- enumerable: true
1537
- });
1698
+ signal == null ? void 0 : signal.throwIfAborted();
1699
+ if (!thisVars) {
1700
+ thisVars = /* @__PURE__ */ new Map();
1538
1701
  }
1702
+ thisVars.set(name, value);
1539
1703
  };
1540
1704
  const appendError = (error) => {
1541
1705
  errors.push(error);
@@ -1543,47 +1707,37 @@ const createReducerContext = (variables, errors) => {
1543
1707
  const isFailed = () => {
1544
1708
  return errors.some((error) => error.type === "error");
1545
1709
  };
1546
- const newScope = () => {
1547
- const newContext = createReducerContext(vs, errors);
1548
- return newContext;
1549
- };
1550
- let context;
1551
- const reduceByProxy = (node) => reduceExpressionNode(context, node);
1552
- const getVariablesFromProxy = () => {
1553
- if (variablesProxy === void 0) {
1554
- variablesProxy = {};
1555
- for (const key of vs.keys()) {
1556
- Object.defineProperty(variablesProxy, key, {
1557
- get: () => vs.get(key),
1558
- configurable: true,
1559
- enumerable: true
1560
- });
1561
- }
1562
- }
1563
- return variablesProxy;
1564
- };
1565
1710
  const createFunctionContext = (thisNode) => {
1566
- return {
1567
- get variables() {
1568
- return getVariablesFromProxy();
1569
- },
1711
+ const newContext = {
1570
1712
  thisNode,
1713
+ abortSignal: signal,
1714
+ getValue,
1715
+ setValue,
1716
+ isFailed,
1571
1717
  appendError,
1572
- reduce: reduceByProxy
1718
+ reduce: (node) => {
1719
+ signal == null ? void 0 : signal.throwIfAborted();
1720
+ return reduceExpressionNode(thisContext, node);
1721
+ }
1573
1722
  };
1723
+ return newContext;
1574
1724
  };
1575
- context = {
1725
+ thisContext = {
1726
+ abortSignal: signal,
1576
1727
  getValue,
1577
1728
  setValue,
1578
1729
  appendError,
1579
1730
  isFailed,
1580
- newScope,
1731
+ newScope: () => {
1732
+ signal == null ? void 0 : signal.throwIfAborted();
1733
+ return createScopedReducerContext(thisContext);
1734
+ },
1581
1735
  createFunctionContext
1582
1736
  };
1583
- return context;
1737
+ return thisContext;
1584
1738
  };
1585
- async function runReducer(nodes, variables, errors) {
1586
- const context = createReducerContext(variables, errors);
1739
+ async function runReducer(nodes, variables, errors, signal) {
1740
+ const context = createReducerContext(variables, errors, signal);
1587
1741
  const resultList = [];
1588
1742
  for (const node of nodes) {
1589
1743
  const results = await reduceNode(context, node);
@@ -1595,7 +1749,15 @@ async function runReducer(nodes, variables, errors) {
1595
1749
  }
1596
1750
  return resultList;
1597
1751
  }
1598
- const _cond = makeSpecialFunction(async function(arg0, arg1, arg2) {
1752
+ const _cond = makeFunCityFunction(async function(arg0, arg1, arg2) {
1753
+ if (!arg0 || !arg1 || !arg2) {
1754
+ this.appendError({
1755
+ type: "error",
1756
+ description: "Required `cond` condition, true and false expressions",
1757
+ range: this.thisNode.range
1758
+ });
1759
+ return void 0;
1760
+ }
1599
1761
  const cond = await this.reduce(arg0);
1600
1762
  if (isConditionalTrue(cond)) {
1601
1763
  return await this.reduce(arg1);
@@ -1603,6 +1765,27 @@ const _cond = makeSpecialFunction(async function(arg0, arg1, arg2) {
1603
1765
  return await this.reduce(arg2);
1604
1766
  }
1605
1767
  });
1768
+ const _set = makeFunCityFunction(async function(arg0, arg1, ...rest) {
1769
+ if (!arg0 || !arg1 || rest.length !== 0) {
1770
+ this.appendError({
1771
+ type: "error",
1772
+ description: "Required `set` bind identity and expression",
1773
+ range: this.thisNode.range
1774
+ });
1775
+ return void 0;
1776
+ }
1777
+ if (arg0.kind !== "variable") {
1778
+ this.appendError({
1779
+ type: "error",
1780
+ description: "Required `set` bind identity",
1781
+ range: arg0.range
1782
+ });
1783
+ return void 0;
1784
+ }
1785
+ const value = await this.reduce(arg1);
1786
+ this.setValue(arg0.name, value);
1787
+ return void 0;
1788
+ });
1606
1789
  const _typeof = async (arg0) => {
1607
1790
  if (arg0 === null) {
1608
1791
  return "null";
@@ -1616,54 +1799,33 @@ const _typeof = async (arg0) => {
1616
1799
  return typeof arg0;
1617
1800
  }
1618
1801
  };
1619
- const funcIds = /* @__PURE__ */ new WeakMap();
1620
- let nextId = 1;
1621
- const getFuncId = (fn) => {
1622
- const cached = funcIds.get(fn);
1623
- if (cached) return cached;
1624
- const id = nextId++;
1625
- funcIds.set(fn, id);
1626
- return id;
1627
- };
1628
1802
  const _toString = async (...args) => {
1629
- const results = args.map((arg0) => {
1630
- switch (arg0) {
1631
- case void 0:
1632
- return "(undefined)";
1633
- case null:
1634
- return "(null)";
1635
- default:
1636
- switch (typeof arg0) {
1637
- case "string":
1638
- return arg0;
1639
- case "boolean":
1640
- return arg0 ? "true" : "false";
1641
- case "number":
1642
- case "bigint":
1643
- case "symbol":
1644
- return arg0.toString();
1645
- case "function":
1646
- if (arg0.name) {
1647
- return `fun<${arg0.name}:#${getFuncId(arg0)}>`;
1648
- } else {
1649
- return `fun<#${getFuncId(arg0)}>`;
1650
- }
1651
- default:
1652
- if (Array.isArray(arg0)) {
1653
- return JSON.stringify(arg0);
1654
- }
1655
- const iterable = asIterable(arg0);
1656
- if (iterable) {
1657
- const arr = Array.from(iterable);
1658
- return JSON.stringify(arr);
1659
- } else {
1660
- return JSON.stringify(arg0);
1661
- }
1662
- }
1663
- }
1664
- });
1803
+ const results = args.map((arg0) => convertToString(arg0));
1665
1804
  return results.join(",");
1666
1805
  };
1806
+ const _toBoolean = async (arg0) => {
1807
+ const r = isConditionalTrue(arg0);
1808
+ return r;
1809
+ };
1810
+ const _toNumber = async (arg0) => {
1811
+ const r = Number(arg0);
1812
+ return r;
1813
+ };
1814
+ const _toBigInt = async (arg0) => {
1815
+ switch (typeof arg0) {
1816
+ case "number":
1817
+ case "bigint":
1818
+ case "string":
1819
+ case "boolean": {
1820
+ const r = BigInt(arg0);
1821
+ return r;
1822
+ }
1823
+ default: {
1824
+ const r = BigInt(await _toString(arg0));
1825
+ return r;
1826
+ }
1827
+ }
1828
+ };
1667
1829
  const _add = async (arg0, ...args) => {
1668
1830
  const r = args.reduce((v0, v) => v0 + Number(v), Number(arg0));
1669
1831
  return r;
@@ -1761,20 +1923,40 @@ const _length = async (arg0) => {
1761
1923
  }
1762
1924
  return 0;
1763
1925
  };
1764
- const _and = async (...args) => {
1926
+ const _and = makeFunCityFunction(async function(...args) {
1765
1927
  if (args.length === 0) {
1766
- throw new Error("empty arguments");
1928
+ this.appendError({
1929
+ type: "error",
1930
+ description: "empty arguments",
1931
+ range: this.thisNode.range
1932
+ });
1933
+ return void 0;
1767
1934
  }
1768
- const r = args.reduce((v0, v) => v0 && isConditionalTrue(v), true);
1769
- return r;
1770
- };
1771
- const _or = async (...args) => {
1935
+ for (const arg of args) {
1936
+ const value = await this.reduce(arg);
1937
+ if (!isConditionalTrue(value)) {
1938
+ return false;
1939
+ }
1940
+ }
1941
+ return true;
1942
+ });
1943
+ const _or = makeFunCityFunction(async function(...args) {
1772
1944
  if (args.length === 0) {
1773
- throw new Error("empty arguments");
1945
+ this.appendError({
1946
+ type: "error",
1947
+ description: "empty arguments",
1948
+ range: this.thisNode.range
1949
+ });
1950
+ return void 0;
1774
1951
  }
1775
- const r = args.reduce((v0, v) => v0 || isConditionalTrue(v), false);
1776
- return r;
1777
- };
1952
+ for (const arg of args) {
1953
+ const value = await this.reduce(arg);
1954
+ if (isConditionalTrue(value)) {
1955
+ return true;
1956
+ }
1957
+ }
1958
+ return false;
1959
+ });
1778
1960
  const _not = async (arg0) => {
1779
1961
  return !isConditionalTrue(arg0);
1780
1962
  };
@@ -1936,13 +2118,24 @@ const _bind = async (arg0, ...args) => {
1936
2118
  const predicate = arg0;
1937
2119
  return predicate.bind(void 0, ...args);
1938
2120
  };
2121
+ const _url = async (arg0, arg1) => {
2122
+ const url = new URL(
2123
+ convertToString(arg0),
2124
+ arg1 !== void 0 ? convertToString(arg1) : void 0
2125
+ );
2126
+ return url;
2127
+ };
1939
2128
  const standardVariables = Object.freeze({
1940
2129
  undefined: void 0,
1941
2130
  null: null,
1942
2131
  true: true,
1943
2132
  false: false,
1944
2133
  cond: _cond,
2134
+ set: _set,
1945
2135
  toString: _toString,
2136
+ toBoolean: _toBoolean,
2137
+ toNumber: _toNumber,
2138
+ toBigInt: _toBigInt,
1946
2139
  typeof: _typeof,
1947
2140
  add: _add,
1948
2141
  sub: _sub,
@@ -1974,34 +2167,38 @@ const standardVariables = Object.freeze({
1974
2167
  match: _match,
1975
2168
  replace: _replace,
1976
2169
  regex: _regex,
1977
- bind: _bind
2170
+ bind: _bind,
2171
+ url: _url
1978
2172
  });
1979
2173
  const buildCandidateVariables = (...variablesList) => {
1980
2174
  return combineVariables(standardVariables, ...variablesList);
1981
2175
  };
1982
- const runScriptOnce = async (script, variables, errors = []) => {
2176
+ const runScriptOnce = async (script, variables, errors = [], signal) => {
1983
2177
  const blocks = runTokenizer(script, errors);
1984
2178
  const nodes = runParser(blocks, errors);
1985
- const results = await runReducer(nodes, variables, errors);
1986
- const text = results.join("");
2179
+ const results = await runReducer(nodes, variables, errors, signal);
2180
+ const text = results.map((result) => convertToString(result)).join("");
1987
2181
  return text;
1988
2182
  };
1989
2183
  exports.asIterable = asIterable;
1990
2184
  exports.buildCandidateVariables = buildCandidateVariables;
1991
2185
  exports.combineVariables = combineVariables;
2186
+ exports.convertToString = convertToString;
1992
2187
  exports.createParserCursor = createParserCursor;
1993
2188
  exports.createReducerContext = createReducerContext;
1994
2189
  exports.emptyLocation = emptyLocation;
1995
2190
  exports.emptyRange = emptyRange;
1996
2191
  exports.fromError = fromError;
1997
2192
  exports.isConditionalTrue = isConditionalTrue;
1998
- exports.isSpecialFunction = isSpecialFunction;
1999
- exports.makeSpecialFunction = makeSpecialFunction;
2193
+ exports.isFunCityFunction = isFunCityFunction;
2194
+ exports.makeFunCityFunction = makeFunCityFunction;
2000
2195
  exports.outputErrors = outputErrors;
2001
2196
  exports.parseBlock = parseBlock;
2002
2197
  exports.parseExpression = parseExpression;
2198
+ exports.parseExpressions = parseExpressions;
2003
2199
  exports.reduceExpressionNode = reduceExpressionNode;
2004
2200
  exports.reduceNode = reduceNode;
2201
+ exports.runCodeTokenizer = runCodeTokenizer;
2005
2202
  exports.runParser = runParser;
2006
2203
  exports.runReducer = runReducer;
2007
2204
  exports.runScriptOnce = runScriptOnce;