# SPDX-FileCopyrightText: ☭ 2021 Emery Hemingway # SPDX-License-Identifier: Unlicense import std/macros import preserves import syndicate/[actors, patterns] export patterns proc wrapPublishHandler(handler: NimNode): NimNode = handler.expectKind nnkDo var innerProc = newNimNode(nnkProcDef) handler.copyChildrenTo innerProc innerProc[0] = genSym(nskProc, "message") var formalArgs = handler[3] valuesSym = genSym(nskVar, "values") valuesTuple = newNimNode(nnkTupleTy, handler) innerTuple = newNimNode(nnkVarTuple, handler) varSectionInner = newNimNode(nnkVarSection, handler).add(innerTuple) for i, arg in formalArgs: if i > 0: arg.expectKind nnkIdentDefs if arg[1].kind == nnkEmpty: error("type required for capture", arg) var def = newNimNode(nnkIdentDefs, arg) arg.copyChildrenTo def valuesTuple.add(def) innerTuple.add(arg[0]) innerTuple.add(newEmptyNode(), valuesSym) var varSectionOuter = newNimNode(nnkVarSection, handler).add( newIdentDefs(valuesSym, valuesTuple)) body = newStmtList(varSectionInner, handler[6]) turnSym = ident"turn" handleSym = ident"handle" handlerSym = genSym(nskProc, "publish") quote do: proc `handlerSym`(_: Entity; `turnSym`: var Turn; bindings: Assertion; `handleSym`: Handle) = `varSectionOuter` if fromPreserve(`valuesSym`, bindings): `body` proc wrapMessageHandler(handler: NimNode): NimNode = handler.expectKind nnkDo var innerProc = newNimNode(nnkProcDef) handler.copyChildrenTo innerProc innerProc[0] = genSym(nskProc, "message") var formalArgs = handler[3] valuesSym = genSym(nskVar, "values") valuesTuple = newNimNode(nnkTupleTy, handler) innerTuple = newNimNode(nnkVarTuple, handler) varSectionInner = newNimNode(nnkVarSection, handler).add(innerTuple) for i, arg in formalArgs: if i > 0: arg.expectKind nnkIdentDefs if arg[1].kind == nnkEmpty: error("type required for capture", arg) var def = newNimNode(nnkIdentDefs, arg) arg.copyChildrenTo def valuesTuple.add(def) innerTuple.add(arg[0]) innerTuple.add(newEmptyNode(), valuesSym) var varSectionOuter = newNimNode(nnkVarSection, handler).add( newIdentDefs(valuesSym, valuesTuple)) body = newStmtList(varSectionInner, handler[6]) turnSym = ident"turn" handlerSym = genSym(nskProc, "message") quote do: proc `handlerSym`(_: Entity; `turnSym`: var Turn; bindings: Assertion) = `varSectionOuter` if fromPreserve(`valuesSym`, bindings): `body` macro onPublish*(turn: Turn; ds: Ref; pattern: Pattern; doHandler: untyped) = let handlerProc = wrapPublishHandler(doHandler) handlerSym = handlerProc[0] result = quote do: `handlerProc` discard observe(`turn`, `ds`, `pattern`, newEntity(publish = `handlerSym`)) macro onMessage*(turn: Turn; ds: Ref; pattern: Pattern; doHandler: untyped) = let handlerProc = wrapMessageHandler(doHandler) handlerSym = handlerProc[0] result = quote do: `handlerProc` discard observe(`turn`, `ds`, `pattern`, newEntity(message = `handlerSym`))