hclang 0.17.1 → 0.19.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/esm/lib/execute/eval-pipe.js +1 -1
- package/esm/lib/frames/frame-array.js +65 -8
- package/esm/lib/frames/frame-handle.js +12 -2
- package/esm/lib/frames/frame-list.js +27 -1
- package/esm/lib/frames/frame-symbol.js +12 -0
- package/esm/lib/frames/frame.js +30 -5
- package/esm/lib/version.js +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { Frame } from "./frame.js";
|
|
2
|
+
import { BoundMethod } from "./bound-method.js";
|
|
3
|
+
import { methodEffect } from "./effect-marker.js";
|
|
2
4
|
import { FrameExpr } from "./frame-expr.js";
|
|
3
5
|
import { FrameList } from "./frame-list.js";
|
|
4
6
|
import { FrameNote } from "./frame-note.js";
|
|
@@ -119,7 +121,7 @@ export class FrameArray extends FrameList {
|
|
|
119
121
|
}
|
|
120
122
|
const clone = this.copy();
|
|
121
123
|
seen.set(this, clone);
|
|
122
|
-
clone.data = this.
|
|
124
|
+
clone.data = this.itemsFor(clone, (item) => item.instanceCopy(seen));
|
|
123
125
|
for (const [key, value] of this.meta_pairs()) {
|
|
124
126
|
clone.set(key, value.instanceCopy(seen));
|
|
125
127
|
}
|
|
@@ -131,9 +133,50 @@ export class FrameArray extends FrameList {
|
|
|
131
133
|
}
|
|
132
134
|
return super.lookup_here(key, origin);
|
|
133
135
|
}
|
|
134
|
-
/**
|
|
136
|
+
/**
|
|
137
|
+
* An aggregate collects, which is what makes applying to one a push, unless
|
|
138
|
+
* it declares its own application. A declared application is an operation,
|
|
139
|
+
* so a refusal applied to one stays a refusal rather than being held.
|
|
140
|
+
*/
|
|
135
141
|
collects() {
|
|
136
|
-
return
|
|
142
|
+
return this.applicationMethod() === undefined;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* The method this aggregate declares as its own application (#375).
|
|
146
|
+
*
|
|
147
|
+
* Applying an aggregate collects, and a receiver that wants another rule
|
|
148
|
+
* declares it as a method named `apply`, or `apply_` when the rule writes the
|
|
149
|
+
* receiver. It is found on the aggregate or its declared parents, the same
|
|
150
|
+
* chain a class's methods come from, and never in the scope around it, so a
|
|
151
|
+
* plain array keeps collecting wherever it is written.
|
|
152
|
+
*/
|
|
153
|
+
applicationMethod() {
|
|
154
|
+
for (const key of FrameArray.APPLICATION_KEYS) {
|
|
155
|
+
const seen = new Set([this]);
|
|
156
|
+
let local = this.get_here(key);
|
|
157
|
+
let next = this.hasDeclaredParent() ? this.parent : undefined;
|
|
158
|
+
while (local.is.missing && next && !seen.has(next)) {
|
|
159
|
+
seen.add(next);
|
|
160
|
+
local = next.get_here(key);
|
|
161
|
+
next = next.hasDeclaredParent() ? next.parent : undefined;
|
|
162
|
+
}
|
|
163
|
+
if (local.className() === "FrameLazy")
|
|
164
|
+
return { key, method: local };
|
|
165
|
+
}
|
|
166
|
+
return undefined;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Runs a declared application with the receiver it binds to.
|
|
170
|
+
*
|
|
171
|
+
* The effect axis decides writes, as it does for every method: `apply_`
|
|
172
|
+
* reached mutably writes the receiver and answers it, and reached immutably
|
|
173
|
+
* answers an updated copy. A step that answers nil leaves the receiver as it
|
|
174
|
+
* was, the way an aggregate ignores a nil argument, so a reduce can skip an
|
|
175
|
+
* element without losing what it accumulated.
|
|
176
|
+
*/
|
|
177
|
+
static applyDeclared(bound, argument, unchanged) {
|
|
178
|
+
const result = bound.call(argument);
|
|
179
|
+
return result.is.void ? unchanged : result;
|
|
137
180
|
}
|
|
138
181
|
/**
|
|
139
182
|
* A fresh aggregate holding the same elements. Only the outer aggregate is
|
|
@@ -141,13 +184,20 @@ export class FrameArray extends FrameList {
|
|
|
141
184
|
* copying, and `===` still finds each one.
|
|
142
185
|
*/
|
|
143
186
|
collectingCopy() {
|
|
144
|
-
|
|
145
|
-
result.data = [...this.data];
|
|
146
|
-
return result;
|
|
187
|
+
return this.copy();
|
|
147
188
|
}
|
|
148
189
|
apply(argument, _parameter) {
|
|
149
|
-
|
|
150
|
-
|
|
190
|
+
const declared = this.applicationMethod();
|
|
191
|
+
if (declared) {
|
|
192
|
+
const bound = new BoundMethod(declared.method, this, true, methodEffect(declared.key));
|
|
193
|
+
return FrameArray.applyDeclared(bound, argument, this);
|
|
194
|
+
}
|
|
195
|
+
return this.collect(argument);
|
|
196
|
+
}
|
|
197
|
+
/** Pushes a non-nil value, whatever application this aggregate declares. */
|
|
198
|
+
collect(value, _context = Frame.nil) {
|
|
199
|
+
if (!value.is.void) {
|
|
200
|
+
this.data.push(value);
|
|
151
201
|
}
|
|
152
202
|
return this;
|
|
153
203
|
}
|
|
@@ -197,3 +247,10 @@ Object.defineProperty(FrameArray, "comparing", {
|
|
|
197
247
|
writable: true,
|
|
198
248
|
value: new Map()
|
|
199
249
|
});
|
|
250
|
+
/** The keys an aggregate declares its own application under, mutating first. */
|
|
251
|
+
Object.defineProperty(FrameArray, "APPLICATION_KEYS", {
|
|
252
|
+
enumerable: true,
|
|
253
|
+
configurable: true,
|
|
254
|
+
writable: true,
|
|
255
|
+
value: ["apply_", "apply"]
|
|
256
|
+
});
|
|
@@ -134,10 +134,20 @@ export class FrameHandle extends Frame {
|
|
|
134
134
|
* Applying through a name answers what applying the value would, without
|
|
135
135
|
* writing through the name. A collect lands on a fresh aggregate, so `xs 3`
|
|
136
136
|
* answers a new array and `xs` is unchanged, whether or not the name is
|
|
137
|
-
* mutable: a write goes through a mutating method or `@`, never
|
|
137
|
+
* mutable: a write goes through a mutating method or `@`, never a collect.
|
|
138
|
+
* An aggregate that declares its own application (#375) is the exception
|
|
139
|
+
* by declaration: its `apply_` method writes like any mutating method.
|
|
138
140
|
*/
|
|
139
141
|
apply(argument, parameter) {
|
|
140
|
-
|
|
142
|
+
const declared = this.target.applicationMethod();
|
|
143
|
+
if (!declared) {
|
|
144
|
+
return this.target.collectingCopy().apply(argument, parameter);
|
|
145
|
+
}
|
|
146
|
+
// A declared application is a method, so this name's mutability decides
|
|
147
|
+
// whether it writes the target or answers an updated copy, and a nil
|
|
148
|
+
// answer leaves the accumulator as it was (`FrameArray.applyDeclared`).
|
|
149
|
+
const result = new BoundMethod(declared.method, this.target, this.mutable, methodEffect(declared.key), this.copyOnWrite, this.readContext).call(argument, parameter);
|
|
150
|
+
return result.is.void ? this : result;
|
|
141
151
|
}
|
|
142
152
|
toString() {
|
|
143
153
|
return this.target.toString();
|
|
@@ -134,9 +134,35 @@ export class FrameList extends Frame {
|
|
|
134
134
|
}
|
|
135
135
|
copy() {
|
|
136
136
|
const clone = super.copy();
|
|
137
|
-
clone.data =
|
|
137
|
+
clone.data = this.itemsFor(clone, (item) => item);
|
|
138
138
|
return clone;
|
|
139
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* This frame's items as a copy holds them.
|
|
142
|
+
*
|
|
143
|
+
* An echo records which frame holds its property, so an echo this frame
|
|
144
|
+
* holds is re-issued for the copy. Otherwise the copy would print and
|
|
145
|
+
* iterate its own declarations as though another frame held them.
|
|
146
|
+
*/
|
|
147
|
+
itemsFor(clone, other) {
|
|
148
|
+
return this.data.map((item) => this.holdsAsProperty(item)
|
|
149
|
+
? FrameList.reownedEcho(item, clone)
|
|
150
|
+
: other(item));
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* A declaration echo re-issued for `owner`, looking through a statement's
|
|
154
|
+
* wrapper. The echo is read structurally for the same reason as
|
|
155
|
+
* `echoedBinding`.
|
|
156
|
+
*/
|
|
157
|
+
static reownedEcho(term, owner) {
|
|
158
|
+
if (term.is.statement === true && term instanceof FrameList) {
|
|
159
|
+
const wrapper = term.copy();
|
|
160
|
+
wrapper.data = term.data.map((inner) => FrameList.reownedEcho(inner, owner));
|
|
161
|
+
return wrapper;
|
|
162
|
+
}
|
|
163
|
+
const echo = term;
|
|
164
|
+
return echo.reownedBy ? echo.reownedBy(owner) : term;
|
|
165
|
+
}
|
|
140
166
|
/** Evaluate source items with an explicit innermost declaration target. */
|
|
141
167
|
array_eval(input, out = this) {
|
|
142
168
|
const scope = EvaluationScope.from(input).withWriteTarget(out, "construction");
|
|
@@ -41,6 +41,18 @@ export class FrameLiteral extends FrameAtom {
|
|
|
41
41
|
toData() {
|
|
42
42
|
return this.data;
|
|
43
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* The same echo, held by `owner`. A copy of the declaring aggregate holds
|
|
46
|
+
* the copied property, so it needs an echo that names it as the holder.
|
|
47
|
+
*/
|
|
48
|
+
reownedBy(owner) {
|
|
49
|
+
if (!this.binding)
|
|
50
|
+
return this;
|
|
51
|
+
return new FrameLiteral(this.data, {
|
|
52
|
+
...this.binding,
|
|
53
|
+
target: new WeakRef(owner),
|
|
54
|
+
});
|
|
55
|
+
}
|
|
44
56
|
}
|
|
45
57
|
export class FrameSymbol extends FrameAtom {
|
|
46
58
|
static for(symbol) {
|
package/esm/lib/frames/frame.js
CHANGED
|
@@ -313,6 +313,28 @@ export class Frame extends MetaFrame {
|
|
|
313
313
|
collectingCopy() {
|
|
314
314
|
return this;
|
|
315
315
|
}
|
|
316
|
+
/**
|
|
317
|
+
* Hands a result to this frame as the interpreter's output, not as an
|
|
318
|
+
* application written in the program.
|
|
319
|
+
*
|
|
320
|
+
* The evaluator's output array is also the file scope, where top-level
|
|
321
|
+
* declarations land, so a program can declare an application on it (#375).
|
|
322
|
+
* Collecting output must not run that declaration, so an aggregate collects
|
|
323
|
+
* here unconditionally. Any other output receiver, such as a test harness,
|
|
324
|
+
* is applied as usual.
|
|
325
|
+
*/
|
|
326
|
+
collect(value, context = Frame.nil) {
|
|
327
|
+
return this.apply(value, context);
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* The method this frame declares as its own application, if any.
|
|
331
|
+
*
|
|
332
|
+
* Only an aggregate can declare one, so the base answers none. See
|
|
333
|
+
* `FrameArray.applicationMethod` for the protocol.
|
|
334
|
+
*/
|
|
335
|
+
applicationMethod() {
|
|
336
|
+
return undefined;
|
|
337
|
+
}
|
|
316
338
|
/**
|
|
317
339
|
* The values this frame streams when it is iterated.
|
|
318
340
|
*
|
|
@@ -348,17 +370,20 @@ export class Frame extends MetaFrame {
|
|
|
348
370
|
* and never of the source, which is why no source has to declare an element
|
|
349
371
|
* type. Nothing is materialized on the receiver's behalf.
|
|
350
372
|
*
|
|
351
|
-
* An empty stream answers
|
|
352
|
-
*
|
|
353
|
-
*
|
|
373
|
+
* An empty stream answers the receiver it started from. The receiver is the
|
|
374
|
+
* accumulator before any element arrives, so a fold over nothing is that
|
|
375
|
+
* accumulator: an empty collect is `[]`, an empty join `“”`, an empty product
|
|
376
|
+
* `1`. This is what keeps a reduce compositional, since folding a whole stream
|
|
377
|
+
* must equal folding its first part and continuing from that answer, even
|
|
378
|
+
* when the first part is empty.
|
|
354
379
|
*/
|
|
355
380
|
reduce(receiver, receiverState) {
|
|
356
381
|
return Frame.reduceInto(this.elements(), receiver, receiverState);
|
|
357
382
|
}
|
|
358
|
-
/** Threads one stream through a receiver, answering
|
|
383
|
+
/** Threads one stream through a receiver, answering the receiver for an empty one. */
|
|
359
384
|
static reduceInto(values, receiver, receiverState) {
|
|
360
385
|
if (values.length === 0) {
|
|
361
|
-
return
|
|
386
|
+
return receiver;
|
|
362
387
|
}
|
|
363
388
|
return values.reduce((accumulator, value) => accumulator.call(value, Frame.nil, receiverState), receiver);
|
|
364
389
|
}
|
package/esm/lib/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = "0.
|
|
1
|
+
export const VERSION = "0.19.0";
|