syndicate-js/packages/compiler/test/compiler.test.ts

214 lines
7.4 KiB
TypeScript

/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { compile, CompileOptions, Syntax } from '../src/index';
import Pos = Syntax.Pos;
import './test-utils';
import { js as format } from 'js-beautify';
type Error = { message: string, start: Pos | undefined, end: Pos | undefined };
function translate(source: string, options: Partial<CompileOptions> = {}): { code: string, errors: Error[] } {
const errors: Error[] = [];
const result = compile({
... options,
module: 'none',
source,
emitError: (message, start, end) => errors.push({ message, start, end }),
});
return { code: result.text, errors };
}
function translateNoErrors(source: string, options?: Partial<CompileOptions>): string {
const o = translate(source, options);
expect(o.errors.length).toBe(0);
return o.code;
}
function expectCodeEqual(input: string, output: string, options?: Partial<CompileOptions>) {
expect(format(translateNoErrors(input, options))).toBe(format(output));
}
describe('react', () => {
it('without label', () => expectCodeEqual(`react { a; b; c; }`, `
__SYNDICATE__.Turn.active.facet(() => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
a; b; c;
});`));
it('with label', () => expectCodeEqual(`someLabel: react { a; b; c; }`, `
__SYNDICATE__.Turn.active.facet(() => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
const someLabel = currentSyndicateFacet;
a; b; c;
});`));
});
describe('spawn', () => {
it('without name', () => expectCodeEqual(`spawn { a; b; c; }`, `
__SYNDICATE__.Dataspace._spawn(() => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
a; b; c;
});`));
it('with name', () => expectCodeEqual(`spawn named 'foo' { a; b; c; }`, `
__SYNDICATE__.Dataspace._spawn(() => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
currentSyndicateFacet.actor.name = 'foo';
a; b; c;
});`));
// At present, the expr() parser accepts *empty input*. TODO: something better.
it('with missing name (known incorrect parsing and codegen)', () =>
expectCodeEqual(`spawn named { a; b; c; }`, `
__SYNDICATE__.Dataspace._spawn(() => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
currentSyndicateFacet.actor.name = ;
a; b; c;
});`));
});
describe('stop', () => {
it('non-statement', () => expectCodeEqual(`(stop)`, `(stop)`));
it('toplevel end-delimited statement', () => expectCodeEqual(`stop`, `
__SYNDICATE__.Turn.active._stop(currentSyndicateFacet, () => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
});`));
it('nested end-delimited statement', () => expectCodeEqual(`{ stop }`, `
{
__SYNDICATE__.Turn.active._stop(currentSyndicateFacet, () => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
});
}`));
it('without facet, without body', () => expectCodeEqual(`stop;`, `
__SYNDICATE__.Turn.active._stop(currentSyndicateFacet, () => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
});`));
it('without facet, empty body', () => expectCodeEqual(`stop {}`, `
__SYNDICATE__.Turn.active._stop(currentSyndicateFacet, () => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
});`));
it('without facet, non-empty body', () => expectCodeEqual(`stop { a; b; }`, `
__SYNDICATE__.Turn.active._stop(currentSyndicateFacet, () => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
a; b;
});`));
it('with facet, without body', () => expectCodeEqual(`stop x.y;`, `
__SYNDICATE__.Turn.active._stop(x.y, () => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
});`));
it('with facet, empty body', () => expectCodeEqual(`stop x.y {}`, `
__SYNDICATE__.Turn.active._stop(x.y, () => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
});`));
it('with facet, non-empty body', () => expectCodeEqual(`stop x.y { a; b; }`, `
__SYNDICATE__.Turn.active._stop(x.y, () => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
a; b;
});`));
it('nested stop, no labels', () => expectCodeEqual(`stop { stop; }`, `
__SYNDICATE__.Turn.active._stop(currentSyndicateFacet, () => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
__SYNDICATE__.Turn.active._stop(currentSyndicateFacet, () => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
});
});`));
});
describe('during', () => {
it('stop in body', () => expectCodeEqual(`during P => { a; stop; b; }`, `
__SYNDICATE__.Turn.active.assertDataflow(() => ({
target: currentSyndicateTarget,
assertion: __SYNDICATE__.Observe({
pattern: __SYNDICATE__.QuasiValue.finish((__SYNDICATE__.QuasiValue.lit(__SYNDICATE__.fromJS(P)))),
observer: __SYNDICATE__.Turn.ref(__SYNDICATE__.assertionFacetObserver(
(__vs) => {
if (Array.isArray(__vs)) {
a;
__SYNDICATE__.Turn.active._stop(currentSyndicateFacet, () => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
});
b;
}
}
))
})
}));`));
it('capture with type at top', () => expectCodeEqual(`during $v: T => { ok() }`, `
__SYNDICATE__.Turn.active.assertDataflow(() => ({
target: currentSyndicateTarget,
assertion: __SYNDICATE__.Observe({
pattern: __SYNDICATE__.QuasiValue.finish((__SYNDICATE__.QuasiValue.bind((__SYNDICATE__.QuasiValue._)))),
observer: __SYNDICATE__.Turn.ref(__SYNDICATE__.assertionFacetObserver(
(__vs: __SYNDICATE__.AnyValue) => {
if (Array.isArray(__vs)) {
const __v_0 = T.__from_preserve__(__vs[0]);
if (__v_0 === void 0) return;
const v = __v_0;
ok()
}
}
))
})
}));
`, { typescript: true }));
});
describe('once', () => {
it('basics with block', () => expectCodeEqual(`once asserted P => { a; b; }`, `
__SYNDICATE__.Turn.active.facet(() => {
const __once_facet = __SYNDICATE__.Turn.activeFacet;
__SYNDICATE__.Turn.active.assertDataflow(() => ({
target: currentSyndicateTarget,
assertion: __SYNDICATE__.Observe({
pattern: __SYNDICATE__.QuasiValue.finish((__SYNDICATE__.QuasiValue.lit(__SYNDICATE__.fromJS(P)))),
observer: __SYNDICATE__.Turn.ref({
assert: (__vs, __handle) => {
if (Array.isArray(__vs)) {
__SYNDICATE__.Turn.active._stop(__once_facet, () => { a; b; })
}
}
}),
}),
}));
});`));
it('basics with statement', () => expectCodeEqual(`once asserted P => x;`, `
__SYNDICATE__.Turn.active.facet(() => {
const __once_facet = __SYNDICATE__.Turn.activeFacet;
__SYNDICATE__.Turn.active.assertDataflow(() => ({
target: currentSyndicateTarget,
assertion: __SYNDICATE__.Observe({
pattern: __SYNDICATE__.QuasiValue.finish((__SYNDICATE__.QuasiValue.lit(__SYNDICATE__.fromJS(P)))),
observer: __SYNDICATE__.Turn.ref({
assert: (__vs, __handle) => {
if (Array.isArray(__vs)) {
__SYNDICATE__.Turn.active._stop(__once_facet, () => {x;})
}
}
}),
}),
}));
});`));
});