Case statement macros

Macros named `` case `` can provide implementations of case statements for certain types. The following is an example of such an implementation for tuples, leveraging the existing equality operator for tuples (as provided in system.==):

  1. import std/macros
  2. macro `case`(n: tuple): untyped =
  3. result = newTree(nnkIfStmt)
  4. let selector = n[0]
  5. for i in 1 ..< n.len:
  6. let it = n[i]
  7. case it.kind
  8. of nnkElse, nnkElifBranch, nnkElifExpr, nnkElseExpr:
  9. result.add it
  10. of nnkOfBranch:
  11. for j in 0..it.len-2:
  12. let cond = newCall("==", selector, it[j])
  13. result.add newTree(nnkElifBranch, cond, it[^1])
  14. else:
  15. error "custom 'case' for tuple cannot handle this node", it
  16. case ("foo", 78)
  17. of ("foo", 78): echo "yes"
  18. of ("bar", 88): echo "no"
  19. else: discard

case macros are subject to overload resolution. The type of the case statement’s selector expression is matched against the type of the first argument of the case macro. Then the complete case statement is passed in place of the argument and the macro is evaluated.

In other words, the macro needs to transform the full case statement but only the statement’s selector expression is used to determine which macro to call.