Be stricter about permissible assertions; repair error in Structure instantiation which led to raw arrays sneaking in
This commit is contained in:
parent
0552de7987
commit
2688c09639
|
@ -77,7 +77,7 @@ const Bag = Immutable.Map;
|
|||
function fromSet(s) {
|
||||
return Bag().withMutations(function (b) {
|
||||
for (let v of Immutable.Set(s)) {
|
||||
b = b.set(v, 1);
|
||||
b = b.set(Immutable.fromJS(v), 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -344,6 +344,20 @@ Actor.prototype.pendingPatch = function () {
|
|||
Actor.prototype.assert = function (a) { this.pendingPatch().adjust(a, +1); };
|
||||
Actor.prototype.retract = function (a) { this.pendingPatch().adjust(a, -1); };
|
||||
|
||||
Actor.prototype.adhocRetract = function (a) {
|
||||
a = Immutable.fromJS(a);
|
||||
if (this.adhocAssertions.change(a, -1, true) === Bag.PRESENT_TO_ABSENT) {
|
||||
this.retract(a);
|
||||
}
|
||||
};
|
||||
|
||||
Actor.prototype.adhocAssert = function (a) {
|
||||
a = Immutable.fromJS(a);
|
||||
if (this.adhocAssertions.change(a, +1) === Bag.ABSENT_TO_PRESENT) {
|
||||
this.assert(a);
|
||||
}
|
||||
};
|
||||
|
||||
Actor.prototype.toString = function () {
|
||||
let s = 'Actor(' + this.id;
|
||||
if (this.name !== void 0) s = s + ',' + JSON.stringify(this.name);
|
||||
|
@ -360,7 +374,7 @@ Patch.prototype.perform = function (ds, ac) {
|
|||
|
||||
Patch.prototype.adjust = function (a, count) {
|
||||
var _net;
|
||||
({bag: this.changes, net: _net} = Bag.change(this.changes, a, count));
|
||||
({bag: this.changes, net: _net} = Bag.change(this.changes, Immutable.fromJS(a), count));
|
||||
};
|
||||
|
||||
function Message(body) {
|
||||
|
@ -369,7 +383,7 @@ function Message(body) {
|
|||
|
||||
Message.prototype.perform = function (ds, ac) {
|
||||
if (this.body !== void 0) {
|
||||
ds.index.sendMessage(this.body);
|
||||
ds.index.sendMessage(Immutable.fromJS(this.body));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -249,7 +249,6 @@ function del_from_handler(h, vs) {
|
|||
|
||||
Index.prototype.adjustAssertion = function(outerValue, delta) {
|
||||
let net;
|
||||
outerValue = Immutable.fromJS(outerValue);
|
||||
({bag: this.allAssertions, net: net} = Bag.change(this.allAssertions, outerValue, delta));
|
||||
switch (net) {
|
||||
case Bag.ABSENT_TO_PRESENT:
|
||||
|
@ -265,7 +264,7 @@ Index.prototype.addAssertion = function(v) { this.adjustAssertion(v, +1); };
|
|||
Index.prototype.removeAssertion = function (v) { this.adjustAssertion(v, -1); };
|
||||
|
||||
Index.prototype.sendMessage = function(v) {
|
||||
this.root.modify(Immutable.fromJS(v), ()=>{}, ()=>{}, (h, vs) => {
|
||||
this.root.modify(v, ()=>{}, ()=>{}, (h, vs) => {
|
||||
h.callbacks.forEach((cb) => {
|
||||
cb(EVENT_MESSAGE, vs);
|
||||
return true;
|
||||
|
@ -321,7 +320,7 @@ function analyzeAssertion(a) {
|
|||
}
|
||||
}
|
||||
|
||||
let skeleton = walk(Immutable.List(), Immutable.fromJS(a));
|
||||
let skeleton = walk(Immutable.List(), a);
|
||||
|
||||
return { skeleton, constPaths, constVals, capturePaths };
|
||||
}
|
||||
|
|
|
@ -28,14 +28,14 @@ const __ = new $Special("wildcard"); /* wildcard marker */
|
|||
function StructureType(label, arity) {
|
||||
this.label = label;
|
||||
this.arity = arity;
|
||||
this.pattern = this.instantiate(Immutable.Repeat(__, arity).toArray());
|
||||
// this.pattern = this.instantiate(Immutable.Repeat(__, arity).toArray());
|
||||
|
||||
var self = this;
|
||||
this.ctor = function () {
|
||||
return self.instantiate(Array.prototype.slice.call(arguments));
|
||||
};
|
||||
this.ctor.meta = this;
|
||||
this.ctor.pattern = this.pattern;
|
||||
// this.ctor.pattern = this.pattern;
|
||||
this.ctor.isClassOf = function (v) { return self.isClassOf(v); };
|
||||
}
|
||||
|
||||
|
@ -68,9 +68,10 @@ function Structure(meta, fields) {
|
|||
throw new Error("Structure: cannot instantiate meta "+JSON.stringify(meta.label)+
|
||||
" expecting "+meta.arity+" fields with "+fields.length+" fields");
|
||||
}
|
||||
fields = fields.slice(0);
|
||||
this.meta = meta;
|
||||
this.length = meta.arity;
|
||||
this.fields = fields.slice(0);
|
||||
this.fields = fields;
|
||||
for (var i = 0; i < fields.length; i++) {
|
||||
this[i] = fields[i] = Immutable.fromJS(fields[i]);
|
||||
if (this[i] === void 0) {
|
||||
|
@ -98,9 +99,11 @@ Structure.prototype.equals = function (other) {
|
|||
if (!(other instanceof Structure)) return false;
|
||||
if (!other.meta.equals(this.meta)) return false;
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
if (this[i] === other[i]) continue;
|
||||
if (typeof this[i].equals !== 'function') return false;
|
||||
if (!this[i].equals(other[i])) return false;
|
||||
const a = this[i];
|
||||
const b = other[i];
|
||||
if (a === b) continue;
|
||||
if (!a || typeof a.equals !== 'function') return false;
|
||||
if (!a.equals(b)) return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
|
|
@ -45,6 +45,10 @@ function skeletonTrace(f) {
|
|||
return traceHolder.trace;
|
||||
}
|
||||
|
||||
function _analyzeAssertion(a) {
|
||||
return Skeleton.analyzeAssertion(Immutable.fromJS(a));
|
||||
}
|
||||
|
||||
describe('skeleton', () => {
|
||||
|
||||
const A = Struct.makeConstructor('A', ['x', 'y']);
|
||||
|
@ -53,14 +57,14 @@ describe('skeleton', () => {
|
|||
|
||||
describe('pattern analysis', () => {
|
||||
it('should handle leaf captures', () => {
|
||||
expect(Immutable.fromJS(Skeleton.analyzeAssertion(A(B(_$), _$))))
|
||||
expect(Immutable.fromJS(_analyzeAssertion(A(B(_$), _$))))
|
||||
.to.equal(Immutable.fromJS({skeleton: [A.meta, [B.meta, null], null],
|
||||
constPaths: Immutable.fromJS([]),
|
||||
constVals: Immutable.fromJS([]),
|
||||
capturePaths: Immutable.fromJS([[0, 0], [1]])}));
|
||||
});
|
||||
it('should handle atomic constants', () => {
|
||||
expect(Immutable.fromJS(Skeleton.analyzeAssertion(A(B("x"), _$))))
|
||||
expect(Immutable.fromJS(_analyzeAssertion(A(B("x"), _$))))
|
||||
.to.equal(Immutable.fromJS({skeleton: [A.meta, [B.meta, null], null],
|
||||
constPaths: Immutable.fromJS([[0, 0]]),
|
||||
constVals: Immutable.fromJS(["x"]),
|
||||
|
@ -74,7 +78,7 @@ describe('skeleton', () => {
|
|||
// that situation without the static analysis half of the code.
|
||||
// TODO later.
|
||||
let complexPlaceholder = new Object();
|
||||
expect(Immutable.fromJS(Skeleton.analyzeAssertion(A(complexPlaceholder, C(_$)))))
|
||||
expect(Immutable.fromJS(_analyzeAssertion(A(complexPlaceholder, C(_$)))))
|
||||
.to.equal(Immutable.fromJS({skeleton: [A.meta, null, [C.meta, null]],
|
||||
constPaths: Immutable.fromJS([[0]]),
|
||||
constVals: Immutable.fromJS([complexPlaceholder]),
|
||||
|
@ -87,21 +91,21 @@ describe('skeleton', () => {
|
|||
// will end up being complex at runtime. We can't properly test
|
||||
// that situation without the static analysis half of the code.
|
||||
// TODO later.
|
||||
expect(Immutable.fromJS(Skeleton.analyzeAssertion(A(B(B("y")), _$("rhs", C(__))))))
|
||||
expect(Immutable.fromJS(_analyzeAssertion(A(B(B("y")), _$("rhs", C(__))))))
|
||||
.to.equal(Immutable.fromJS({skeleton: [A.meta, [B.meta, [B.meta, null]], [C.meta, null]],
|
||||
constPaths: Immutable.fromJS([[0, 0, 0]]),
|
||||
constVals: Immutable.fromJS(["y"]),
|
||||
capturePaths: Immutable.fromJS([[1]])}));
|
||||
});
|
||||
it('should handle list patterns with discards', () => {
|
||||
expect(Immutable.fromJS(Skeleton.analyzeAssertion([__, __])))
|
||||
expect(Immutable.fromJS(_analyzeAssertion([__, __])))
|
||||
.to.equal(Immutable.fromJS({skeleton: [2, null, null],
|
||||
constPaths: Immutable.fromJS([]),
|
||||
constVals: Immutable.fromJS([]),
|
||||
capturePaths: Immutable.fromJS([])}));
|
||||
});
|
||||
it('should handle list patterns with constants and captures', () => {
|
||||
expect(Immutable.fromJS(Skeleton.analyzeAssertion(["hi", _$, _$])))
|
||||
expect(Immutable.fromJS(_analyzeAssertion(["hi", _$, _$])))
|
||||
.to.equal(Immutable.fromJS({skeleton: [3, null, null, null],
|
||||
constPaths: Immutable.fromJS([[0]]),
|
||||
constVals: Immutable.fromJS(["hi"]),
|
||||
|
@ -111,8 +115,8 @@ describe('skeleton', () => {
|
|||
|
||||
describe('nested structs', () => {
|
||||
let trace = skeletonTrace((i, traceHolder) => {
|
||||
i.addHandler(Skeleton.analyzeAssertion(A(B(_$), _$)), eventCallback(traceHolder, "AB"));
|
||||
i.addHandler(Skeleton.analyzeAssertion(A(B("x"), _$)), eventCallback(traceHolder, "ABx"));
|
||||
i.addHandler(_analyzeAssertion(A(B(_$), _$)), eventCallback(traceHolder, "AB"));
|
||||
i.addHandler(_analyzeAssertion(A(B("x"), _$)), eventCallback(traceHolder, "ABx"));
|
||||
let complexConstantPattern1 = {skeleton: [A.meta, null, [C.meta, null]],
|
||||
constPaths: Immutable.fromJS([[0]]),
|
||||
constVals: Immutable.fromJS([B("y")]),
|
||||
|
@ -125,10 +129,10 @@ describe('skeleton', () => {
|
|||
capturePaths: Immutable.fromJS([[1]])};
|
||||
i.addHandler(complexConstantPattern2, eventCallback(traceHolder, "ABByC"));
|
||||
|
||||
i.addAssertion(A(B("x"),C(1)));
|
||||
i.addAssertion(A(B("y"),C(2)));
|
||||
i.addAssertion(A(B(B("y")),C(2)));
|
||||
i.addAssertion(A(B("z"),C(3)));
|
||||
i.addAssertion(Immutable.fromJS(A(B("x"),C(1))));
|
||||
i.addAssertion(Immutable.fromJS(A(B("y"),C(2))));
|
||||
i.addAssertion(Immutable.fromJS(A(B(B("y")),C(2))));
|
||||
i.addAssertion(Immutable.fromJS(A(B("z"),C(3))));
|
||||
});
|
||||
|
||||
// trace.forEach((e) => { console.log(e.toString()) });
|
||||
|
@ -146,12 +150,12 @@ describe('skeleton', () => {
|
|||
|
||||
describe('simple detail-erasing trace', () => {
|
||||
let trace = skeletonTrace((i, traceHolder) => {
|
||||
i.addHandler(Skeleton.analyzeAssertion([__, __]), eventCallback(traceHolder, "2-EVENT"));
|
||||
i.addHandler(_analyzeAssertion([__, __]), eventCallback(traceHolder, "2-EVENT"));
|
||||
|
||||
i.addAssertion(["hi", 123]);
|
||||
i.addAssertion(["hi", 234]);
|
||||
i.removeAssertion(["hi", 123]);
|
||||
i.removeAssertion(["hi", 234]);
|
||||
i.addAssertion(Immutable.fromJS(["hi", 123]));
|
||||
i.addAssertion(Immutable.fromJS(["hi", 234]));
|
||||
i.removeAssertion(Immutable.fromJS(["hi", 123]));
|
||||
i.removeAssertion(Immutable.fromJS(["hi", 234]));
|
||||
});
|
||||
|
||||
it('should have one add and one remove', () => {
|
||||
|
@ -164,9 +168,9 @@ describe('skeleton', () => {
|
|||
|
||||
describe('handler added after assertion (1)', () => {
|
||||
let trace = skeletonTrace((i, traceHolder) => {
|
||||
i.addAssertion(["hi", 123, 234]);
|
||||
i.addHandler(Skeleton.analyzeAssertion(["hi", _$, _$]), eventCallback(traceHolder, "X"));
|
||||
i.removeAssertion(["hi", 123, 234]);
|
||||
i.addAssertion(Immutable.fromJS(["hi", 123, 234]));
|
||||
i.addHandler(_analyzeAssertion(["hi", _$, _$]), eventCallback(traceHolder, "X"));
|
||||
i.removeAssertion(Immutable.fromJS(["hi", 123, 234]));
|
||||
});
|
||||
|
||||
it('should get two events', () => {
|
||||
|
@ -178,9 +182,9 @@ describe('skeleton', () => {
|
|||
|
||||
describe('handler added after assertion (2)', () => {
|
||||
let trace = skeletonTrace((i, traceHolder) => {
|
||||
i.addAssertion(["hi", 123, 234]);
|
||||
i.addHandler(Skeleton.analyzeAssertion(_$), eventCallback(traceHolder, "X"));
|
||||
i.removeAssertion(["hi", 123, 234]);
|
||||
i.addAssertion(Immutable.fromJS(["hi", 123, 234]));
|
||||
i.addHandler(_analyzeAssertion(_$), eventCallback(traceHolder, "X"));
|
||||
i.removeAssertion(Immutable.fromJS(["hi", 123, 234]));
|
||||
});
|
||||
|
||||
it('should get two events', () => {
|
||||
|
@ -192,12 +196,12 @@ describe('skeleton', () => {
|
|||
|
||||
describe('handler removed before assertion removed', () => {
|
||||
let trace = skeletonTrace((i, traceHolder) => {
|
||||
i.addAssertion(["hi", 123, 234]);
|
||||
let h = Skeleton.analyzeAssertion(["hi", _$, _$]);
|
||||
i.addAssertion(Immutable.fromJS(["hi", 123, 234]));
|
||||
let h = _analyzeAssertion(["hi", _$, _$]);
|
||||
h.callback = eventCallback(traceHolder, "X")
|
||||
i.addHandler(h, h.callback);
|
||||
i.removeHandler(h, h.callback);
|
||||
i.removeAssertion(["hi", 123, 234]);
|
||||
i.removeAssertion(Immutable.fromJS(["hi", 123, 234]));
|
||||
});
|
||||
|
||||
it('should get one event', () => {
|
||||
|
@ -208,24 +212,24 @@ describe('skeleton', () => {
|
|||
|
||||
describe('simple list assertions trace', () => {
|
||||
let trace = skeletonTrace((i, traceHolder) => {
|
||||
i.addHandler(Skeleton.analyzeAssertion(["hi", _$, _$]), eventCallback(traceHolder, "3-EVENT"));
|
||||
i.addHandler(Skeleton.analyzeAssertion([__, __]), eventCallback(traceHolder, "2-EVENT"));
|
||||
i.addHandler(_analyzeAssertion(["hi", _$, _$]), eventCallback(traceHolder, "3-EVENT"));
|
||||
i.addHandler(_analyzeAssertion([__, __]), eventCallback(traceHolder, "2-EVENT"));
|
||||
|
||||
i.addAssertion(["hi", 123, 234]);
|
||||
i.addAssertion(["hi", 999, 999]);
|
||||
i.addAssertion(["hi", 123]);
|
||||
i.addAssertion(["hi", 123, 234]);
|
||||
i.sendMessage(["hi", 303]);
|
||||
i.sendMessage(["hi", 303, 404]);
|
||||
i.sendMessage(["hi", 303, 404, 808]);
|
||||
i.removeAssertion(["hi", 123, 234]);
|
||||
i.removeAssertion(["hi", 999, 999]);
|
||||
i.removeAssertion(["hi", 123, 234]);
|
||||
i.addAssertion(["hi", 123]);
|
||||
i.addAssertion(["hi", 234]);
|
||||
i.removeAssertion(["hi", 123]);
|
||||
i.removeAssertion(["hi", 123]);
|
||||
i.removeAssertion(["hi", 234]);
|
||||
i.addAssertion(Immutable.fromJS(["hi", 123, 234]));
|
||||
i.addAssertion(Immutable.fromJS(["hi", 999, 999]));
|
||||
i.addAssertion(Immutable.fromJS(["hi", 123]));
|
||||
i.addAssertion(Immutable.fromJS(["hi", 123, 234]));
|
||||
i.sendMessage(Immutable.fromJS(["hi", 303]));
|
||||
i.sendMessage(Immutable.fromJS(["hi", 303, 404]));
|
||||
i.sendMessage(Immutable.fromJS(["hi", 303, 404, 808]));
|
||||
i.removeAssertion(Immutable.fromJS(["hi", 123, 234]));
|
||||
i.removeAssertion(Immutable.fromJS(["hi", 999, 999]));
|
||||
i.removeAssertion(Immutable.fromJS(["hi", 123, 234]));
|
||||
i.addAssertion(Immutable.fromJS(["hi", 123]));
|
||||
i.addAssertion(Immutable.fromJS(["hi", 234]));
|
||||
i.removeAssertion(Immutable.fromJS(["hi", 123]));
|
||||
i.removeAssertion(Immutable.fromJS(["hi", 123]));
|
||||
i.removeAssertion(Immutable.fromJS(["hi", 234]));
|
||||
});
|
||||
|
||||
it('should have 8 entries', () => {
|
||||
|
|
Loading…
Reference in New Issue