Quick actions

cmd+k|ctrl+k

Navigation

Languages

DSL example

Snippet info

Language

Nim

Visibility

unlisted

Author

legacy-anonymous

Created

2018-10-05T06:43:17Z

Updated

2018-10-05T06:43:17Z

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()
INFO