From 268af2602e0b81037e8873a0f16edf607d1da354 Mon Sep 17 00:00:00 2001 From: hlaaftana <10591326+hlaaftana@users.noreply.github.com> Date: Mon, 8 Feb 2021 21:35:06 +0300 Subject: [PATCH] rename case statement macro from match to `case` (#16923) * rename case statement macro from match to `case` * fix test --- changelog.md | 2 ++ compiler/semstmts.nim | 6 +++--- doc/manual_experimental.rst | 24 +++++++++++----------- tests/macros/tcasestmtmacro.nim | 35 +++++++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 16 deletions(-) create mode 100644 tests/macros/tcasestmtmacro.nim diff --git a/changelog.md b/changelog.md index 8fadd0b4c8578..6228cc4b36c45 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 c7aabea238160..2c4672dfcbfbc 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 02602d98dddd6..63108c8964da6 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 0000000000000..26519f637c70f --- /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