Switch to Preserves for Record and Bytes

This commit is contained in:
Tony Garnock-Jones 2018-11-15 23:24:58 +00:00
parent ea907c5aee
commit 44c1d425b3
20 changed files with 144 additions and 291 deletions

View File

@ -21,6 +21,7 @@
"nyc": "^13.1.0"
},
"dependencies": {
"immutable": "^3.8.2"
"immutable": "^3.8.2",
"preserves": "^0.0.2"
}
}

View File

@ -17,13 +17,10 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//---------------------------------------------------------------------------
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']);

View File

@ -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);
}
});
}

View File

@ -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);

View File

@ -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) {

View File

@ -17,7 +17,6 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//---------------------------------------------------------------------------
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;

View File

@ -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;

View File

@ -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);

View File

@ -1,169 +0,0 @@
"use strict";
//---------------------------------------------------------------------------
// @syndicate-lang/core, an implementation of Syndicate dataspaces for JS.
// Copyright (C) 2016-2018 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
//
// 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 <https://www.gnu.org/licenses/>.
//---------------------------------------------------------------------------
// "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;

View File

@ -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');

View File

@ -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, []),

View File

@ -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[0], '>');
j.get(2).forEach(walk);
if (!(j.get(0) in emptyHtmlElements)) {
pieces.push('</', j.get(0), '>');
}
} 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 {

View File

@ -16,7 +16,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//---------------------------------------------------------------------------
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, _));

View File

@ -16,7 +16,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//---------------------------------------------------------------------------
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));
}
}
}

View File

@ -16,7 +16,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//---------------------------------------------------------------------------
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);

View File

@ -16,7 +16,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//---------------------------------------------------------------------------
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));
}
}
}

View File

@ -16,7 +16,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//---------------------------------------------------------------------------
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')));
}
}
}

View File

@ -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) {

View File

@ -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;

View File

@ -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))),
}));