From 0a8975a2f6c9743c5acf72e0fdcedb669cdad422 Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Thu, 21 Dec 2023 10:30:23 +1300 Subject: [PATCH] once asserted ..., once message ..., etc --- packages/compiler/src/compiler/codegen.ts | 20 +++++++++++++------- packages/compiler/src/compiler/grammar.ts | 10 ++++++++-- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/packages/compiler/src/compiler/codegen.ts b/packages/compiler/src/compiler/codegen.ts index 202d43f..e4684e8 100644 --- a/packages/compiler/src/compiler/codegen.ts +++ b/packages/compiler/src/compiler/codegen.ts @@ -124,6 +124,10 @@ export function expand(tree: Items, ctx: ExpansionContext): Items { } } + function facetWrap(t: TemplateFunction, items: Items): Items { + return t`__SYNDICATE__.Turn.active.facet(() => {${items}})`; + } + function x(p: Pattern, f: (v: T, t: TemplateFunction) => Items) { tree = replace(tree, p, (v, start) => f(v, macro.template(fixPos(start)))); } @@ -222,8 +226,10 @@ ${joinItems(sa.captureBinders.map(binderTypeGuard(t)), '\n')} t`_dataflow(() => {${walk(s.body)}});`); x(ctx.parser.eventHandlerEndpointStatement, (s, t) => { + const wrap = s.once ? (i: Items) => facetWrap(t, i) : (i: Items) => i; + if (s.triggerType === 'dataflow') { - return t`__SYNDICATE__.Turn.active._dataflow(() => { if (${walk(s.predicate)}) { ${terminalWrap(t, s.terminal, walk(s.body))} } });`; + return wrap(t`__SYNDICATE__.Turn.active._dataflow(() => { if (${walk(s.predicate)}) { ${terminalWrap(t, s.terminal, walk(s.body))} } });`); } if (s.triggerType === 'stop') { @@ -265,12 +271,14 @@ ${joinItems(sa.captureBinders.map(binderTypeGuard(t)), '\n')} })`; if (s.isDynamic) { - return t`__SYNDICATE__.Turn.active.assertDataflow(() => ({ + return wrap(t`__SYNDICATE__.Turn.active.assertDataflow(() => ({ target: currentSyndicateTarget, assertion: ${assertion}, - }));`; + }));`); } else { - return t`__SYNDICATE__.Turn.active.replace(currentSyndicateTarget, void 0, ${assertion});`; + return wrap( + t`__SYNDICATE__.Turn.active.replace(currentSyndicateTarget, void 0, ${assertion});` + ); } }); @@ -286,9 +294,7 @@ ${joinItems(sa.captureBinders.map(binderTypeGuard(t)), '\n')} xf(ctx.parser.messageSendStatement, (s, t) => t`message(currentSyndicateTarget, ${walk(s.expr)});`); - xf(ctx.parser.reactStatement, (s, t) => { - return t`facet(() => {${s.body}});`; - }); + x(ctx.parser.reactStatement, (s, t) => facetWrap(t, s.body)); x(ctx.parser.stopStatement, (s, t) => t`__SYNDICATE__.Turn.active._stop(__SYNDICATE__.Turn.activeFacet, () => {${walk(s.body)}});`) diff --git a/packages/compiler/src/compiler/grammar.ts b/packages/compiler/src/compiler/grammar.ts index 32f2bba..127e8f4 100644 --- a/packages/compiler/src/compiler/grammar.ts +++ b/packages/compiler/src/compiler/grammar.ts @@ -52,6 +52,7 @@ export interface StatementTurnAction extends TurnAction { export interface GenericEventEndpointStatement extends StatementTurnAction { terminal: boolean; + once: boolean; isDynamic: boolean; } @@ -278,10 +279,15 @@ export class SyndicateParser { readonly eventHandlerEndpointStatement: Pattern = this.turnAction(o => { o.terminal = false; + o.once = false; o.isDynamic = true; o.body = []; - return seq(option(map(atom('stop'), _ => o.terminal = true)), - atom('on'), + return seq(alt(seq(option(map(atom('stop'), _ => o.terminal = true)), + atom('on')), + map(atom('once'), _ => { + o.terminal = true; + o.once = true; + })), alt(seq(map(group('(', bind(o as DataflowEndpointStatement, 'predicate', this.expr())), _ => o.triggerType = 'dataflow'),