@calcit/procs 0.5.0-a6 → 0.5.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/lib/calcit-data.js +37 -18
- package/lib/calcit.procs.js +77 -76
- package/lib/custom-formatter.js +11 -11
- package/lib/js-cirru.js +20 -20
- package/lib/js-list.js +190 -117
- package/lib/js-map.js +194 -130
- package/lib/js-record.js +7 -7
- package/lib/js-set.js +5 -5
- package/lib/js-tuple.js +4 -4
- package/package.json +6 -6
- package/ts-src/calcit-data.ts +37 -18
- package/ts-src/calcit.procs.ts +99 -98
- package/ts-src/custom-formatter.ts +10 -10
- package/ts-src/js-cirru.ts +22 -22
- package/ts-src/js-list.ts +195 -121
- package/ts-src/js-map.ts +216 -135
- package/ts-src/js-primes.ts +5 -3
- package/ts-src/js-record.ts +6 -6
- package/ts-src/js-set.ts +18 -5
- package/ts-src/js-tuple.ts +4 -4
|
@@ -3,8 +3,8 @@ import { CalcitRef, CalcitSymbol, CalcitKeyword } from "./calcit-data";
|
|
|
3
3
|
import { toPairs } from "@calcit/ternary-tree";
|
|
4
4
|
|
|
5
5
|
import { CalcitRecord } from "./js-record";
|
|
6
|
-
import { CalcitMap } from "./js-map";
|
|
7
|
-
import { CalcitList } from "./js-list";
|
|
6
|
+
import { CalcitMap, CalcitSliceMap } from "./js-map";
|
|
7
|
+
import { CalcitList, CalcitSliceList } from "./js-list";
|
|
8
8
|
import { CalcitSet } from "./js-set";
|
|
9
9
|
import { CalcitTuple } from "./js-tuple";
|
|
10
10
|
|
|
@@ -41,7 +41,7 @@ export let load_console_formatter_$x_ = () => {
|
|
|
41
41
|
if (obj instanceof CalcitSymbol) {
|
|
42
42
|
return ["div", { style: "color: hsl(340, 80%, 60%)" }, obj.toString()];
|
|
43
43
|
}
|
|
44
|
-
if (obj instanceof CalcitList) {
|
|
44
|
+
if (obj instanceof CalcitList || obj instanceof CalcitSliceList) {
|
|
45
45
|
return [
|
|
46
46
|
"div",
|
|
47
47
|
{ style: "color: hsl(280, 80%, 60%, 0.4)" },
|
|
@@ -49,7 +49,7 @@ export let load_console_formatter_$x_ = () => {
|
|
|
49
49
|
["span", { style: "font-size: 80%; vertical-align: 0.7em; color: hsl(280, 80%, 60%, 0.8)" }, `${obj.len()}`],
|
|
50
50
|
];
|
|
51
51
|
}
|
|
52
|
-
if (obj instanceof CalcitMap) {
|
|
52
|
+
if (obj instanceof CalcitMap || obj instanceof CalcitSliceMap) {
|
|
53
53
|
return ["div", { style: "color: hsl(280, 80%, 60%, 0.4)" }, obj.toString(true)];
|
|
54
54
|
}
|
|
55
55
|
if (obj instanceof CalcitSet) {
|
|
@@ -78,10 +78,10 @@ export let load_console_formatter_$x_ = () => {
|
|
|
78
78
|
return null;
|
|
79
79
|
},
|
|
80
80
|
hasBody: (obj) => {
|
|
81
|
-
if (obj instanceof CalcitList) {
|
|
81
|
+
if (obj instanceof CalcitList || obj instanceof CalcitSliceList) {
|
|
82
82
|
return obj.len() > 0;
|
|
83
83
|
}
|
|
84
|
-
if (obj instanceof CalcitMap) {
|
|
84
|
+
if (obj instanceof CalcitMap || obj instanceof CalcitSliceMap) {
|
|
85
85
|
return obj.len() > 0;
|
|
86
86
|
}
|
|
87
87
|
if (obj instanceof CalcitSet) {
|
|
@@ -90,7 +90,7 @@ export let load_console_formatter_$x_ = () => {
|
|
|
90
90
|
return false;
|
|
91
91
|
},
|
|
92
92
|
body: (obj, config) => {
|
|
93
|
-
if (obj instanceof CalcitList) {
|
|
93
|
+
if (obj instanceof CalcitList || obj instanceof CalcitSliceList) {
|
|
94
94
|
return ["div", { style: "color: hsl(280, 80%, 60%)" }].concat(
|
|
95
95
|
obj.toArray().map((x, idx) => {
|
|
96
96
|
return [
|
|
@@ -117,10 +117,10 @@ export let load_console_formatter_$x_ = () => {
|
|
|
117
117
|
ret.push(["div", { style: "margin-left: 8px; display: inline-block;" }, embedObject(obj.snd)]);
|
|
118
118
|
return ret;
|
|
119
119
|
}
|
|
120
|
-
if (obj instanceof CalcitMap) {
|
|
120
|
+
if (obj instanceof CalcitMap || obj instanceof CalcitSliceMap) {
|
|
121
121
|
let ret: any[] = ["div", { style: "color: hsl(280, 80%, 60%)" }];
|
|
122
|
-
obj.
|
|
123
|
-
for (let [k, v] of
|
|
122
|
+
let pairs = obj.pairs();
|
|
123
|
+
for (let [k, v] of pairs) {
|
|
124
124
|
ret.push([
|
|
125
125
|
"div",
|
|
126
126
|
{ style: "margin-left: 8px; display: flex;" },
|
package/ts-src/js-cirru.ts
CHANGED
|
@@ -2,9 +2,9 @@ import { overwriteComparator, initTernaryTreeMap } from "@calcit/ternary-tree";
|
|
|
2
2
|
import { CirruWriterNode, writeCirruCode } from "@cirru/writer.ts";
|
|
3
3
|
|
|
4
4
|
import { CalcitValue } from "./js-primes";
|
|
5
|
-
import { CalcitList } from "./js-list";
|
|
5
|
+
import { CalcitList, CalcitSliceList } from "./js-list";
|
|
6
6
|
import { CalcitRecord } from "./js-record";
|
|
7
|
-
import { CalcitMap } from "./js-map";
|
|
7
|
+
import { CalcitMap, CalcitSliceMap } from "./js-map";
|
|
8
8
|
import { CalcitSet } from "./js-set";
|
|
9
9
|
import { CalcitKeyword, CalcitSymbol, CalcitRecur, CalcitRef, kwd } from "./calcit-data";
|
|
10
10
|
import { CalcitTuple } from "./js-tuple";
|
|
@@ -44,11 +44,11 @@ export let to_cirru_edn = (x: CalcitValue): CirruEdnFormat => {
|
|
|
44
44
|
if (x instanceof CalcitSymbol) {
|
|
45
45
|
return x.toString();
|
|
46
46
|
}
|
|
47
|
-
if (x instanceof CalcitList) {
|
|
47
|
+
if (x instanceof CalcitList || x instanceof CalcitSliceList) {
|
|
48
48
|
// TODO can be faster
|
|
49
49
|
return (["[]"] as CirruEdnFormat[]).concat(x.toArray().map(to_cirru_edn));
|
|
50
50
|
}
|
|
51
|
-
if (x instanceof CalcitMap) {
|
|
51
|
+
if (x instanceof CalcitMap || x instanceof CalcitSliceMap) {
|
|
52
52
|
let buffer: CirruEdnFormat = ["{}"];
|
|
53
53
|
for (let [k, v] of x.pairs()) {
|
|
54
54
|
buffer.push([to_cirru_edn(k), to_cirru_edn(v)]);
|
|
@@ -105,7 +105,7 @@ export let extract_cirru_edn = (x: CirruEdnFormat): CalcitValue => {
|
|
|
105
105
|
if (x === "false") {
|
|
106
106
|
return false;
|
|
107
107
|
}
|
|
108
|
-
if (x
|
|
108
|
+
if (x === "") {
|
|
109
109
|
throw new Error("cannot be empty");
|
|
110
110
|
}
|
|
111
111
|
if (x[0] === "|" || x[0] === '"') {
|
|
@@ -129,18 +129,18 @@ export let extract_cirru_edn = (x: CirruEdnFormat): CalcitValue => {
|
|
|
129
129
|
throw new Error("Cannot be empty");
|
|
130
130
|
}
|
|
131
131
|
if (x[0] === "{}") {
|
|
132
|
-
let result: Array<
|
|
132
|
+
let result: Array<CalcitValue> = [];
|
|
133
133
|
x.forEach((pair, idx) => {
|
|
134
|
-
if (idx
|
|
134
|
+
if (idx === 0) {
|
|
135
135
|
return; // skip first `{}` symbol
|
|
136
136
|
}
|
|
137
|
-
if (pair instanceof Array && pair.length
|
|
138
|
-
result.push(
|
|
137
|
+
if (pair instanceof Array && pair.length === 2) {
|
|
138
|
+
result.push(extract_cirru_edn(pair[0]), extract_cirru_edn(pair[1]));
|
|
139
139
|
} else {
|
|
140
140
|
throw new Error("Expected pairs for map");
|
|
141
141
|
}
|
|
142
142
|
});
|
|
143
|
-
return new
|
|
143
|
+
return new CalcitSliceMap(result);
|
|
144
144
|
}
|
|
145
145
|
if (x[0] === "%{}") {
|
|
146
146
|
let name = x[1];
|
|
@@ -154,7 +154,7 @@ export let extract_cirru_edn = (x: CirruEdnFormat): CalcitValue => {
|
|
|
154
154
|
return; // skip %{} name
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
-
if (pair instanceof Array && pair.length
|
|
157
|
+
if (pair instanceof Array && pair.length === 2) {
|
|
158
158
|
if (typeof pair[0] === "string") {
|
|
159
159
|
entries.push([extractFieldKwd(pair[0]), extract_cirru_edn(pair[1])]);
|
|
160
160
|
} else {
|
|
@@ -177,7 +177,7 @@ export let extract_cirru_edn = (x: CirruEdnFormat): CalcitValue => {
|
|
|
177
177
|
return new CalcitRecord(extractFieldKwd(name), fields, values);
|
|
178
178
|
}
|
|
179
179
|
if (x[0] === "[]") {
|
|
180
|
-
return new
|
|
180
|
+
return new CalcitSliceList(x.slice(1).map(extract_cirru_edn));
|
|
181
181
|
}
|
|
182
182
|
if (x[0] === "#{}") {
|
|
183
183
|
return new CalcitSet(x.slice(1).map(extract_cirru_edn));
|
|
@@ -209,10 +209,10 @@ export let format_cirru_edn = (data: CalcitValue, useInline: boolean = true): st
|
|
|
209
209
|
if (typeof data === "string") {
|
|
210
210
|
return "\ndo " + to_cirru_edn(data) + "\n";
|
|
211
211
|
}
|
|
212
|
-
if (typeof data
|
|
212
|
+
if (typeof data === "boolean") {
|
|
213
213
|
return "\ndo " + to_cirru_edn(data) + "\n";
|
|
214
214
|
}
|
|
215
|
-
if (typeof data
|
|
215
|
+
if (typeof data === "string") {
|
|
216
216
|
return "\ndo " + to_cirru_edn(data) + "\n";
|
|
217
217
|
}
|
|
218
218
|
if (data instanceof CalcitSymbol) {
|
|
@@ -244,7 +244,7 @@ export let to_calcit_data = (x: any, noKeyword: boolean = false): CalcitValue =>
|
|
|
244
244
|
x.forEach((v) => {
|
|
245
245
|
result.push(to_calcit_data(v, noKeyword));
|
|
246
246
|
});
|
|
247
|
-
return new
|
|
247
|
+
return new CalcitSliceList(result);
|
|
248
248
|
}
|
|
249
249
|
if (x instanceof Set) {
|
|
250
250
|
let result: Array<CalcitValue> = [];
|
|
@@ -254,8 +254,8 @@ export let to_calcit_data = (x: any, noKeyword: boolean = false): CalcitValue =>
|
|
|
254
254
|
return new CalcitSet(result);
|
|
255
255
|
}
|
|
256
256
|
|
|
257
|
-
if (x instanceof CalcitList) return x;
|
|
258
|
-
if (x instanceof CalcitMap) return x;
|
|
257
|
+
if (x instanceof CalcitList || x instanceof CalcitSliceList) return x;
|
|
258
|
+
if (x instanceof CalcitMap || x instanceof CalcitSliceMap) return x;
|
|
259
259
|
if (x instanceof CalcitSet) return x;
|
|
260
260
|
if (x instanceof CalcitRecord) return x;
|
|
261
261
|
if (x instanceof CalcitRecur) return x;
|
|
@@ -266,22 +266,22 @@ export let to_calcit_data = (x: any, noKeyword: boolean = false): CalcitValue =>
|
|
|
266
266
|
|
|
267
267
|
// detects object
|
|
268
268
|
if (x === Object(x)) {
|
|
269
|
-
let result: Array<
|
|
269
|
+
let result: Array<CalcitValue> = [];
|
|
270
270
|
Object.keys(x).forEach((k) => {
|
|
271
|
-
result.push(
|
|
271
|
+
result.push(to_calcit_data(k, noKeyword), to_calcit_data(x[k], noKeyword));
|
|
272
272
|
});
|
|
273
|
-
return new
|
|
273
|
+
return new CalcitSliceMap(result);
|
|
274
274
|
}
|
|
275
275
|
|
|
276
276
|
console.error(x);
|
|
277
277
|
throw new Error("Unexpected data for converting");
|
|
278
278
|
};
|
|
279
279
|
|
|
280
|
-
let toWriterNode = (xs: CalcitList): CirruWriterNode => {
|
|
280
|
+
let toWriterNode = (xs: CalcitList | CalcitSliceList): CirruWriterNode => {
|
|
281
281
|
if (typeof xs === "string") {
|
|
282
282
|
return xs;
|
|
283
283
|
}
|
|
284
|
-
if (xs instanceof CalcitList) {
|
|
284
|
+
if (xs instanceof CalcitList || xs instanceof CalcitSliceList) {
|
|
285
285
|
return xs.toArray().map(toWriterNode);
|
|
286
286
|
} else {
|
|
287
287
|
throw new Error("Unexpected type for CirruWriteNode");
|
package/ts-src/js-list.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { CalcitValue } from "./js-primes";
|
|
|
5
5
|
import {
|
|
6
6
|
TernaryTreeList,
|
|
7
7
|
initTernaryTreeList,
|
|
8
|
+
initTernaryTreeListFromRange,
|
|
8
9
|
listLen,
|
|
9
10
|
listGet,
|
|
10
11
|
assocList,
|
|
@@ -15,97 +16,157 @@ import {
|
|
|
15
16
|
assocAfter,
|
|
16
17
|
} from "@calcit/ternary-tree";
|
|
17
18
|
|
|
18
|
-
import { CalcitMap } from "./js-map";
|
|
19
|
+
import { CalcitMap, CalcitSliceMap } from "./js-map";
|
|
19
20
|
import { CalcitSet } from "./js-set";
|
|
20
21
|
import { CalcitTuple } from "./js-tuple";
|
|
21
|
-
import { CalcitFn } from "./calcit.procs";
|
|
22
22
|
|
|
23
|
-
import { isNestedCalcitData, tipNestedCalcitData, toString } from "./calcit-data";
|
|
23
|
+
import { isNestedCalcitData, tipNestedCalcitData, toString, CalcitFn } from "./calcit-data";
|
|
24
24
|
|
|
25
|
+
// two list implementations, should offer same interface
|
|
25
26
|
export class CalcitList {
|
|
26
27
|
value: TernaryTreeList<CalcitValue>;
|
|
27
|
-
// array mode store bare array for performance
|
|
28
|
-
arrayValue: Array<CalcitValue>;
|
|
29
|
-
arrayMode: boolean;
|
|
30
|
-
arrayStart: number;
|
|
31
|
-
arrayEnd: number;
|
|
32
28
|
cachedHash: Hash;
|
|
33
|
-
constructor(value:
|
|
34
|
-
if (value == null) {
|
|
35
|
-
value = []; // dirty, better handled from outside
|
|
36
|
-
}
|
|
29
|
+
constructor(value: TernaryTreeList<CalcitValue>) {
|
|
37
30
|
this.cachedHash = null;
|
|
38
|
-
if (
|
|
39
|
-
this.
|
|
40
|
-
this.arrayValue = value;
|
|
41
|
-
this.arrayStart = 0;
|
|
42
|
-
this.arrayEnd = value.length;
|
|
43
|
-
this.value = null;
|
|
31
|
+
if (value == null) {
|
|
32
|
+
this.value = initTernaryTreeList([]);
|
|
44
33
|
} else {
|
|
45
|
-
this.arrayMode = false;
|
|
46
34
|
this.value = value;
|
|
47
|
-
this.arrayValue = [];
|
|
48
|
-
this.arrayStart = null;
|
|
49
|
-
this.arrayEnd = null;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
turnListMode() {
|
|
53
|
-
if (this.arrayMode) {
|
|
54
|
-
this.value = initTernaryTreeList(this.arrayValue.slice(this.arrayStart, this.arrayEnd));
|
|
55
|
-
this.arrayValue = null;
|
|
56
|
-
this.arrayStart = null;
|
|
57
|
-
this.arrayEnd = null;
|
|
58
|
-
this.arrayMode = false;
|
|
59
35
|
}
|
|
60
36
|
}
|
|
61
37
|
len() {
|
|
62
|
-
|
|
63
|
-
return this.arrayEnd - this.arrayStart;
|
|
64
|
-
} else {
|
|
65
|
-
return listLen(this.value);
|
|
66
|
-
}
|
|
38
|
+
return listLen(this.value);
|
|
67
39
|
}
|
|
68
40
|
get(idx: number) {
|
|
69
|
-
|
|
70
|
-
return this.arrayValue[this.arrayStart + idx];
|
|
71
|
-
} else {
|
|
72
|
-
return listGet(this.value, idx);
|
|
73
|
-
}
|
|
41
|
+
return listGet(this.value, idx);
|
|
74
42
|
}
|
|
75
43
|
assoc(idx: number, v: CalcitValue) {
|
|
76
|
-
this.turnListMode();
|
|
77
44
|
return new CalcitList(assocList(this.value, idx, v));
|
|
78
45
|
}
|
|
79
46
|
assocBefore(idx: number, v: CalcitValue) {
|
|
80
|
-
this.turnListMode();
|
|
81
47
|
return new CalcitList(assocBefore(this.value, idx, v));
|
|
82
48
|
}
|
|
83
49
|
assocAfter(idx: number, v: CalcitValue) {
|
|
84
|
-
this.turnListMode();
|
|
85
50
|
return new CalcitList(assocAfter(this.value, idx, v));
|
|
86
51
|
}
|
|
87
52
|
dissoc(idx: number) {
|
|
88
|
-
this.turnListMode();
|
|
89
53
|
return new CalcitList(dissocList(this.value, idx));
|
|
90
54
|
}
|
|
91
55
|
slice(from: number, to: number) {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
56
|
+
return new CalcitList(ternaryTree.slice(this.value, from, to));
|
|
57
|
+
}
|
|
58
|
+
toString(shorter = false): string {
|
|
59
|
+
let result = "";
|
|
60
|
+
for (let item of this.items()) {
|
|
61
|
+
if (shorter && isNestedCalcitData(item)) {
|
|
62
|
+
result = `${result} ${tipNestedCalcitData(item)}`;
|
|
63
|
+
} else {
|
|
64
|
+
result = `${result} ${toString(item, true)}`;
|
|
101
65
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
66
|
+
}
|
|
67
|
+
return `([]${result})`;
|
|
68
|
+
}
|
|
69
|
+
isEmpty() {
|
|
70
|
+
return this.len() === 0;
|
|
71
|
+
}
|
|
72
|
+
/** usage: `for of` */
|
|
73
|
+
items(): Generator<CalcitValue> {
|
|
74
|
+
return listToItems(this.value);
|
|
75
|
+
}
|
|
76
|
+
append(v: CalcitValue) {
|
|
77
|
+
return new CalcitList(ternaryTree.append(this.value, v));
|
|
78
|
+
}
|
|
79
|
+
prepend(v: CalcitValue) {
|
|
80
|
+
return new CalcitList(ternaryTree.prepend(this.value, v));
|
|
81
|
+
}
|
|
82
|
+
first() {
|
|
83
|
+
return ternaryTree.first(this.value);
|
|
84
|
+
}
|
|
85
|
+
rest() {
|
|
86
|
+
return new CalcitList(ternaryTree.rest(this.value));
|
|
87
|
+
}
|
|
88
|
+
concat(ys: CalcitList | CalcitSliceList) {
|
|
89
|
+
if (ys instanceof CalcitSliceList) {
|
|
90
|
+
return new CalcitList(ternaryTree.concat(this.value, ys.turnListMode().value));
|
|
91
|
+
} else if (ys instanceof CalcitList) {
|
|
92
|
+
return new CalcitList(ternaryTree.concat(this.value, ys.value));
|
|
93
|
+
} else {
|
|
94
|
+
throw new Error(`Unknown data to concat: ${ys}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
map(f: (v: CalcitValue) => CalcitValue): CalcitList {
|
|
98
|
+
return new CalcitList(ternaryTree.listMapValues(this.value, f));
|
|
99
|
+
}
|
|
100
|
+
toArray(): CalcitValue[] {
|
|
101
|
+
return [...ternaryTree.listToItems(this.value)];
|
|
102
|
+
}
|
|
103
|
+
reverse() {
|
|
104
|
+
return new CalcitList(ternaryTree.reverse(this.value));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// represent append-only immutable list in Array slices
|
|
109
|
+
export class CalcitSliceList {
|
|
110
|
+
// array mode store bare array for performance
|
|
111
|
+
value: Array<CalcitValue>;
|
|
112
|
+
start: number;
|
|
113
|
+
end: number;
|
|
114
|
+
cachedHash: Hash;
|
|
115
|
+
constructor(value: Array<CalcitValue>) {
|
|
116
|
+
if (value == null) {
|
|
117
|
+
value = []; // dirty, better handled from outside
|
|
118
|
+
}
|
|
119
|
+
this.cachedHash = null;
|
|
120
|
+
|
|
121
|
+
this.value = value;
|
|
122
|
+
this.start = 0;
|
|
123
|
+
this.end = value.length;
|
|
124
|
+
}
|
|
125
|
+
turnListMode(): CalcitList {
|
|
126
|
+
return new CalcitList(initTernaryTreeListFromRange(this.value, this.start, this.end));
|
|
127
|
+
}
|
|
128
|
+
len() {
|
|
129
|
+
return this.end - this.start;
|
|
130
|
+
}
|
|
131
|
+
get(idx: number) {
|
|
132
|
+
return this.value[this.start + idx];
|
|
133
|
+
}
|
|
134
|
+
assoc(idx: number, v: CalcitValue) {
|
|
135
|
+
return this.turnListMode().assoc(idx, v);
|
|
136
|
+
}
|
|
137
|
+
assocBefore(idx: number, v: CalcitValue) {
|
|
138
|
+
return this.turnListMode().assocBefore(idx, v);
|
|
139
|
+
}
|
|
140
|
+
assocAfter(idx: number, v: CalcitValue) {
|
|
141
|
+
if (idx === this.len() - 1) {
|
|
142
|
+
return this.append(v);
|
|
106
143
|
} else {
|
|
107
|
-
return
|
|
144
|
+
return this.turnListMode().assocAfter(idx, v);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
dissoc(idx: number) {
|
|
148
|
+
if (idx === 0) {
|
|
149
|
+
return this.rest();
|
|
150
|
+
} else if (idx === this.len() - 1) {
|
|
151
|
+
return this.slice(0, idx);
|
|
152
|
+
} else {
|
|
153
|
+
return this.turnListMode().dissoc(idx);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
slice(from: number, to: number) {
|
|
157
|
+
if (from < 0) {
|
|
158
|
+
throw new Error(`from index too small: ${from}`);
|
|
159
|
+
}
|
|
160
|
+
if (to > this.len()) {
|
|
161
|
+
throw new Error(`end index too large: ${to}`);
|
|
162
|
+
}
|
|
163
|
+
if (to < from) {
|
|
164
|
+
throw new Error("end index too small");
|
|
108
165
|
}
|
|
166
|
+
let result = new CalcitSliceList(this.value);
|
|
167
|
+
result.start = this.start + from;
|
|
168
|
+
result.end = this.start + to;
|
|
169
|
+
return result;
|
|
109
170
|
}
|
|
110
171
|
toString(shorter = false): string {
|
|
111
172
|
let result = "";
|
|
@@ -123,54 +184,38 @@ export class CalcitList {
|
|
|
123
184
|
}
|
|
124
185
|
/** usage: `for of` */
|
|
125
186
|
items(): Generator<CalcitValue> {
|
|
126
|
-
|
|
127
|
-
return sliceGenerator(this.arrayValue, this.arrayStart, this.arrayEnd);
|
|
128
|
-
} else {
|
|
129
|
-
return listToItems(this.value);
|
|
130
|
-
}
|
|
187
|
+
return sliceGenerator(this.value, this.start, this.end);
|
|
131
188
|
}
|
|
132
|
-
append(v: CalcitValue) {
|
|
133
|
-
if (this.
|
|
189
|
+
append(v: CalcitValue): CalcitSliceList | CalcitList {
|
|
190
|
+
if (this.end === this.value.length && this.start < 32) {
|
|
134
191
|
// dirty trick to reuse list memory, data storage actually appended at existing array
|
|
135
|
-
this.
|
|
136
|
-
let newList = new
|
|
137
|
-
newList.
|
|
138
|
-
newList.
|
|
192
|
+
this.value.push(v);
|
|
193
|
+
let newList = new CalcitSliceList(this.value);
|
|
194
|
+
newList.start = this.start;
|
|
195
|
+
newList.end = this.end + 1;
|
|
139
196
|
return newList;
|
|
140
197
|
} else {
|
|
141
|
-
this.turnListMode();
|
|
142
|
-
return new CalcitList(ternaryTree.append(this.value, v));
|
|
198
|
+
return this.turnListMode().append(v);
|
|
143
199
|
}
|
|
144
200
|
}
|
|
145
201
|
prepend(v: CalcitValue) {
|
|
146
|
-
this.turnListMode();
|
|
147
|
-
return new CalcitList(ternaryTree.prepend(this.value, v));
|
|
202
|
+
return this.turnListMode().prepend(v);
|
|
148
203
|
}
|
|
149
204
|
first() {
|
|
150
|
-
if (this.
|
|
151
|
-
|
|
152
|
-
return this.arrayValue[this.arrayStart];
|
|
153
|
-
} else {
|
|
154
|
-
return null;
|
|
155
|
-
}
|
|
205
|
+
if (this.value.length > this.start) {
|
|
206
|
+
return this.value[this.start];
|
|
156
207
|
} else {
|
|
157
|
-
return
|
|
208
|
+
return null;
|
|
158
209
|
}
|
|
159
210
|
}
|
|
160
211
|
rest() {
|
|
161
|
-
|
|
162
|
-
return this.slice(1, this.arrayEnd - this.arrayStart);
|
|
163
|
-
} else {
|
|
164
|
-
return new CalcitList(ternaryTree.rest(this.value));
|
|
165
|
-
}
|
|
212
|
+
return this.slice(1, this.end - this.start);
|
|
166
213
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
let size = this.arrayEnd - this.arrayStart;
|
|
173
|
-
let otherSize = ys.arrayEnd - ys.arrayStart;
|
|
214
|
+
// TODO
|
|
215
|
+
concat(ys: CalcitSliceList | CalcitList) {
|
|
216
|
+
if (ys instanceof CalcitSliceList) {
|
|
217
|
+
let size = this.end - this.start;
|
|
218
|
+
let otherSize = ys.end - ys.start;
|
|
174
219
|
let combined = new Array(size + otherSize);
|
|
175
220
|
for (let i = 0; i < size; i++) {
|
|
176
221
|
combined[i] = this.get(i);
|
|
@@ -178,36 +223,38 @@ export class CalcitList {
|
|
|
178
223
|
for (let i = 0; i < otherSize; i++) {
|
|
179
224
|
combined[i + size] = ys.get(i);
|
|
180
225
|
}
|
|
181
|
-
return new
|
|
226
|
+
return new CalcitSliceList(combined);
|
|
227
|
+
} else if (ys instanceof CalcitList) {
|
|
228
|
+
return this.turnListMode().concat(ys);
|
|
182
229
|
} else {
|
|
183
|
-
|
|
184
|
-
ys.turnListMode();
|
|
185
|
-
return new CalcitList(ternaryTree.concat(this.value, ys.value));
|
|
230
|
+
throw new Error("Expected list");
|
|
186
231
|
}
|
|
187
232
|
}
|
|
188
|
-
map(f: (v: CalcitValue) => CalcitValue):
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
return new CalcitList(ternaryTree.listMapValues(this.value, f));
|
|
233
|
+
map(f: (v: CalcitValue) => CalcitValue): CalcitSliceList {
|
|
234
|
+
let ys: CalcitValue[] = [];
|
|
235
|
+
for (let x in sliceGenerator(this.value, this.start, this.end)) {
|
|
236
|
+
ys.push(f(x));
|
|
193
237
|
}
|
|
238
|
+
|
|
239
|
+
return new CalcitSliceList(ys);
|
|
194
240
|
}
|
|
195
241
|
toArray(): CalcitValue[] {
|
|
196
|
-
|
|
197
|
-
return this.arrayValue.slice(this.arrayStart, this.arrayEnd);
|
|
198
|
-
} else {
|
|
199
|
-
return [...ternaryTree.listToItems(this.value)];
|
|
200
|
-
}
|
|
242
|
+
return this.value.slice(this.start, this.end);
|
|
201
243
|
}
|
|
202
244
|
reverse() {
|
|
203
|
-
this.turnListMode();
|
|
204
|
-
return new CalcitList(ternaryTree.reverse(this.value));
|
|
245
|
+
return this.turnListMode().reverse();
|
|
205
246
|
}
|
|
206
247
|
}
|
|
207
248
|
|
|
208
249
|
function* sliceGenerator(xs: Array<CalcitValue>, start: number, end: number): Generator<CalcitValue> {
|
|
209
|
-
|
|
210
|
-
|
|
250
|
+
if (xs == null) {
|
|
251
|
+
if (end <= start) {
|
|
252
|
+
throw new Error("invalid list to slice");
|
|
253
|
+
}
|
|
254
|
+
} else {
|
|
255
|
+
for (let idx = start; idx < end; idx++) {
|
|
256
|
+
yield xs[idx];
|
|
257
|
+
}
|
|
211
258
|
}
|
|
212
259
|
}
|
|
213
260
|
|
|
@@ -217,10 +264,9 @@ export let foldl = function (xs: CalcitValue, acc: CalcitValue, f: CalcitFn): Ca
|
|
|
217
264
|
}
|
|
218
265
|
|
|
219
266
|
if (f == null) {
|
|
220
|
-
debugger;
|
|
221
267
|
throw new Error("Expected function for folding");
|
|
222
268
|
}
|
|
223
|
-
if (xs instanceof CalcitList) {
|
|
269
|
+
if (xs instanceof CalcitSliceList || xs instanceof CalcitList) {
|
|
224
270
|
var result = acc;
|
|
225
271
|
for (let idx = 0; idx < xs.len(); idx++) {
|
|
226
272
|
let item = xs.get(idx);
|
|
@@ -235,10 +281,20 @@ export let foldl = function (xs: CalcitValue, acc: CalcitValue, f: CalcitFn): Ca
|
|
|
235
281
|
});
|
|
236
282
|
return result;
|
|
237
283
|
}
|
|
284
|
+
if (xs instanceof CalcitSliceMap) {
|
|
285
|
+
let result = acc;
|
|
286
|
+
// low-level code for performance
|
|
287
|
+
let size = xs.chunk.length >> 1;
|
|
288
|
+
for (let i = 0; i < size; i++) {
|
|
289
|
+
let pos = i << 1;
|
|
290
|
+
result = f(result, new CalcitSliceList([xs.chunk[pos], xs.chunk[pos + 1]]));
|
|
291
|
+
}
|
|
292
|
+
return result;
|
|
293
|
+
}
|
|
238
294
|
if (xs instanceof CalcitMap) {
|
|
239
295
|
let result = acc;
|
|
240
|
-
xs.pairs().forEach((
|
|
241
|
-
result = f(result, new
|
|
296
|
+
xs.pairs().forEach((pair) => {
|
|
297
|
+
result = f(result, new CalcitSliceList(pair));
|
|
242
298
|
});
|
|
243
299
|
return result;
|
|
244
300
|
}
|
|
@@ -251,10 +307,9 @@ export let foldl_shortcut = function (xs: CalcitValue, acc: CalcitValue, v0: Cal
|
|
|
251
307
|
}
|
|
252
308
|
|
|
253
309
|
if (f == null) {
|
|
254
|
-
debugger;
|
|
255
310
|
throw new Error("Expected function for folding");
|
|
256
311
|
}
|
|
257
|
-
if (xs instanceof CalcitList) {
|
|
312
|
+
if (xs instanceof CalcitList || xs instanceof CalcitSliceList) {
|
|
258
313
|
var state = acc;
|
|
259
314
|
for (let idx = 0; idx < xs.len(); idx++) {
|
|
260
315
|
let item = xs.get(idx);
|
|
@@ -291,11 +346,31 @@ export let foldl_shortcut = function (xs: CalcitValue, acc: CalcitValue, v0: Cal
|
|
|
291
346
|
}
|
|
292
347
|
return v0;
|
|
293
348
|
}
|
|
294
|
-
|
|
349
|
+
if (xs instanceof CalcitSliceMap) {
|
|
350
|
+
let state = acc;
|
|
351
|
+
// low-level code for performance
|
|
352
|
+
let size = xs.chunk.length >> 1;
|
|
353
|
+
for (let i = 0; i < size; i++) {
|
|
354
|
+
let pos = i << 1;
|
|
355
|
+
let pair = f(state, new CalcitSliceList([xs.chunk[pos], xs.chunk[pos + 1]]));
|
|
356
|
+
if (pair instanceof CalcitTuple) {
|
|
357
|
+
if (typeof pair.fst === "boolean") {
|
|
358
|
+
if (pair.fst) {
|
|
359
|
+
return pair.snd;
|
|
360
|
+
} else {
|
|
361
|
+
state = pair.snd;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
} else {
|
|
365
|
+
throw new Error("Expected return value in `:: bool acc` structure");
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
return v0;
|
|
369
|
+
}
|
|
295
370
|
if (xs instanceof CalcitMap) {
|
|
296
371
|
let state = acc;
|
|
297
372
|
for (let item of xs.pairs()) {
|
|
298
|
-
let pair = f(state, new
|
|
373
|
+
let pair = f(state, new CalcitSliceList(item));
|
|
299
374
|
if (pair instanceof CalcitTuple) {
|
|
300
375
|
if (typeof pair.fst === "boolean") {
|
|
301
376
|
if (pair.fst) {
|
|
@@ -318,10 +393,9 @@ export let foldr_shortcut = function (xs: CalcitValue, acc: CalcitValue, v0: Cal
|
|
|
318
393
|
}
|
|
319
394
|
|
|
320
395
|
if (f == null) {
|
|
321
|
-
debugger;
|
|
322
396
|
throw new Error("Expected function for folding");
|
|
323
397
|
}
|
|
324
|
-
if (xs instanceof CalcitList) {
|
|
398
|
+
if (xs instanceof CalcitList || xs instanceof CalcitSliceList) {
|
|
325
399
|
var state = acc;
|
|
326
400
|
// iterate from right
|
|
327
401
|
for (let idx = xs.len() - 1; idx >= 0; idx--) {
|