syndicate-nim/src/syndicate.nim

92 lines
3.1 KiB
Nim

# 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`))