From 44c1d425b3795775af41a6f42ea9be21fc3e974e Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Thu, 15 Nov 2018 23:24:58 +0000 Subject: [PATCH] Switch to Preserves for Record and Bytes --- packages/core/package.json | 3 +- packages/core/src/assertions.js | 21 ++- packages/core/src/bag.js | 3 +- packages/core/src/dataspace.js | 17 ++- packages/core/src/ground.js | 1 + packages/core/src/index.js | 4 +- packages/core/src/relay.js | 10 +- packages/core/src/skeleton.js | 36 ++--- packages/core/src/struct.js | 169 ----------------------- packages/core/test/test-dataspace.js | 19 ++- packages/core/test/test-skeleton.js | 53 ++++--- packages/driver-browser-ui/src/html.js | 15 +- packages/driver-http-node/src/index.js | 14 +- packages/driver-tcp-node/src/index.js | 21 +-- packages/driver-udp-node/src/index.js | 5 +- packages/driver-websocket/src/index.js | 6 +- packages/syntax-playground/src/client.js | 4 +- packages/syntax-playground/src/mc.js | 2 +- packages/syntax-playground/src/server.js | 9 ++ packages/syntax/src/plugin.js | 23 ++- 20 files changed, 144 insertions(+), 291 deletions(-) delete mode 100644 packages/core/src/struct.js diff --git a/packages/core/package.json b/packages/core/package.json index ad90956..d64b965 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -21,6 +21,7 @@ "nyc": "^13.1.0" }, "dependencies": { - "immutable": "^3.8.2" + "immutable": "^3.8.2", + "preserves": "^0.0.2" } } diff --git a/packages/core/src/assertions.js b/packages/core/src/assertions.js index 7861772..93fbfd2 100644 --- a/packages/core/src/assertions.js +++ b/packages/core/src/assertions.js @@ -17,13 +17,10 @@ // along with this program. If not, see . //--------------------------------------------------------------------------- -var Struct = require('./struct.js'); +var { Record } = require('preserves'); function Seal(contents) { - if (this === void 0) { - return new Seal(contents); - } - + if (!(this instanceof Seal)) return new Seal(contents); this.contents = contents; } @@ -35,10 +32,12 @@ Seal.prototype.toJSON = function () { return { '@seal': 0 }; }; -module.exports.Discard = Struct.makeConstructor('discard', []); -module.exports.Capture = Struct.makeConstructor('capture', ['specification']); -module.exports.Observe = Struct.makeConstructor('observe', ['specification']); +module.exports.Discard = Record.makeConstructor('discard', []); +module.exports.Capture = Record.makeConstructor('capture', ['specification']); +module.exports.Observe = Record.makeConstructor('observe', ['specification']); + +module.exports.Inbound = Record.makeConstructor('inbound', ['assertion']); +module.exports.Outbound = Record.makeConstructor('outbound', ['assertion']); +module.exports.Instance = Record.makeConstructor('instance', ['uniqueId']); + module.exports.Seal = Seal; -module.exports.Inbound = Struct.makeConstructor('inbound', ['assertion']); -module.exports.Outbound = Struct.makeConstructor('outbound', ['assertion']); -module.exports.Instance = Struct.makeConstructor('instance', ['uniqueId']); diff --git a/packages/core/src/bag.js b/packages/core/src/bag.js index 917b605..0533371 100644 --- a/packages/core/src/bag.js +++ b/packages/core/src/bag.js @@ -20,6 +20,7 @@ // Bags and Deltas (which are Bags where item-counts can be negative). const Immutable = require("immutable"); +const { fromJS } = require("preserves"); const PRESENT_TO_ABSENT = -1; const ABSENT_TO_ABSENT = 0; @@ -77,7 +78,7 @@ const Bag = Immutable.Map; function fromSet(s) { return Bag().withMutations(function (b) { for (let v of Immutable.Set(s)) { - b = b.set(Immutable.fromJS(v), 1); + b = b.set(fromJS(v), 1); } }); } diff --git a/packages/core/src/dataspace.js b/packages/core/src/dataspace.js index d4b96ae..0faa7b6 100644 --- a/packages/core/src/dataspace.js +++ b/packages/core/src/dataspace.js @@ -18,7 +18,8 @@ //--------------------------------------------------------------------------- const Immutable = require("immutable"); -const Struct = require('./struct.js'); +const { fromJS } = require("preserves"); + const Skeleton = require('./skeleton.js'); const $Special = require('./special.js'); const Bag = require('./bag.js'); @@ -343,14 +344,14 @@ 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); + a = 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); + a = fromJS(a); if (this.adhocAssertions.change(a, +1) === Bag.ABSENT_TO_PRESENT) { this.assert(a); } @@ -371,8 +372,10 @@ Patch.prototype.perform = function (ds, ac) { }; Patch.prototype.adjust = function (a, count) { - var _net; - ({bag: this.changes, net: _net} = Bag.change(this.changes, Immutable.fromJS(a), count)); + if (a !== void 0) { + var _net; + ({bag: this.changes, net: _net} = Bag.change(this.changes, fromJS(a), count)); + } }; function Message(body) { @@ -381,7 +384,7 @@ function Message(body) { Message.prototype.perform = function (ds, ac) { if (this.body !== void 0) { - ds.sendMessage(Immutable.fromJS(this.body)); + ds.sendMessage(fromJS(this.body)); } }; @@ -612,7 +615,7 @@ Endpoint.prototype._uninstall = function (ds, ac, emitPatches) { Endpoint.prototype.refresh = function (ds, ac, facet) { let [newAssertion, newHandler] = this.updateFun.call(facet.fields); - newAssertion = Immutable.fromJS(newAssertion); + if (newAssertion !== void 0) newAssertion = fromJS(newAssertion); if (!Immutable.is(newAssertion, this.assertion)) { this._uninstall(ds, ac, true); this._install(ds, ac, newAssertion, newHandler); diff --git a/packages/core/src/ground.js b/packages/core/src/ground.js index bd4afb9..93a8f07 100644 --- a/packages/core/src/ground.js +++ b/packages/core/src/ground.js @@ -19,6 +19,7 @@ Ground.prototype = new Dataspace(null); Ground._resolved = Promise.resolve(); Ground.laterCall = function (thunk) { Ground._resolved.then(() => { + Error.stackTraceLimit = 100; try { thunk(); } catch (e) { diff --git a/packages/core/src/index.js b/packages/core/src/index.js index 2dd4e83..41988f5 100644 --- a/packages/core/src/index.js +++ b/packages/core/src/index.js @@ -17,7 +17,6 @@ // along with this program. If not, see . //--------------------------------------------------------------------------- -const Struct = require('./struct.js'); const Skeleton = require('./skeleton.js'); const RandomID = require('./randomid.js'); const Dataspace = require('./dataspace.js'); @@ -25,11 +24,12 @@ const Ground = require('./ground.js'); const Assertions = require('./assertions.js'); const Relay = require('./relay.js'); +Object.assign(module.exports, require("preserves")); + module.exports.Immutable = require('immutable'); // ^ for use by import machinery in syntactic extensions module.exports.Bag = require("./bag.js"); -module.exports.Struct = Struct; module.exports.Skeleton = Skeleton; module.exports.RandomID = RandomID; diff --git a/packages/core/src/relay.js b/packages/core/src/relay.js index 23d6368..94a2e8a 100644 --- a/packages/core/src/relay.js +++ b/packages/core/src/relay.js @@ -47,18 +47,18 @@ NestedDataspace.prototype.sendMessage = function (m) { NestedDataspace.prototype.endpointHook = function (facet, innerEp) { const innerDs = this; Dataspace.prototype.endpointHook.call(this, facet, innerEp); - if (Observe.isClassOf(innerEp.assertion) && Inbound.isClassOf(innerEp.assertion[0])) { + if (Observe.isClassOf(innerEp.assertion) && Inbound.isClassOf(innerEp.assertion.get(0))) { // We know that innerEp.assertion is an Observe(Inbound(...)). // Also, if innerEp.handler exists, it will be consonant with innerEp.assertion. // Beware of completely-constant patterns, which cause skeleton to be null! this.hookEndpointLifecycle(innerEp, this.outerFacet.addEndpoint(() => { const h = innerEp.handler; - return [Observe(innerEp.assertion[0][0]), + return [Observe(innerEp.assertion.get(0).get(0)), h && (h.skeleton === null ? { skeleton: null, constPaths: h.constPaths, - constVals: h.constVals.map((v) => v[0]), + constVals: h.constVals.map((v) => v.get(0)), capturePaths: h.capturePaths.map((p) => p.shift()), callback: function (evt, captures) { h.callback.call(this, evt, captures); @@ -85,13 +85,13 @@ NestedDataspace.prototype.adjustIndex = function (a, count) { switch (net) { case Bag.ABSENT_TO_PRESENT: this.outerFacet.actor.pushScript(() => { - this.outerFacet.actor.adhocAssert(a[0]); + this.outerFacet.actor.adhocAssert(a.get(0)); }); this.outerFacet.actor.dataspace.start(); break; case Bag.PRESENT_TO_ABSENT: this.outerFacet.actor.pushScript(() => { - this.outerFacet.actor.adhocRetract(a[0]); + this.outerFacet.actor.adhocRetract(a.get(0)); }); this.outerFacet.actor.dataspace.start(); break; diff --git a/packages/core/src/skeleton.js b/packages/core/src/skeleton.js index d91408e..b1a8199 100644 --- a/packages/core/src/skeleton.js +++ b/packages/core/src/skeleton.js @@ -18,7 +18,8 @@ //--------------------------------------------------------------------------- const Immutable = require("immutable"); -const Struct = require('./struct.js'); +const { Record } = require("preserves"); + const $Special = require('./special.js'); const Bag = require('./bag.js'); const { Capture, Discard } = require('./assertions.js'); @@ -66,8 +67,8 @@ function Handler(cachedCaptures) { } function classOf(v) { - if (v instanceof Struct.Structure) { - return v.meta; + if (v instanceof Record) { + return v.getConstructorInfo(); } else if (v instanceof Immutable.List) { return v.size; } else { @@ -104,7 +105,7 @@ Node.prototype.extend = function(skeleton) { if (!nextNode) { nextNode = new Node(new Continuation( node.continuation.cachedAssertions.filter( - (a) => classOf(projectPath(a, path)) === cls))); + (a) => Immutable.is(classOf(projectPath(a, path)), cls)))); table = table.set(cls, nextNode); node.edges = node.edges.set(selector, table); } @@ -191,8 +192,7 @@ Node.prototype.modify = function(outerValue, m_cont, m_leaf, m_handler) { while (i--) { mutable.pop(); } }); let nextValue = step(nextStack.first(), selector.index); - let cls = classOf(nextValue); - let nextNode = table.get(cls, false); + let nextNode = table.get(classOf(nextValue), false); if (nextNode) { walkNode(nextNode, nextStack.push(nextValue)); } @@ -279,6 +279,15 @@ function analyzeAssertion(a) { let capturePaths = Immutable.List(); function walk(path, a) { + if (Capture.isClassOf(a)) { + capturePaths = capturePaths.push(path); + return walk(path, a.get(0)); + } + + if (Discard.isClassOf(a)) { + return null; + } + let cls = classOf(a); if (cls !== null) { let arity = (typeof cls === 'number') ? cls : cls.arity; @@ -287,18 +296,11 @@ function analyzeAssertion(a) { result.push(walk(path.push(i), step(a, i))); } return result; - } else { - if (Capture.isClassOf(a)) { - capturePaths = capturePaths.push(path); - return walk(path, a.get(0)); - } else if (Discard.isClassOf(a)) { - return null; - } else { - constPaths = constPaths.push(path); - constVals = constVals.push(a); - return null; - } } + + constPaths = constPaths.push(path); + constVals = constVals.push(a); + return null; } let skeleton = walk(Immutable.List(), a); diff --git a/packages/core/src/struct.js b/packages/core/src/struct.js deleted file mode 100644 index 213d5fe..0000000 --- a/packages/core/src/struct.js +++ /dev/null @@ -1,169 +0,0 @@ -"use strict"; -//--------------------------------------------------------------------------- -// @syndicate-lang/core, an implementation of Syndicate dataspaces for JS. -// Copyright (C) 2016-2018 Tony Garnock-Jones -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -//--------------------------------------------------------------------------- - -// "Structures": Simple named-tuple-like records. - -const Immutable = require("immutable"); -const $Special = require('./special.js'); - -function StructureType(label, arity) { - this.label = label; - this.arity = arity; - - var self = this; - this.ctor = function () { - return self.instantiate(Array.prototype.slice.call(arguments)); - }; - this.ctor.meta = this; - this.ctor.isClassOf = function (v) { return self.isClassOf(v); }; -} - -function makeConstructor(label, fieldNames) { - return new StructureType(label, fieldNames.length).ctor; -} - -StructureType.prototype.equals = function (other) { - if (!(other instanceof StructureType)) return false; - return this.arity === other.arity && this.label === other.label; -}; - -StructureType.prototype.hashCode = function () { - return Immutable.List([this.label, this.arity]).hashCode(); -}; - -StructureType.prototype.instantiate = function (fields) { - return new Structure(this, fields); -}; - -StructureType.prototype.isClassOf = function (v) { - return v && (v instanceof Structure) && (v.meta.equals(this)); -}; - -function Structure(meta, fields) { - if (!isStructureType(meta)) { - throw new Error("Structure: requires structure type"); - } - if (fields.length !== meta.arity) { - 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; - for (var i = 0; i < fields.length; i++) { - this[i] = fields[i] = Immutable.fromJS(fields[i]); - if (this[i] === void 0) { - throw new Error("Structure: cannot contain undefined value at field " + i); - } - } -} - -Structure.prototype.clone = function () { - return new Structure(this.meta, this.fields); -}; - -Structure.prototype.get = function (index) { - return this[index]; -}; - -Structure.prototype.set = function (index, value) { - var s = this.clone(); - s[index] = s.fields[index] = value; - return s; -}; - -Structure.prototype.equals = function (other) { - if (!other) return false; - if (!(other instanceof Structure)) return false; - if (!other.meta.equals(this.meta)) return false; - for (let i = 0; i < this.length; i++) { - 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; -}; - -Structure.prototype.hashCode = function () { - return Immutable.List(this.fields).unshift(this.meta).hashCode(); -}; - -Structure.prototype.toString = function () { - let b = this.meta.label + "("; - let needComma = false; - for (let v of this.fields) { - if (needComma) b = b + ", "; - needComma = true; - b = b + JSON.stringify(v); - } - return b + ")"; -}; - -function reviveStructs(j) { - if (Array.isArray(j)) { - return j.map(reviveStructs); - } - - if ((j !== null) && typeof j === 'object') { - if ((typeof j['@type'] === 'string') && Array.isArray(j['fields'])) { - return (new StructureType(j['@type'], j['fields'].length)).instantiate(j['fields']); - } else { - for (var k in j) { - if (Object.prototype.hasOwnProperty.call(j, k)) { - j[k] = reviveStructs(j[k]); - } - } - return j; - } - } - - return j; -} - -function reviver(k, v) { - if (k === '') { - return reviveStructs(v); - } - return v; -}; - -Structure.prototype.toJSON = function () { - return { '@type': this.meta.label, 'fields': this.fields }; -}; - -function isStructureType(v) { - return v && (v instanceof StructureType); -} - -function isStructure(v) { - return v && (v instanceof Structure); -} - -/////////////////////////////////////////////////////////////////////////// - -module.exports.StructureType = StructureType; -module.exports.makeConstructor = makeConstructor; -module.exports.Structure = Structure; -module.exports.reviveStructs = reviveStructs; -module.exports.reviver = reviver; -module.exports.isStructureType = isStructureType; -module.exports.isStructure = isStructure; diff --git a/packages/core/test/test-dataspace.js b/packages/core/test/test-dataspace.js index 50f1711..2866ade 100644 --- a/packages/core/test/test-dataspace.js +++ b/packages/core/test/test-dataspace.js @@ -24,28 +24,27 @@ chai.use(require('chai-immutable')); const Immutable = require('immutable'); const Syndicate = require('../src/index.js'); -const Skeleton = Syndicate.Skeleton; -const Dataspace = Syndicate.Dataspace; -const Struct = Syndicate.Struct; -const __ = Syndicate.__; -const _$ = Syndicate._$; +const { Skeleton, Dataspace, Observe, Capture, Discard } = Syndicate; describe('dataspace', () => { it('should boot and run', () => { // TODO: convert this into even a rudimentary somewhat-real test case // (change console.log into gathering a trace) - let ds = new Dataspace(null, () => { + let ds = new Dataspace(() => { // console.log('boot'); Dataspace.currentFacet().addEndpoint(() => { - let handler = Skeleton.analyzeAssertion(_$); + let handler = Skeleton.analyzeAssertion(Capture(Discard())); handler.callback = (evt, vs) => { - if (Syndicate.Observe.isClassOf(vs.get(0))) { - // console.log('OBSERVATION EVENT', evt, vs, vs.get(0).get(0) === _$); + if (Observe.isClassOf(vs.get(0))) { + // console.log('OBSERVATION EVENT', + // evt, + // vs, + // Immutable.is(vs.get(0).get(0), Capture(Discard()))); } else { // console.log('EVENT', evt, vs); } }; - return [Syndicate.Observe(_$), handler]; + return [Observe(Capture(Discard())), handler]; }); Dataspace.deferTurn(() => { // console.log('after defer'); diff --git a/packages/core/test/test-skeleton.js b/packages/core/test/test-skeleton.js index 33d2e4a..07f2924 100644 --- a/packages/core/test/test-skeleton.js +++ b/packages/core/test/test-skeleton.js @@ -24,12 +24,12 @@ chai.use(require('chai-immutable')); const Immutable = require('immutable'); const Syndicate = require('../src/index.js'); -const Skeleton = Syndicate.Skeleton; -const Struct = Syndicate.Struct; -const __ = Syndicate.__; -const _$ = Syndicate._$; +const { Seal, Skeleton, Capture, Discard, Record } = Syndicate; -const Event = Struct.makeConstructor('Event', ['label', 'type', 'values']); +const __ = Discard(); +const _$ = Capture(Discard()); + +const Event = Record.makeConstructor('Event', ['label', 'type', 'values']); function eventCallback(traceHolder, label) { return (e, vs) => { traceHolder.push(Event(label, e, vs)) }; @@ -51,21 +51,21 @@ function _analyzeAssertion(a) { describe('skeleton', () => { - const A = Struct.makeConstructor('A', ['x', 'y']); - const B = Struct.makeConstructor('B', ['v']); - const C = Struct.makeConstructor('C', ['v']); + const A = Record.makeConstructor('A', ['x', 'y']); + const B = Record.makeConstructor('B', ['v']); + const C = Record.makeConstructor('C', ['v']); describe('pattern analysis', () => { it('should handle leaf captures', () => { expect(Immutable.fromJS(_analyzeAssertion(A(B(_$), _$)))) - .to.equal(Immutable.fromJS({skeleton: [A.meta, [B.meta, null], null], + .to.equal(Immutable.fromJS({skeleton: [A.constructorInfo, [B.constructorInfo, null], null], constPaths: Immutable.fromJS([]), constVals: Immutable.fromJS([]), capturePaths: Immutable.fromJS([[0, 0], [1]])})); }); it('should handle atomic constants', () => { expect(Immutable.fromJS(_analyzeAssertion(A(B("x"), _$)))) - .to.equal(Immutable.fromJS({skeleton: [A.meta, [B.meta, null], null], + .to.equal(Immutable.fromJS({skeleton: [A.constructorInfo, [B.constructorInfo, null], null], constPaths: Immutable.fromJS([[0, 0]]), constVals: Immutable.fromJS(["x"]), capturePaths: Immutable.fromJS([[1]])})); @@ -77,12 +77,15 @@ 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. - let complexPlaceholder = new Object(); - 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]), - capturePaths: Immutable.fromJS([[1, 0]])})); + const complexPlaceholder = new Object(); + const analysis = Immutable.fromJS(_analyzeAssertion(A(complexPlaceholder, C(_$)))); + const expected = Immutable.fromJS({ + skeleton: [A.constructorInfo, null, [C.constructorInfo, null]], + constPaths: Immutable.fromJS([[0]]), + constVals: Immutable.List([complexPlaceholder]), + capturePaths: Immutable.fromJS([[1, 0]]), + }); + expect(analysis).to.equal(expected); }); it('should handle complex constants (2)', () => { // Marker: (***) @@ -91,8 +94,10 @@ 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(_analyzeAssertion(A(B(B("y")), _$("rhs", C(__)))))) - .to.equal(Immutable.fromJS({skeleton: [A.meta, [B.meta, [B.meta, null]], [C.meta, null]], + expect(Immutable.fromJS(_analyzeAssertion(A(B(B("y")), Capture(C(__)))))) + .to.equal(Immutable.fromJS({skeleton: [A.constructorInfo, + [B.constructorInfo, [B.constructorInfo, null]], + [C.constructorInfo, null]], constPaths: Immutable.fromJS([[0, 0, 0]]), constVals: Immutable.fromJS(["y"]), capturePaths: Immutable.fromJS([[1]])})); @@ -117,13 +122,15 @@ describe('skeleton', () => { let trace = skeletonTrace((i, traceHolder) => { 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]], + let complexConstantPattern1 = {skeleton: [A.constructorInfo, null, [C.constructorInfo, null]], constPaths: Immutable.fromJS([[0]]), constVals: Immutable.fromJS([B("y")]), capturePaths: Immutable.fromJS([[1, 0]])}; // ^ See comment in 'should handle complex constants (1)' test above (marked (***)). i.addHandler(complexConstantPattern1, eventCallback(traceHolder, "AByC")); - let complexConstantPattern2 = {skeleton: [A.meta, [B.meta, null], [C.meta, null]], + let complexConstantPattern2 = {skeleton: [A.constructorInfo, + [B.constructorInfo, null], + [C.constructorInfo, null]], constPaths: Immutable.fromJS([[0, 0]]), constVals: Immutable.fromJS([B("y")]), capturePaths: Immutable.fromJS([[1]])}; @@ -135,7 +142,7 @@ describe('skeleton', () => { i.addAssertion(Immutable.fromJS(A(B("z"),C(3)))); }); - // trace.forEach((e) => { console.log(e.toString()) }); + // trace.forEach((e) => { console.log(e) }); expect(trace) .to.equal(Immutable.List([ @@ -236,7 +243,7 @@ describe('skeleton', () => { expect(trace.size).to.equal(8); }); it('should have a correct 3-EVENT subtrace', () => { - expect(trace.filter((e) => { return e[0] === "3-EVENT"; })) + expect(trace.filter((e) => { return e.get(0) === "3-EVENT"; })) .to.equal(Immutable.List([ Event("3-EVENT", Skeleton.EVENT_ADDED, [123, 234]), Event("3-EVENT", Skeleton.EVENT_ADDED, [999, 999]), @@ -245,7 +252,7 @@ describe('skeleton', () => { Event("3-EVENT", Skeleton.EVENT_REMOVED, [123, 234])])); }); it('should have a correct 2-EVENT subtrace', () => { - expect(trace.filter((e) => { return e[0] === "2-EVENT"; })) + expect(trace.filter((e) => { return e.get(0) === "2-EVENT"; })) .to.equal(Immutable.List([ Event("2-EVENT", Skeleton.EVENT_ADDED, []), Event("2-EVENT", Skeleton.EVENT_MESSAGE, []), diff --git a/packages/driver-browser-ui/src/html.js b/packages/driver-browser-ui/src/html.js index ad0c25c..21ef0be 100644 --- a/packages/driver-browser-ui/src/html.js +++ b/packages/driver-browser-ui/src/html.js @@ -57,17 +57,18 @@ export function htmlToString(j) { function walk(j) { if (htmlTag.isClassOf(j)) { - pieces.push('<', j[0]); - j[1].forEach((p) => pieces.push(' ', escapeHtml(p[0]), '="', escapeHtml(p[1]), '"')); + pieces.push('<', j.get(0)); + j.get(1).forEach( + (p) => pieces.push(' ', escapeHtml(p.get(0)), '="', escapeHtml(p.get(1)), '"')); pieces.push('>'); - j[2].forEach(walk); - if (!(j[0] in emptyHtmlElements)) { - pieces.push(''); + j.get(2).forEach(walk); + if (!(j.get(0) in emptyHtmlElements)) { + pieces.push(''); } } else if (htmlFragment.isClassOf(j)) { - j[0].forEach(walk); + j.get(0).forEach(walk); } else if (htmlLiteral.isClassOf(j)) { - pieces.push(j[0]); + pieces.push(j.get(0)); } else if (typeof j === 'object' && j && typeof j[Symbol.iterator] === 'function') { for (let k of j) { walk(k); } } else { diff --git a/packages/driver-http-node/src/index.js b/packages/driver-http-node/src/index.js index f29230e..90916a8 100644 --- a/packages/driver-http-node/src/index.js +++ b/packages/driver-http-node/src/index.js @@ -16,7 +16,7 @@ // along with this program. If not, see . //--------------------------------------------------------------------------- -import { genUuid, Seal, Capture, Observe, Dataspace, currentFacet } from "@syndicate-lang/core"; +import { genUuid, Seal, Capture, Observe, Dataspace, currentFacet, Bytes } from "@syndicate-lang/core"; import { parse as parseUrl } from "url"; const http = require('http'); @@ -40,14 +40,14 @@ Object.assign(module.exports, { Response, DataOut, }); -spawn named 'HttpServerFactory' { +spawn named 'driver/HttpServerFactory' { during Observe(Request(_, HttpServer($h, $p), _, _, _, _)) assert HttpServer(h, p); during Observe(Request(_, HttpsServer($h, $p, $o), _, _, _, _)) assert HttpsServer(h, p, o); - during HttpServer($host, $port) spawn named ['HttpServer', host, port] { + during HttpServer($host, $port) spawn named ['driver/HttpServer', host, port] { _server.call(this, host, port, null); } - during HttpsServer($host, $port, $options) spawn named ['HttpsServer', host, port] { + during HttpsServer($host, $port, $options) spawn named ['driver/HttpsServer', host, port] { _server.call(this, host, port, options); } } @@ -179,7 +179,7 @@ function _server(host, port, httpsOptions) { facet.stop(); } on message DataOut(id, $chunk) { - res.write(chunk); + res.write(Bytes.toIO(chunk)); } } } else { @@ -218,12 +218,12 @@ function _server(host, port, httpsOptions) { on asserted Observe(DataIn(id, _)) { ws.on('message', Dataspace.wrapExternal((message) => { - ^ DataIn(id, message); + ^ DataIn(id, Bytes.fromIO(message)); })); } on message DataOut(id, $message) { - ws.send(message); + ws.send(Bytes.toIO(message)); } stop on retracted Observe(WebSocket(_, server, pathPattern, _)); diff --git a/packages/driver-tcp-node/src/index.js b/packages/driver-tcp-node/src/index.js index 355f5f0..03e2227 100644 --- a/packages/driver-tcp-node/src/index.js +++ b/packages/driver-tcp-node/src/index.js @@ -16,7 +16,7 @@ // along with this program. If not, see . //--------------------------------------------------------------------------- -import { currentFacet, Observe, Dataspace, genUuid } from "@syndicate-lang/core"; +import { currentFacet, Observe, Dataspace, genUuid, Bytes } from "@syndicate-lang/core"; const net = require('net'); const { sleep } = activate require("@syndicate-lang/driver-timer"); @@ -38,14 +38,14 @@ export { TcpAddress, TcpListener, }; -spawn named 'TcpDriver' { - during Observe(TcpConnection(_, TcpListener($port))) spawn named ['TcpListener', port] { +spawn named 'driver/TcpDriver' { + during Observe(TcpConnection(_, TcpListener($port))) spawn named ['driver/TcpListener', port] { let finish = Dataspace.backgroundTask(); on stop finish(); let server = net.createServer(Dataspace.wrapExternal((socket) => { let id = genUuid('tcp' + port); - spawn named ['TcpInbound', id] { + spawn named ['driver/TcpInbound', id] { assert TcpConnection(id, TcpListener(port)); on asserted TcpAccepted(id) _connectionCommon.call(this, currentFacet(), id, socket, true); stop on retracted TcpAccepted(id); @@ -57,7 +57,8 @@ spawn named 'TcpDriver' { on stop try { server.close() } catch (e) { console.error(e); } } - during TcpConnection($id, TcpAddress($host, $port)) spawn named ['TcpOutbound', id, host, port] { + during TcpConnection($id, TcpAddress($host, $port)) + spawn named ['driver/TcpOutbound', id, host, port] { let finish = Dataspace.backgroundTask(); on stop finish(); @@ -69,9 +70,9 @@ spawn named 'TcpDriver' { } } - during Observe(LineIn($id, _)) spawn named ['TcpLineReader', id] { - field this.buffer = Buffer.alloc(0); - on message DataIn(id, $data) this.buffer = Buffer.concat([this.buffer, data]); + during Observe(LineIn($id, _)) spawn named ['driver/TcpLineReader', id] { + field this.buffer = Bytes(); + on message DataIn(id, $data) this.buffer = Bytes.concat([this.buffer, data]); dataflow { const pos = this.buffer.indexOf(10); if (pos !== -1) { @@ -107,12 +108,12 @@ function _connectionCommon(rootFacet, id, socket, established) { on start react stop on asserted Observe(DataIn(id, _)) { socket.on('data', Dataspace.wrapExternal((data) => { - ^ DataIn(id, data); + ^ DataIn(id, Bytes.fromIO(data)); })); } on message DataOut(id, $data) { - socket.write(data); + socket.write(Bytes.toIO(data)); } } } diff --git a/packages/driver-udp-node/src/index.js b/packages/driver-udp-node/src/index.js index 5055cf0..9f58cd6 100644 --- a/packages/driver-udp-node/src/index.js +++ b/packages/driver-udp-node/src/index.js @@ -16,7 +16,7 @@ // along with this program. If not, see . //--------------------------------------------------------------------------- -import { currentFacet, Observe, Dataspace } from "@syndicate-lang/core"; +import { currentFacet, Observe, Dataspace, Bytes } from "@syndicate-lang/core"; import { createSocket } from "dgram"; const { sleep } = activate require("@syndicate-lang/driver-timer"); @@ -70,7 +70,7 @@ function _socket(addr, port) { socket.on('listening', Dataspace.wrapExternal(() => { this.connected = true; })); socket.on('message', Dataspace.wrapExternal((message, rinfo) => { - ^ UdpPacket(UdpPeer(rinfo.address, rinfo.port), addr, message); + ^ UdpPacket(UdpPeer(rinfo.address, rinfo.port), addr, Bytes.fromIO(message)); })); }; @@ -88,6 +88,7 @@ function _socket(addr, port) { assert addr when (this.connected); on message UdpPacket(addr, UdpPeer($host, $port), $payload) { + payload = Bytes.toIO(payload); socket.send(payload, 0, payload.length, port, host, Dataspace.wrapExternal((err) => { if (err) { console.error(err); diff --git a/packages/driver-websocket/src/index.js b/packages/driver-websocket/src/index.js index 2bad7cb..4136226 100644 --- a/packages/driver-websocket/src/index.js +++ b/packages/driver-websocket/src/index.js @@ -16,7 +16,7 @@ // along with this program. If not, see . //--------------------------------------------------------------------------- -import { currentFacet, Observe, Dataspace } from "@syndicate-lang/core"; +import { currentFacet, Bytes, Observe, Dataspace } from "@syndicate-lang/core"; const { sleep } = activate require("@syndicate-lang/driver-timer"); const _WebSocket = require('isomorphic-ws'); @@ -52,7 +52,7 @@ spawn named 'WebSocketFactory' { ws.onopen = Dataspace.wrapExternal(() => { this.connected = true; }); ws.onclose = Dataspace.wrapExternal(() => { if (this.connected) { connect(); }}); - ws.onmessage = Dataspace.wrapExternal((data) => { ^ DataIn(id, data.data); }); + ws.onmessage = Dataspace.wrapExternal((data) => { ^ DataIn(id, Bytes.fromIO(data.data)); }); }; const disconnect = () => { @@ -70,7 +70,7 @@ spawn named 'WebSocketFactory' { on message DataOut(id, $data) { if (this.connected) { - ws.send(data); + ws.send(Bytes.toIO(data)); } } } diff --git a/packages/syntax-playground/src/client.js b/packages/syntax-playground/src/client.js index 0ed3294..a15bd77 100644 --- a/packages/syntax-playground/src/client.js +++ b/packages/syntax-playground/src/client.js @@ -16,7 +16,7 @@ // along with this program. If not, see . //--------------------------------------------------------------------------- -import { currentFacet, genUuid } from "@syndicate-lang/core"; +import { currentFacet, genUuid, Bytes } from "@syndicate-lang/core"; const WS = activate require("@syndicate-lang/driver-websocket"); const { PeriodicTick } = activate require("@syndicate-lang/driver-timer"); @@ -34,7 +34,7 @@ spawn named 'demo' { } on message PeriodicTick(1000) { - ^ WS.DataOut(wsId, genUuid('timestamp')); + ^ WS.DataOut(wsId, Bytes.from(genUuid('timestamp'))); } } } diff --git a/packages/syntax-playground/src/mc.js b/packages/syntax-playground/src/mc.js index d9ce76c..96e13b5 100644 --- a/packages/syntax-playground/src/mc.js +++ b/packages/syntax-playground/src/mc.js @@ -35,7 +35,7 @@ spawn named 'multicast_demo' { assert U.UdpMulticastLoopback(HANDLE, true); on message U.UdpPacket(U.UdpPeer($host, $port), HANDLE, $body) { - console.log('Got', body.toString(), 'from', host, port); + console.log('Got', body, 'from', host, port); } on message PeriodicTick(2000) { diff --git a/packages/syntax-playground/src/server.js b/packages/syntax-playground/src/server.js index 4c6de0c..51551d7 100644 --- a/packages/syntax-playground/src/server.js +++ b/packages/syntax-playground/src/server.js @@ -74,6 +74,15 @@ function counter() { return id; } +spawn named 'serverLogger' { + on asserted Http.Request(_, server, $method, $path, $query, $req) { + console.log(method, path.toJS(), query.toJS()); + } + on asserted Http.WebSocket(_, server, $path, $query) { + console.log(path.toJS(), query.toJS()); + } +} + spawn named 'rootServer' { let counters = {}; on asserted Counter($id) counters[id] = true; diff --git a/packages/syntax/src/plugin.js b/packages/syntax/src/plugin.js index 053cfdf..472b10c 100644 --- a/packages/syntax/src/plugin.js +++ b/packages/syntax/src/plugin.js @@ -66,9 +66,9 @@ function discardAst(state) { return _discardAst({ SYNDICATE: state.SyndicateID }); } -const _listAst = template.expression(`IMMUTABLE.fromJS(VS)`); +const _listAst = template.expression(`SYNDICATE.fromJS(VS)`); function listAst(state, vs) { - return _listAst({ IMMUTABLE: state.ImmutableID, VS: vs }); + return _listAst({ SYNDICATE: state.SyndicateID, VS: vs }); } function captureWrap(state, ast) { @@ -123,7 +123,7 @@ function compilePattern(state, patternPath) { // constPaths/constVals. if (hasCapturesOrDiscards(patternPath)) { let arity = pattern.arguments.length; - let skel = [t.memberExpression(pattern.callee, t.identifier('meta'), false, false)]; + let skel = [t.memberExpression(pattern.callee, t.identifier('constructorInfo'), false, false)]; let assn = []; for (let i = 0; i < arity; i++) { syndicatePath.push(i); @@ -295,25 +295,22 @@ export default declare((api, options) => { visitor: { Program(path, state) { let savedGlobalFacetUid = path.scope.generateUidIdentifier("savedGlobalFacet"); - state.ImmutableID = path.scope.generateUidIdentifier("Immutable"); state.SyndicateID = path.scope.generateUidIdentifier("Syndicate"); state.DataspaceID = path.scope.generateUidIdentifier("Dataspace"); state.SkeletonID = path.scope.generateUidIdentifier("Skeleton"); - state.StructID = path.scope.generateUidIdentifier("Struct"); + state.RecordID = path.scope.generateUidIdentifier("Record"); path.unshiftContainer( 'body', template(`const SYNDICATE = require("@syndicate-lang/core"); - const IMMUTABLE = SYNDICATE.Immutable; const DATASPACE = SYNDICATE.Dataspace; const SKELETON = SYNDICATE.Skeleton; - const STRUCT = SYNDICATE.Struct; + const RECORD = SYNDICATE.Record; let SAVEDGLOBALFACET = DATASPACE._currentFacet; DATASPACE._currentFacet = new SYNDICATE._Dataspace.ActionCollector();`)({ - IMMUTABLE: state.ImmutableID, SYNDICATE: state.SyndicateID, DATASPACE: state.DataspaceID, SKELETON: state.SkeletonID, - STRUCT: state.StructID, + RECORD: state.RecordID, SAVEDGLOBALFACET: savedGlobalFacetUid, })); path.pushContainer( @@ -346,8 +343,8 @@ export default declare((api, options) => { PROC: node.bootProc }), ASSERTIONS: node.initialAssertions.length === 0 ? null : - template.expression(`IMMUTABLE.Set(SEQ)`)({ - IMMUTABLE: state.ImmutableID, + template.expression(`SYNDICATE.Set(SEQ)`)({ + SYNDICATE: state.SyndicateID, SEQ: t.arrayExpression(node.initialAssertions) }), })); @@ -453,9 +450,9 @@ export default declare((api, options) => { SyndicateTypeDefinition(path, state) { const { node } = path; - path.replaceWith(template(`const ID = STRUCT.makeConstructor(WIRE, FORMALS);`)({ + path.replaceWith(template(`const ID = RECORD.makeConstructor(WIRE, FORMALS);`)({ ID: node.id, - STRUCT: state.StructID, + RECORD: state.RecordID, WIRE: node.wireName || t.stringLiteral(node.id.name), FORMALS: t.arrayExpression(node.formals.map((f) => t.stringLiteral(f.name))), }));