rename case statement macro from match to case (#16923)

* rename case statement macro from match to `case`

* fix test
This commit is contained in:
hlaaftana 2021-02-08 21:35:06 +03:00 • committed by GitHub
commit 6a7baff97d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 51 additions and 16 deletions

View file

@ -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`; - `os.copyFile` is now 2.5x faster on OSX, by using `copyfile` from `copyfile.h`;
use `-d:nimLegacyCopyFile` for OSX < 10.5. 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 ## Compiler changes

View file

@ -861,10 +861,10 @@ proc handleForLoopMacro(c: PContext; n: PNode; flags: TExprFlags): PNode =
proc handleCaseStmtMacro(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 # 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. # be the best solution.
var toResolve = newNodeI(nkCall, n.info) 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] toResolve.add n[0]
var errors: CandidateErrors var errors: CandidateErrors
@ -875,7 +875,7 @@ proc handleCaseStmtMacro(c: PContext; n: PNode; flags: TExprFlags): PNode =
markUsed(c, n[0].info, match) markUsed(c, n[0].info, match)
onUse(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 r.call[1] = n
let toExpand = semResolvedCall(c, r, r.call, {}) let toExpand = semResolvedCall(c, r, r.call, {})
case match.kind case match.kind

View file

@ -947,11 +947,10 @@ the documentation of `spawn <#parallel-amp-spawn-spawn-statement>`_ for details.
Case statement macros Case statement macros
===================== =====================
A macro that needs to be called `match`:idx: can be used to rewrite Macros named `case` can rewrite `case` statements for certain types in order to
``case`` statements in order to implement `pattern matching`:idx: for implement `pattern matching`:idx:. The following example implements a
certain types. The following example implements a simplistic form of simplistic form of pattern matching for tuples, leveraging the existing
pattern matching for tuples, leveraging the existing equality operator equality operator for tuples (as provided in ``system.==``):
for tuples (as provided in ``system.==``):
.. code-block:: nim .. code-block:: nim
:test: "nim c $1" :test: "nim c $1"
@ -960,7 +959,7 @@ for tuples (as provided in ``system.==``):
import macros import macros
macro match(n: tuple): untyped = macro `case`(n: tuple): untyped =
result = newTree(nnkIfStmt) result = newTree(nnkIfStmt)
let selector = n[0] let selector = n[0]
for i in 1 ..< n.len: for i in 1 ..< n.len:
@ -973,8 +972,7 @@ for tuples (as provided in ``system.==``):
let cond = newCall("==", selector, it[j]) let cond = newCall("==", selector, it[j])
result.add newTree(nnkElifBranch, cond, it[^1]) result.add newTree(nnkElifBranch, cond, it[^1])
else: else:
error "'match' cannot handle this node", it error "custom 'case' for tuple cannot handle this node", it
echo repr result
case ("foo", 78) case ("foo", 78)
of ("foo", 78): echo "yes" of ("foo", 78): echo "yes"
@ -985,12 +983,12 @@ for tuples (as provided in ``system.==``):
Currently case statement macros must be enabled explicitly Currently case statement macros must be enabled explicitly
via ``{.experimental: "caseStmtMacros".}``. via ``{.experimental: "caseStmtMacros".}``.
``match`` macros are subject to overload resolution. First the `case` macros are subject to overload resolution. The type of the
``case``'s selector expression is used to determine which ``match`` `case` statement's selector expression is matched against the type
macro to call. To this macro is then passed the complete ``case`` of the first argument of the `case` macro. Then the complete `case`
statement body and the macro is evaluated. 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 but only the statement's selector expression is used to determine which
macro to call. macro to call.

View file

@ -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