hclang 0.17.0 → 0.18.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 +72 -5
- package/esm/lib/frames/frame-handle.js +28 -4
- package/esm/lib/frames/frame-list.js +27 -1
- package/esm/lib/frames/frame-symbol.js +12 -0
- package/esm/lib/frames/frame.js +33 -0
- 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,13 +133,71 @@ 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;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* A fresh aggregate holding the same elements. Only the outer aggregate is
|
|
183
|
+
* new: the elements are shared, so collecting reuses them rather than
|
|
184
|
+
* copying, and `===` still finds each one.
|
|
185
|
+
*/
|
|
186
|
+
collectingCopy() {
|
|
187
|
+
return this.copy();
|
|
137
188
|
}
|
|
138
189
|
apply(argument, _parameter) {
|
|
139
|
-
|
|
140
|
-
|
|
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);
|
|
141
201
|
}
|
|
142
202
|
return this;
|
|
143
203
|
}
|
|
@@ -187,3 +247,10 @@ Object.defineProperty(FrameArray, "comparing", {
|
|
|
187
247
|
writable: true,
|
|
188
248
|
value: new Map()
|
|
189
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
|
+
});
|
|
@@ -7,10 +7,11 @@ import { methodEffect } from "./effect-marker.js";
|
|
|
7
7
|
*
|
|
8
8
|
* The handle's charter is that reference and nothing more. Two rules define it:
|
|
9
9
|
*
|
|
10
|
-
* - **Transparency.** Wrapping must not change what a value prints, equals,
|
|
11
|
-
* exposes, so rendering, data, metadata,
|
|
12
|
-
* target. A handle is invisible to
|
|
13
|
-
*
|
|
10
|
+
* - **Transparency.** Wrapping must not change what a value prints, equals,
|
|
11
|
+
* exposes, or answers when applied, so rendering, data, metadata, array
|
|
12
|
+
* views, and application all delegate to the target. A handle is invisible to
|
|
13
|
+
* comparison, and assignment unwraps it, so a mutation lands on the same
|
|
14
|
+
* frame it would have without the wrapper.
|
|
14
15
|
* - **Caller-scoped lookup.** A handle created by symbol lookup carries that
|
|
15
16
|
* read's lexical context separately from the shared target. Local and
|
|
16
17
|
* declared-parent lookup remains live on the target, then falls back through
|
|
@@ -125,6 +126,29 @@ export class FrameHandle extends Frame {
|
|
|
125
126
|
called_by(context, parameter) {
|
|
126
127
|
return context.apply(this.target, parameter);
|
|
127
128
|
}
|
|
129
|
+
/** Transparency covers application: a named aggregate collects like its literal. */
|
|
130
|
+
collects() {
|
|
131
|
+
return this.target.collects();
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Applying through a name answers what applying the value would, without
|
|
135
|
+
* writing through the name. A collect lands on a fresh aggregate, so `xs 3`
|
|
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 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.
|
|
140
|
+
*/
|
|
141
|
+
apply(argument, parameter) {
|
|
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;
|
|
151
|
+
}
|
|
128
152
|
toString() {
|
|
129
153
|
return this.target.toString();
|
|
130
154
|
}
|
|
@@ -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
|
@@ -302,6 +302,39 @@ export class Frame extends MetaFrame {
|
|
|
302
302
|
collects() {
|
|
303
303
|
return false;
|
|
304
304
|
}
|
|
305
|
+
/**
|
|
306
|
+
* The receiver a collect lands on when it must not write this frame.
|
|
307
|
+
*
|
|
308
|
+
* A literal is a fresh aggregate each time it is evaluated, so collecting
|
|
309
|
+
* into it in place is unobservable. A value reached through a name is not,
|
|
310
|
+
* so the name asks for this instead. Anything that does not collect is its
|
|
311
|
+
* own receiver.
|
|
312
|
+
*/
|
|
313
|
+
collectingCopy() {
|
|
314
|
+
return this;
|
|
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
|
+
}
|
|
305
338
|
/**
|
|
306
339
|
* The values this frame streams when it is iterated.
|
|
307
340
|
*
|
package/esm/lib/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = "0.
|
|
1
|
+
export const VERSION = "0.18.0";
|