/// SPDX-License-Identifier: GPL-3.0-or-later /// SPDX-FileCopyrightText: Copyright © 2024 Tony Garnock-Jones 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 = {}): { 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; } function expectCodeEqual(input: string, output: string) { expect(format(translateNoErrors(input))).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; } } )) }) }));`)); }); 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;}) } } }), }), })); });`)); });