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

142 lines
6.5 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';
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): string {
const o = translate(source);
expect(o.errors.length).toBe(0);
return o.code;
}
describe('react', () => {
it('without label', () => {
expect(translateNoErrors(`react { a; b; c; }`)).toBe(
`__SYNDICATE__.Turn.active.facet(() => {const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet; a; b; c; });`);
});
it('with label', () => {
expect(translateNoErrors(`someLabel: react { a; b; c; }`)).toBe(
`__SYNDICATE__.Turn.active.facet(() => {const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet; const someLabel = currentSyndicateFacet; a; b; c; });`);
});
});
describe('spawn', () => {
it('without name', () => {
expect(translateNoErrors(`spawn { a; b; c; }`)).toBe(
`__SYNDICATE__.Dataspace._spawn(() => { const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet; a; b; c; });`);
});
it('with name', () => {
expect(translateNoErrors(`spawn named 'foo' { a; b; c; }`)).toBe(
`__SYNDICATE__.Dataspace._spawn(() => { const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet; currentSyndicateFacet.actor.name = 'foo'; a; b; c; });`);
});
it('with missing name (known incorrect parsing and codegen)', () => {
// At present, the expr() parser accepts *empty input*. TODO: something better.
expect(translateNoErrors(`spawn named { a; b; c; }`)).toBe(
`__SYNDICATE__.Dataspace._spawn(() => { const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet; currentSyndicateFacet.actor.name = ; a; b; c; });`);
});
});
describe('stop', () => {
it('non-statement', () => {
expect(translateNoErrors(`stop`)).toBe(
`stop`);
});
it('without facet, without body', () => {
expect(translateNoErrors(`stop;`)).toBe(
`__SYNDICATE__.Turn.active._stop(currentSyndicateFacet, () => {const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;});`);
});
it('without facet, empty body', () => {
expect(translateNoErrors(`stop {}`)).toBe(
`__SYNDICATE__.Turn.active._stop(currentSyndicateFacet, () => {const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;});`);
});
it('without facet, non-empty body', () => {
expect(translateNoErrors(`stop { a; b; }`)).toBe(
`__SYNDICATE__.Turn.active._stop(currentSyndicateFacet, () => {const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet; a; b; });`);
});
it('with facet, without body', () => {
expect(translateNoErrors(`stop x.y;`)).toBe(
`__SYNDICATE__.Turn.active._stop(x.y, () => {const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;});`);
});
it('with facet, empty body', () => {
expect(translateNoErrors(`stop x.y {}`)).toBe(
`__SYNDICATE__.Turn.active._stop(x.y, () => {const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;});`);
});
it('with facet, non-empty body', () => {
expect(translateNoErrors(`stop x.y { a; b; }`)).toBe(
`__SYNDICATE__.Turn.active._stop(x.y, () => {const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet; a; b; });`);
});
it('nested stop, no labels', () => {
expect(translateNoErrors(`stop { stop; }`)).toBe(
`__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', () => {
expect(translateNoErrors(`during P => { a; stop; b; }`)).toBe(
`__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;
}
}
))
}) }));`);
});
});
describe('once', () => {
it('basics with block', () => {
expect(translateNoErrors(`once asserted P => { a; b; }`)).toBe(
`__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', () => {
expect(translateNoErrors(`once asserted P => x;`)).toBe(
`__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;})
}
}
}),
}),
}));});`);
});
});