import macros, tables
# === class defination ===
type
MessageListener = proc (msg: string): void
MessageType = enum
UserEnter, UserLeave, UserMsg
MessageDispather = object of RootObj
listeners : Table[MessageType, MessageListener]
func initMessageDispatcher(): MessageDispather = MessageDispather(
listeners: initTable[MessageType, MessageListener]()
)
func setOnMessageListener(self: var MessageDispather, msgType: MessageType, listener: MessageListener) =
self.listeners[msgType] = listener
func dispatch(self: MessageDispather, msgType: MessageType, msg: string) =
if self.listeners.hasKey(msgType):
self.listeners[msgType](msg)
func run(self: MessageDispather) =
self.dispatch(UserEnter, "7sDream")
self.dispatch(UserMsg, "hello, everyone")
self.dispatch(UserLeave, "7sDream")
# === shortcut macro ====
template listenerFunc(funcName, msgType: untyped): untyped =
proc funcName(msg: string) =
let msg {.inject.} = msg
template setListenerStmt(client, funcName, typeName: untyped): untyped =
client.setOnMessageListener(MessageType.typeName, funcName)
macro OnMessage(dispatcher, ls: untyped): untyped =
expectKind(dispatcher, nnkIdent)
expectKind(ls, nnkStmtList)
result = newStmtList()
for i in 0..<ls.len:
let listenerDef = ls[i]
expectKind(listenerDef, nnkCall)
let cls = listenerDef[0]
expectKind(cls, nnkIdent)
let doWhat = listenerDef[1]
expectKind(doWhat, nnkStmtList)
let
funcName = genSym(nskFunc, "on" & $cls)
listenerFuncDef = getAst(listenerFunc(funcName, cls))
listenerFuncStmts = listenerFuncDef[^1]
doWhat.copyChildrenTo(listenerFuncStmts)
result.add(listenerFuncDef)
let addListenerStmtDef = getAst(setListenerStmt(dispatcher, funcName, cls))
result.add(addListenerStmtDef)
# uncomment the line below to see what the macro generated
# result.repr.echo
# === Use example ===
var dispatcher = initMessageDispatcher()
OnMessage(dispatcher):
UserEnter:
echo "User enter: " & msg
UserMsg:
echo "Message: " & msg
UserLeave:
echo "User leave: " & msg
dispatcher.run()