summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--changelog.md2
-rw-r--r--compiler/semstmts.nim6
-rw-r--r--doc/manual_experimental.rst24
-rw-r--r--tests/macros/tcasestmtmacro.nim35
4 files changed, 51 insertions, 16 deletions
diff --git a/changelog.md b/changelog.md
index 8fadd0b4c..6228cc4b3 100644
--- a/changelog.md
+++ b/changelog.md
@@ -139,6 +139,8 @@ with other backends. see #9125. Use `-d:nimLegacyJsRound` for previous behavior.
 - `os.copyFile` is now 2.5x faster on OSX, by using `copyfile` from `copyfile.h`;
   use `-d:nimLegacyCopyFile` for OSX < 10.5.
 
+- The required name of case statement macros for the experimental
+  `caseStmtMacros` feature has changed from `match` to `` `case` ``.
 
 ## Compiler changes
 
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index c7aabea23..2c4672dfc 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -861,10 +861,10 @@ proc handleForLoopMacro(c: PContext; n: PNode; flags: TExprFlags): PNode =
 
 proc handleCaseStmtMacro(c: PContext; n: PNode; flags: TExprFlags): PNode =
   # n[0] has been sem'checked and has a type. We use this to resolve
-  # 'match(n[0])' but then we pass 'n' to the 'match' macro. This seems to
+  # '`case`(n[0])' but then we pass 'n' to the `case` macro. This seems to
   # be the best solution.
   var toResolve = newNodeI(nkCall, n.info)
-  toResolve.add newIdentNode(getIdent(c.cache, "match"), n.info)
+  toResolve.add newIdentNode(getIdent(c.cache, "case"), n.info)
   toResolve.add n[0]
 
   var errors: CandidateErrors
@@ -875,7 +875,7 @@ proc handleCaseStmtMacro(c: PContext; n: PNode; flags: TExprFlags): PNode =
     markUsed(c, n[0].info, match)
     onUse(n[0].info, match)
 
-    # but pass 'n' to the 'match' macro, not 'n[0]':
+    # but pass 'n' to the `case` macro, not 'n[0]':
     r.call[1] = n
     let toExpand = semResolvedCall(c, r, r.call, {})
     case match.kind
diff --git a/doc/manual_experimental.rst b/doc/manual_experimental.rst
index 02602d98d..63108c896 100644
--- a/doc/manual_experimental.rst
+++ b/doc/manual_experimental.rst
@@ -947,11 +947,10 @@ the documentation of `spawn <#parallel-amp-spawn-spawn-statement>`_ for details.
 Case statement macros
 =====================
 
-A macro that needs to be called `match`:idx: can be used to rewrite
-``case`` statements in order to implement `pattern matching`:idx: for
-certain types. The following example implements a simplistic form of
-pattern matching for tuples, leveraging the existing equality operator
-for tuples (as provided in ``system.==``):
+Macros named `case` can rewrite `case` statements for certain types in order to
+implement `pattern matching`:idx:. The following example implements a
+simplistic form of pattern matching for tuples, leveraging the existing
+equality operator for tuples (as provided in ``system.==``):
 
 .. code-block:: nim
     :test: "nim c $1"
@@ -960,7 +959,7 @@ for tuples (as provided in ``system.==``):
 
   import macros
 
-  macro match(n: tuple): untyped =
+  macro `case`(n: tuple): untyped =
     result = newTree(nnkIfStmt)
     let selector = n[0]
     for i in 1 ..< n.len:
@@ -973,8 +972,7 @@ for tuples (as provided in ``system.==``):
           let cond = newCall("==", selector, it[j])
           result.add newTree(nnkElifBranch, cond, it[^1])
       else:
-        error "'match' cannot handle this node", it
-    echo repr result
+        error "custom 'case' for tuple cannot handle this node", it
 
   case ("foo", 78)
   of ("foo", 78): echo "yes"
@@ -985,12 +983,12 @@ for tuples (as provided in ``system.==``):
 Currently case statement macros must be enabled explicitly
 via ``{.experimental: "caseStmtMacros".}``.
 
-``match`` macros are subject to overload resolution. First the
-``case``'s selector expression is used to determine which ``match``
-macro to call. To this macro is then passed the complete ``case``
-statement body and the macro is evaluated.
+`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
+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.
 
diff --git a/tests/macros/tcasestmtmacro.nim b/tests/macros/tcasestmtmacro.nim
new file mode 100644
index 000000000..26519f637
--- /dev/null
+++ b/tests/macros/tcasestmtmacro.nim
@@ -0,0 +1,35 @@
+discard """
+  output: '''
+yes
+'''
+"""
+
+{.experimental: "caseStmtMacros".}
+
+import macros
+
+macro `case`(n: tuple): untyped =
+  result = newTree(nnkIfStmt)
+  let selector = n[0]
+  for i in 1 ..< n.len:
+    let it = n[i]
+    case it.kind
+    of nnkElse, nnkElifBranch, nnkElifExpr, nnkElseExpr:
+      result.add it
+    of nnkOfBranch:
+      for j in 0..it.len-2:
+        let cond = newCall("==", selector, it[j])
+        result.add newTree(nnkElifBranch, cond, it[^1])
+    else:
+      error "custom 'case' for tuple cannot handle this node", it
+
+var correct = false
+
+case ("foo", 78)
+of ("foo", 78):
+  correct = true
+  echo "yes"
+of ("bar", 88): echo "no"
+else: discard
+
+doAssert correct