rename case statement macro from match to case (#16923)
* rename case statement macro from match to `case` * fix test
This commit is contained in:
parent
abac35e743
commit
6a7baff97d
4 changed files with 51 additions and 16 deletions
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
||||||
35
tests/macros/tcasestmtmacro.nim
Normal file
35
tests/macros/tcasestmtmacro.nim
Normal 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
|
||||||
Loading…
Add table
Add a link
Reference in a new issue