hclang 0.16.0 → 0.17.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/frames/evaluation-scope.js +7 -6
- package/esm/lib/frames/frame-array.js +60 -0
- package/esm/lib/frames/frame-handle.js +14 -0
- package/esm/lib/frames/frame-typed-number.js +7 -0
- package/esm/lib/frames/frame.js +35 -0
- package/esm/lib/ops/conditionals.js +6 -1
- package/esm/lib/ops/math.js +6 -4
- package/esm/lib/ops.js +3 -3
- package/esm/lib/version.js +1 -1
- package/package.json +1 -1
|
@@ -166,15 +166,16 @@ export class EvaluationScope {
|
|
|
166
166
|
* the argument to the argument", which is what made a closure's write target
|
|
167
167
|
* and its argument the same frame and produced a self-referential binding.
|
|
168
168
|
*
|
|
169
|
-
* A handle argument is the one exception, because
|
|
170
|
-
* mutable view
|
|
169
|
+
* A mutable handle argument is the one exception, because the caller asked
|
|
170
|
+
* for a mutable view by spelling the name with the effect marker (`x_`). A
|
|
171
|
+
* plain name also arrives as a handle, but an immutable one, and it grants no
|
|
172
|
+
* write: `f x` must not change `x`.
|
|
171
173
|
*/
|
|
172
174
|
static call(argument, parameter = Frame.nil, closure, enclosing, receiverState) {
|
|
173
175
|
const local = new Frame();
|
|
174
|
-
const
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
: "statement";
|
|
176
|
+
const writable = argument instanceof FrameHandle && argument.isMutable();
|
|
177
|
+
const target = writable ? argument.unwrap() : local;
|
|
178
|
+
const targetRole = writable ? "handle" : "statement";
|
|
178
179
|
const lookupFrames = [local, argument];
|
|
179
180
|
if (!parameter.is.void)
|
|
180
181
|
lookupFrames.push(parameter);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Frame } from "./frame.js";
|
|
1
2
|
import { FrameExpr } from "./frame-expr.js";
|
|
2
3
|
import { FrameList } from "./frame-list.js";
|
|
3
4
|
import { FrameNote } from "./frame-note.js";
|
|
@@ -51,6 +52,58 @@ export class FrameArray extends FrameList {
|
|
|
51
52
|
}
|
|
52
53
|
return undefined;
|
|
53
54
|
}
|
|
55
|
+
/** Aggregates own identity, so `===` compares them by reference. */
|
|
56
|
+
ownsIdentity() {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* `=` compares the complete view, the same one `&&` iterates: visible
|
|
61
|
+
* properties in declaration order, then elements by index, each by `=`.
|
|
62
|
+
* Spelling, private fields, the declared parent, and ids are not the value.
|
|
63
|
+
*/
|
|
64
|
+
equals(other) {
|
|
65
|
+
return this.sameMembers(other, (left, right) => left.equals(right));
|
|
66
|
+
}
|
|
67
|
+
/** `==` is the same walk with `==` at every node. */
|
|
68
|
+
typeEquals(other) {
|
|
69
|
+
return this.sameMembers(other, (left, right) => left.typeEquals(right));
|
|
70
|
+
}
|
|
71
|
+
sameMembers(other, same) {
|
|
72
|
+
const right = other.referent();
|
|
73
|
+
if (right === this)
|
|
74
|
+
return Frame.all;
|
|
75
|
+
if (right.constructor !== this.constructor)
|
|
76
|
+
return Frame.nil;
|
|
77
|
+
const inProgress = FrameArray.comparing.get(this) ?? new Set();
|
|
78
|
+
if (inProgress.has(right))
|
|
79
|
+
return Frame.all;
|
|
80
|
+
inProgress.add(right);
|
|
81
|
+
FrameArray.comparing.set(this, inProgress);
|
|
82
|
+
try {
|
|
83
|
+
const keys = this.visibleKeys();
|
|
84
|
+
const rightKeys = right.visibleKeys();
|
|
85
|
+
if (keys.length !== rightKeys.length ||
|
|
86
|
+
keys.some((key, index) => key !== rightKeys[index]))
|
|
87
|
+
return Frame.nil;
|
|
88
|
+
for (const key of keys) {
|
|
89
|
+
if (same(this.get_here(key), right.get_here(key)) !== Frame.all) {
|
|
90
|
+
return Frame.nil;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const elements = this.elements();
|
|
94
|
+
const rightElements = right.elements();
|
|
95
|
+
if (elements.length !== rightElements.length)
|
|
96
|
+
return Frame.nil;
|
|
97
|
+
return elements.every((element, index) => same(element, rightElements[index]) === Frame.all)
|
|
98
|
+
? Frame.all
|
|
99
|
+
: Frame.nil;
|
|
100
|
+
}
|
|
101
|
+
finally {
|
|
102
|
+
inProgress.delete(right);
|
|
103
|
+
if (inProgress.size === 0)
|
|
104
|
+
FrameArray.comparing.delete(this);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
54
107
|
/**
|
|
55
108
|
* Aggregates are where identity matters, so an instance copy isolates them:
|
|
56
109
|
* every nested aggregate, in the data plane and the metadata plane alike, gets
|
|
@@ -127,3 +180,10 @@ Object.defineProperty(FrameArray, "SIGIL_STARTS", {
|
|
|
127
180
|
{ key: FrameArray.END_ARRAY, mode: "pop" },
|
|
128
181
|
]
|
|
129
182
|
});
|
|
183
|
+
/** Pairs under comparison, so a frame reachable from itself terminates. */
|
|
184
|
+
Object.defineProperty(FrameArray, "comparing", {
|
|
185
|
+
enumerable: true,
|
|
186
|
+
configurable: true,
|
|
187
|
+
writable: true,
|
|
188
|
+
value: new Map()
|
|
189
|
+
});
|
|
@@ -60,6 +60,20 @@ export class FrameHandle extends Frame {
|
|
|
60
60
|
unwrap() {
|
|
61
61
|
return this.target;
|
|
62
62
|
}
|
|
63
|
+
/** A handle is transparent to equality: it compares as its target. */
|
|
64
|
+
referent() {
|
|
65
|
+
return this.target.referent();
|
|
66
|
+
}
|
|
67
|
+
equals(other) {
|
|
68
|
+
return this.target.equals(other);
|
|
69
|
+
}
|
|
70
|
+
typeEquals(other) {
|
|
71
|
+
return this.target.typeEquals(other);
|
|
72
|
+
}
|
|
73
|
+
/** Whether the name that produced this handle carried the effect marker. */
|
|
74
|
+
isMutable() {
|
|
75
|
+
return this.mutable;
|
|
76
|
+
}
|
|
63
77
|
/** The lexical fallback selected for this particular read. */
|
|
64
78
|
readContextFrame() {
|
|
65
79
|
return this.readContext;
|
|
@@ -66,6 +66,13 @@ export class FrameTypedNumber extends FrameNumeric {
|
|
|
66
66
|
}
|
|
67
67
|
return super.lookup_here(key, origin);
|
|
68
68
|
}
|
|
69
|
+
/** `==` also asks the magnitude's rung: `3.m == 3.0.m` is nil. */
|
|
70
|
+
typeEquals(right) {
|
|
71
|
+
if (!(right instanceof FrameTypedNumber) || this.unit !== right.unit) {
|
|
72
|
+
return Frame.nil;
|
|
73
|
+
}
|
|
74
|
+
return this.magnitude.typeEquals(right.magnitude);
|
|
75
|
+
}
|
|
69
76
|
equals(right) {
|
|
70
77
|
if (!(right instanceof FrameTypedNumber) || this.unit !== right.unit) {
|
|
71
78
|
return Frame.nil;
|
package/esm/lib/frames/frame.js
CHANGED
|
@@ -179,6 +179,41 @@ export class Frame extends MetaFrame {
|
|
|
179
179
|
equals(other) {
|
|
180
180
|
return this.toString() === other.toString() ? Frame.all : Frame.nil;
|
|
181
181
|
}
|
|
182
|
+
/**
|
|
183
|
+
* typeEquals is `==`: the same value, and the same type at every node.
|
|
184
|
+
* It is strictly stronger than `equals`, so `3 == 3.0` is nil while
|
|
185
|
+
* `3 = 3.0` holds.
|
|
186
|
+
*/
|
|
187
|
+
typeEquals(other) {
|
|
188
|
+
const left = this.referent();
|
|
189
|
+
const right = other.referent();
|
|
190
|
+
return left.constructor === right.constructor
|
|
191
|
+
? left.equals(right)
|
|
192
|
+
: Frame.nil;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* identical is `===`: whether both references reach the same frame.
|
|
196
|
+
*
|
|
197
|
+
* Only a frame that owns identity can be told apart from an equal copy.
|
|
198
|
+
* Atoms and closure bodies are shared by the copy contract, so sharing them
|
|
199
|
+
* is unobservable and identity falls back to `typeEquals`, which keeps the
|
|
200
|
+
* ladder monotone: `===` implies `==` implies `=`. No id is ever exposed.
|
|
201
|
+
*/
|
|
202
|
+
identical(other) {
|
|
203
|
+
const left = this.referent();
|
|
204
|
+
const right = other.referent();
|
|
205
|
+
if (left.ownsIdentity())
|
|
206
|
+
return left === right ? Frame.all : Frame.nil;
|
|
207
|
+
return left.typeEquals(right);
|
|
208
|
+
}
|
|
209
|
+
/** The frame a reference reaches. A handle answers its target. */
|
|
210
|
+
referent() {
|
|
211
|
+
return this;
|
|
212
|
+
}
|
|
213
|
+
/** Whether a write can land on this frame, so that identity is observable. */
|
|
214
|
+
ownsIdentity() {
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
182
217
|
/** Compare only this frame's data plane, excluding metadata. */
|
|
183
218
|
dataEquals(other) {
|
|
184
219
|
return this.dataString() === other.dataString() ? Frame.all : Frame.nil;
|
|
@@ -5,9 +5,14 @@ export const IfThen = (source, block, receiverState) => {
|
|
|
5
5
|
}
|
|
6
6
|
return Frame.nil;
|
|
7
7
|
};
|
|
8
|
+
/**
|
|
9
|
+
* `:` is "or else": a value that is not nil answers itself, and only nil calls
|
|
10
|
+
* the fallback. Composed after `?`, that makes `c ? t : e` answer `t` or `e`,
|
|
11
|
+
* because the taken branch's value reaches `:` as its source.
|
|
12
|
+
*/
|
|
8
13
|
export const IfElse = (source, block, receiverState) => {
|
|
9
14
|
if (source === Frame.nil) {
|
|
10
15
|
return block.call(Frame.nil, Frame.nil, receiverState);
|
|
11
16
|
}
|
|
12
|
-
return
|
|
17
|
+
return source;
|
|
13
18
|
};
|
package/esm/lib/ops/math.js
CHANGED
|
@@ -13,11 +13,13 @@ export const Power = (source, block) => numeric(source, block, (left, right) =>
|
|
|
13
13
|
export const Equals = (source, block) => {
|
|
14
14
|
return source.equals(block);
|
|
15
15
|
};
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
/** `==`: the same value and the same type at every node. */
|
|
17
|
+
export const TypeEquals = (source, block) => {
|
|
18
|
+
return source.typeEquals(block);
|
|
18
19
|
};
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
/** `===`: the same frame. Atoms, which own no identity, fall back to `==`. */
|
|
21
|
+
export const Identical = (source, block) => {
|
|
22
|
+
return source.identical(block);
|
|
21
23
|
};
|
|
22
24
|
export const GreaterThan = (source, block) => numeric(source, block, (left, right) => left.greaterThan(right));
|
|
23
25
|
export const GreaterThanOrEqual = (source, block) => numeric(source, block, (left, right) => left.greaterThanOrEqual(right));
|
package/esm/lib/ops.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { IfElse, IfThen } from "./ops/conditionals.js";
|
|
2
2
|
import { FrameOps } from "./ops/frame-ops.js";
|
|
3
3
|
import { MapElements, MapMembers, ReduceElements, ReduceMembers, } from "./ops/iterators.js";
|
|
4
|
-
import { Add,
|
|
4
|
+
import { Add, Divide, Equals, GreaterThan, GreaterThanOrEqual, Identical, LessThan, LessThanOrEqual, Modulo, Multiply, Power, Subtract, TypeEquals, } from "./ops/math.js";
|
|
5
5
|
import { BindType, HasType } from "./ops/type-operations.js";
|
|
6
6
|
export { FrameCurry } from "./ops/frame-curry.js";
|
|
7
7
|
export const Ops = new FrameOps({
|
|
@@ -18,8 +18,8 @@ export const Ops = new FrameOps({
|
|
|
18
18
|
"%%": Modulo,
|
|
19
19
|
"**": Power,
|
|
20
20
|
"=": Equals,
|
|
21
|
-
"==":
|
|
22
|
-
"===":
|
|
21
|
+
"==": TypeEquals,
|
|
22
|
+
"===": Identical,
|
|
23
23
|
">": GreaterThan,
|
|
24
24
|
">>": GreaterThan,
|
|
25
25
|
">=": GreaterThanOrEqual,
|
package/esm/lib/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = "0.
|
|
1
|
+
export const VERSION = "0.17.0";
|