diff --git a/compiler/front/in_options.nim b/compiler/front/in_options.nim index 06977a03c4c..74333a5c46e 100644 --- a/compiler/front/in_options.nim +++ b/compiler/front/in_options.nim @@ -190,9 +190,6 @@ type destructor, notnil, dynamicBindSym, - forLoopMacros, ## not experimental anymore; remains here for backwards - ## compatibility - caseStmtMacros,## ditto vmopsDanger, strictFuncs, views, diff --git a/compiler/sem/semstmts.nim b/compiler/sem/semstmts.nim index 8b8b9c6727d..9a1031669dd 100644 --- a/compiler/sem/semstmts.nim +++ b/compiler/sem/semstmts.nim @@ -1614,83 +1614,8 @@ proc isTrivalStmtExpr(n: PNode): bool = return false result = true -proc handleStmtMacro(c: PContext; n, selector: PNode; magicType: string; - flags: TExprFlags): PNode = - if selector.kind in nkCallKinds: - # we transform - # n := for a, b, c in m(x, y, z): Y - # to - # m(n) - let maType = magicsys.getCompilerProc(c.graph, magicType) - if maType == nil: return - - let headSymbol = selector[0] - var o: TOverloadIter - var match: PSym = nil - var symx = initOverloadIter(o, c, headSymbol) - while symx != nil: - if symx.kind in {skTemplate, skMacro}: - if symx.typ.len == 2 and symx.typ[1] == maType.typ: - if match == nil: - match = symx - else: - localReport( - c.config, n.info, - reportSymbols(rsemAmbiguous, @[match, symx]).withIt do: - it.ast = selector - ) - elif symx.isError: - localReport(c.config, symx.ast) - - symx = nextOverloadIter(o, c, headSymbol) - - if match == nil: return - var callExpr = newNodeI(nkCall, n.info) - callExpr.add newSymNode(match) - callExpr.add n - case match.kind - of skMacro: result = semMacroExpr(c, callExpr, match, flags) - of skTemplate: result = semTemplateExpr(c, callExpr, match, flags) - else: result = nil - -proc handleForLoopMacro(c: PContext; n: PNode; flags: TExprFlags): PNode = - result = handleStmtMacro(c, n, n[^2], "ForLoopStmt", flags) - -proc handleCaseStmtMacro(c: PContext; n: PNode; flags: TExprFlags): PNode = - # n[0] has been sem'checked and has a type. We use this to resolve - # '`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, "case"), n.info) - toResolve.add n[0] - - var errors: seq[SemCallMismatch] - var r = resolveOverloads(c, toResolve, {skTemplate, skMacro}, {}, errors) - if r.state == csMatch: - var match = r.calleeSym - markUsed(c, n[0].info, match) - onUse(n[0].info, match) - - # but pass 'n' to the `case` macro, not 'n[0]': - r.call[1] = n - let toExpand = semResolvedCall(c, r, r.call, {}) - case match.kind - of skMacro: result = semMacroExpr(c, toExpand, match, flags) - of skTemplate: result = semTemplateExpr(c, toExpand, match, flags) - else: result = nil - else: - assert r.call.kind == nkError - result = r.call # xxx: hope this is nkError - # this would be the perfectly consistent solution with 'for loop macros', - # but it kinda sucks for pattern matching as the matcher is not attached to - # a type then: - when false: - result = handleStmtMacro(c, n, n[0], "CaseStmt") - proc semFor(c: PContext, n: PNode; flags: TExprFlags): PNode = checkMinSonsLen(n, 3, c.config) - result = handleForLoopMacro(c, n, flags) - if result != nil: return result openScope(c) result = n n[^2] = semExprNoDeref(c, n[^2], {efWantIterator}) @@ -1748,9 +1673,6 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags): PNode = else: popCaseContext(c) closeScope(c) - result = handleCaseStmtMacro(c, n, flags) - if result != nil: - return result result[0] = c.config.newError(n[0], reportSem rsemSelectorMustBeOfCertainTypes) return for i in 1..`_ This module implements color handling for Nim. -* `enumerate `_ - This module implements `enumerate` syntactic sugar based on Nim's macro system. - * `logging `_ This module implements a simple logger. diff --git a/doc/manual.rst b/doc/manual.rst index 6c68016e3a0..87c07d48ee3 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -4429,43 +4429,6 @@ parameters of an outer factory proc: for f in foo(): echo f -The call can be made more like an inline iterator with a for loop macro: - -.. code-block:: nim - import std/macros - macro toItr(x: ForLoopStmt): untyped = - let expr = x[0] - let call = x[1][1] # Get foo out of toItr(foo) - let body = x[2] - result = quote do: - block: - let itr = `call` - for `expr` in itr(): - `body` - - for f in toItr(mycount(1, 4)): # using early `proc mycount` - echo f - -Because of full backend function call aparatus involvment, closure iterator -invocation is typically higher cost than inline iterators. Adornment by -a macro wrapper at the call site like this is a possibly useful reminder. - -The factory `proc`, as an ordinary procedure, can be recursive. The -above macro allows such recursion to look much like a recursive iterator -would. For example: - -.. code-block:: nim - proc recCountDown(n: int): iterator(): int = - result = iterator(): int = - if n > 0: - yield n - for e in toItr(recCountDown(n - 1)): - yield e - - for i in toItr(recCountDown(6)): # Emits: 6 5 4 3 2 1 - echo i - - See also see `iterable <#overloading-resolution-iterable>`_ for passing iterators to templates and macros. Converters @@ -6018,110 +5981,6 @@ as arguments if called in statement form. echo num -For loop macro --------------- - -A macro that takes as its only input parameter an expression of the special -type `system.ForLoopStmt` can rewrite the entirety of a `for` loop: - -.. code-block:: nim - :test: "nim c $1" - - import std/macros - - macro example(loop: ForLoopStmt) = - result = newTree(nnkForStmt) # Create a new For loop. - result.add loop[^3] # This is "item". - result.add loop[^2][^1] # This is "[1, 2, 3]". - result.add newCall(bindSym"echo", loop[0]) - - for item in example([1, 2, 3]): discard - -Expands to: - -.. code-block:: nim - for item in items([1, 2, 3]): - echo item - -Another example: - -.. code-block:: nim - :test: "nim c $1" - - import std/macros - - macro enumerate(x: ForLoopStmt): untyped = - expectKind x, nnkForStmt - # check if the starting count is specified: - var countStart = if x[^2].len == 2: newLit(0) else: x[^2][1] - result = newStmtList() - # we strip off the first for loop variable and use it as an integer counter: - result.add newVarStmt(x[0], countStart) - var body = x[^1] - if body.kind != nnkStmtList: - body = newTree(nnkStmtList, body) - body.add newCall(bindSym"inc", x[0]) - var newFor = newTree(nnkForStmt) - for i in 1..x.len-3: - newFor.add x[i] - # transform enumerate(X) to 'X' - newFor.add x[^2][^1] - newFor.add body - result.add newFor - # now wrap the whole macro in a block to create a new scope - result = quote do: - block: `result` - - for a, b in enumerate(items([1, 2, 3])): - echo a, " ", b - - # without wrapping the macro in a block, we'd need to choose different - # names for `a` and `b` here to avoid redefinition errors - for a, b in enumerate(10, [1, 2, 3, 5]): - echo a, " ", b - - -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.==`): - -.. code-block:: nim - :test: "nim c $1" - import std/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 - - case ("foo", 78) - of ("foo", 78): echo "yes" - of ("bar", 88): echo "no" - 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. - Special Types ============= diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim index d1de0ea6725..6f8aa397785 100644 --- a/lib/pure/collections/lists.nim +++ b/lib/pure/collections/lists.nim @@ -268,7 +268,7 @@ iterator mitems*[T](L: var SomeLinkedRing[T]): var T = itemsRingImpl() iterator nodes*[T](L: SomeLinkedList[T]): SomeLinkedNode[T] = - ## Iterates over every node of `x`. Removing the current node from the + ## Iterates over every node of `L`. Removing the current node from the ## list during traversal is supported. ## ## **See also:** @@ -293,7 +293,7 @@ iterator nodes*[T](L: SomeLinkedList[T]): SomeLinkedNode[T] = it = nxt iterator nodes*[T](L: SomeLinkedRing[T]): SomeLinkedNode[T] = - ## Iterates over every node of `x`. Removing the current node from the + ## Iterates over every node of `L`. Removing the current node from the ## list during traversal is supported. ## ## **See also:** @@ -319,6 +319,22 @@ iterator nodes*[T](L: SomeLinkedRing[T]): SomeLinkedNode[T] = it = nxt if it == L.head: break +iterator enumerate*[T](L: SomeLinkedList[T]): (int, T) = + ## Iterates over every node of `L`, yielding `(count, value)` tuples with + ## count starting at `0`. + var i = 0 + for n in L.items: + yield (i, n) + inc i + +iterator enumerate*[T](L: SomeLinkedRing[T]): (int, T) = + ## Iterates over every node of `L`, yielding `(count, value)` tuples with + ## count starting at `0`. + var i = 0 + for n in L.items: + yield (i, n) + inc i + proc `$`*[T](L: SomeLinkedCollection[T]): string = ## Turns a list into its string representation for logging and printing. runnableExamples: @@ -390,7 +406,7 @@ proc prependMoved*[T: SomeLinkedList](a, b: var T) {.since: (1, 5, 1).} = ## * `prepend proc <#prepend,T,T>`_ ## for prepending a copy of a list runnableExamples: - import std/[sequtils, enumerate, sugar] + import std/[sequtils, sugar] var a = [4, 5].toSinglyLinkedList b = [1, 2, 3].toSinglyLinkedList @@ -515,7 +531,7 @@ proc addMoved*[T](a, b: var SinglyLinkedList[T]) {.since: (1, 5, 1).} = ## **See also:** ## * `add proc <#add,T,T>`_ for adding a copy of a list runnableExamples: - import std/[sequtils, enumerate, sugar] + import std/[sequtils, sugar] var a = [1, 2, 3].toSinglyLinkedList b = [4, 5].toSinglyLinkedList @@ -659,7 +675,7 @@ proc addMoved*[T](a, b: var DoublyLinkedList[T]) {.since: (1, 5, 1).} = ## * `add proc <#add,T,T>`_ ## for adding a copy of a list runnableExamples: - import std/[sequtils, enumerate, sugar] + import std/[sequtils, sugar] var a = [1, 2, 3].toDoublyLinkedList b = [4, 5].toDoublyLinkedList @@ -712,7 +728,7 @@ proc remove*[T](L: var SinglyLinkedList[T], n: SinglyLinkedNode[T]): bool {.disc ## Attempting to remove an element not contained in the list is a no-op. ## When the list is cyclic, the cycle is preserved after removal. runnableExamples: - import std/[sequtils, enumerate, sugar] + import std/[sequtils, sugar] var a = [0, 1, 2].toSinglyLinkedList let n = a.head.next assert n.value == 1 @@ -749,7 +765,7 @@ proc remove*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = ## otherwise the effects are undefined. ## When the list is cyclic, the cycle is preserved after removal. runnableExamples: - import std/[sequtils, enumerate, sugar] + import std/[sequtils, sugar] var a = [0, 1, 2].toSinglyLinkedList let n = a.head.next assert n.value == 1 diff --git a/lib/pure/options.nim b/lib/pure/options.nim index 850bfa555d4..2ba6709b2d5 100644 --- a/lib/pure/options.nim +++ b/lib/pure/options.nim @@ -42,29 +42,6 @@ raises `UnpackDefect` if there is no value. Note that `UnpackDefect` inherits from `system.Defect` and should therefore never be caught. Instead, rely on checking if the option contains a value with the `isSome <#isSome,Option[T]>`_ and `isNone <#isNone,Option[T]>`_ procs. - - -Pattern matching -================ - -.. note:: This requires the [fusion](https://github.com/nim-lang/fusion) package. - -[fusion/matching](https://nim-lang.github.io/fusion/src/fusion/matching.html) -supports pattern matching on `Option`s, with the `Some()` and -`None()` patterns. - -.. code-block:: nim - {.experimental: "caseStmtMacros".} - - import fusion/matching - - case some(42) - of Some(@a): - assert a == 42 - of None(): - assert false - - assertMatch(some(some(none(int))), Some(Some(None()))) ]## # xxx pending https://github.com/timotheecour/Nim/issues/376 use `runnableExamples` and `whichModule` diff --git a/lib/std/enumerate.nim b/lib/std/enumerate.nim deleted file mode 100644 index a8f0e1ba7f8..00000000000 --- a/lib/std/enumerate.nim +++ /dev/null @@ -1,70 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2020 Nim contributors -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module implements `enumerate` syntactic sugar based on Nim's -## macro system. - -import std/private/since -import macros - - -macro enumerate*(x: ForLoopStmt): untyped {.since: (1, 3).} = - ## Enumerating iterator for collections. - ## - ## It yields `(count, value)` tuples (which must be immediately unpacked). - ## The default starting count `0` can be manually overridden if needed. - runnableExamples: - let a = [10, 20, 30] - var b: seq[(int, int)] - for i, x in enumerate(a): - b.add((i, x)) - assert b == @[(0, 10), (1, 20), (2, 30)] - - let c = "abcd" - var d: seq[(int, char)] - for (i, x) in enumerate(97, c): - d.add((i, x)) - assert d == @[(97, 'a'), (98, 'b'), (99, 'c'), (100, 'd')] - - template genCounter(x): untyped = - # We strip off the first for loop variable and use it as an integer counter. - # We must immediately decrement it by one, because it gets incremented before - # the loop body - to be able to use the final expression in other macros. - newVarStmt(x, infix(countStart, "-", newLit(1))) - - template genInc(x): untyped = - newCall(bindSym"inc", x) - - expectKind x, nnkForStmt - # check if the starting count is specified: - var countStart = if x[^2].len == 2: newLit(0) else: x[^2][1] - result = newStmtList() - var body = x[^1] - if body.kind != nnkStmtList: - body = newTree(nnkStmtList, body) - var newFor = newTree(nnkForStmt) - if x.len == 3: # single iteration variable - if x[0].kind == nnkVarTuple: # for (x, y, ...) in iter - result.add genCounter(x[0][0]) - body.insert(0, genInc(x[0][0])) - for i in 1 .. x[0].len-2: - newFor.add x[0][i] - else: - error("Missing second for loop variable") # for x in iter - else: # for x, y, ... in iter - result.add genCounter(x[0]) - body.insert(0, genInc(x[0])) - for i in 1 .. x.len-3: - newFor.add x[i] - # transform enumerate(X) to 'X' - newFor.add x[^2][^1] - newFor.add body - result.add newFor - # now wrap the whole macro in a block to create a new scope - result = newBlockStmt(result) diff --git a/lib/system.nim b/lib/system.nim index fd9ada76617..cc8e67c9ea0 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -3102,11 +3102,6 @@ proc toOpenArrayByte*(x: openArray[char]; first, last: int): openArray[byte] {. proc toOpenArrayByte*(x: seq[char]; first, last: int): openArray[byte] {. magic: "Slice".} -type - ForLoopStmt* {.compilerproc.} = object ## \ - ## A special type that marks a macro as a `for-loop macro`:idx:. - ## See `"For Loop Macro" `_. - when defined(genode): var componentConstructHook*: proc (env: GenodeEnv) {.nimcall.} ## Hook into the Genode component bootstrap process. diff --git a/tests/effects/tstrict_funcs_imports.nim b/tests/effects/tstrict_funcs_imports.nim index 7e42733fedf..5a44a1a1b77 100644 --- a/tests/effects/tstrict_funcs_imports.nim +++ b/tests/effects/tstrict_funcs_imports.nim @@ -134,7 +134,6 @@ import std/[ compilesettings, editdistance, effecttraits, - enumerate, enumutils, exitprocs, isolation, diff --git a/tests/js/tstdlib_imports.nim b/tests/js/tstdlib_imports.nim index 8633c48789b..f2f3ca6bd56 100644 --- a/tests/js/tstdlib_imports.nim +++ b/tests/js/tstdlib_imports.nim @@ -63,7 +63,7 @@ import std/[ # fails due to copyMem/endians import: sha1 # Miscellaneous: - colors, logging, sugar, unittest, varints, enumerate, with, + colors, logging, sugar, unittest, varints, with, # fails due to FFI: browsers # works but uses FFI: segfaults diff --git a/tests/macros/tcasestmtmacro.nim b/tests/macros/tcasestmtmacro.nim deleted file mode 100644 index 32019a92a6c..00000000000 --- a/tests/macros/tcasestmtmacro.nim +++ /dev/null @@ -1,33 +0,0 @@ -discard """ - output: ''' -yes -''' -""" - -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 diff --git a/tests/macros/tforloop_macro1.nim b/tests/macros/tforloop_macro1.nim deleted file mode 100644 index a8f45c7ac44..00000000000 --- a/tests/macros/tforloop_macro1.nim +++ /dev/null @@ -1,44 +0,0 @@ -discard """ - output: '''0 1 -1 2 -2 3 -0 1 -1 2 -2 3 -0 1 -1 2 -2 3 -3 5''' -""" - -import macros - -macro mymacro(): untyped = - result = newLit([1, 2, 3]) - -for a, b in mymacro(): - echo a, " ", b - -macro enumerate(x: ForLoopStmt): untyped = - expectKind x, nnkForStmt - # we strip off the first for loop variable and use - # it as an integer counter: - result = newStmtList() - result.add newVarStmt(x[0], newLit(0)) - var body = x[^1] - if body.kind != nnkStmtList: - body = newTree(nnkStmtList, body) - body.add newCall(bindSym"inc", x[0]) - var newFor = newTree(nnkForStmt) - for i in 1..x.len-3: - newFor.add x[i] - # transform enumerate(X) to 'X' - newFor.add x[^2][1] - newFor.add body - result.add newFor - -for a, b in enumerate(items([1, 2, 3])): - echo a, " ", b - -for a2, b2 in enumerate([1, 2, 3, 5]): - echo a2, " ", b2 diff --git a/tests/pragmas/mpushexperimental.nim b/tests/pragmas/mpushexperimental.nim deleted file mode 100644 index 569861c1d9c..00000000000 --- a/tests/pragmas/mpushexperimental.nim +++ /dev/null @@ -1,30 +0,0 @@ - -import macros - -macro enumerate(x: ForLoopStmt): untyped = - expectKind x, nnkForStmt - # we strip off the first for loop variable and use - # it as an integer counter: - result = newStmtList() - result.add newVarStmt(x[0], newLit(0)) - var body = x[^1] - if body.kind != nnkStmtList: - body = newTree(nnkStmtList, body) - body.add newCall(bindSym"inc", x[0]) - var newFor = newTree(nnkForStmt) - for i in 1..x.len-3: - newFor.add x[i] - # transform enumerate(X) to 'X' - newFor.add x[^2][1] - newFor.add body - result.add newFor - -proc main*[T](x: T) = - {.push experimental: "forLoopMacros".} - - for a, b in enumerate(items([1, 2, 3])): - echo a, " ", b - - for a2, b2 in enumerate([1, 2, 3, 5]): - echo a2, " ", b2 - {.pop.} diff --git a/tests/pragmas/tpushexperimental.nim b/tests/pragmas/tpushexperimental.nim deleted file mode 100644 index 301419f607d..00000000000 --- a/tests/pragmas/tpushexperimental.nim +++ /dev/null @@ -1,13 +0,0 @@ -discard """ - output: '''0 1 -1 2 -2 3 -0 1 -1 2 -2 3 -3 5''' -""" - -import mpushexperimental - -main(12) diff --git a/tests/stdlib/tenumerate.nim b/tests/stdlib/tenumerate.nim deleted file mode 100644 index 7a1c2d10a1c..00000000000 --- a/tests/stdlib/tenumerate.nim +++ /dev/null @@ -1,19 +0,0 @@ -import std/enumerate - -let a = @[1, 3, 5, 7] - -block: - var res: seq[(int, int)] - for i, x in enumerate(a): - res.add (i, x) - doAssert res == @[(0, 1), (1, 3), (2, 5), (3, 7)] -block: - var res: seq[(int, int)] - for (i, x) in enumerate(a.items): - res.add (i, x) - doAssert res == @[(0, 1), (1, 3), (2, 5), (3, 7)] -block: - var res: seq[(int, int)] - for i, x in enumerate(3, a): - res.add (i, x) - doAssert res == @[(3, 1), (4, 3), (5, 5), (6, 7)] diff --git a/tests/stylecheck/tstyle_imports.nim b/tests/stylecheck/tstyle_imports.nim index b0242a159b9..17fe9a9fd71 100644 --- a/tests/stylecheck/tstyle_imports.nim +++ b/tests/stylecheck/tstyle_imports.nim @@ -140,7 +140,6 @@ import std/[ compilesettings, editdistance, effecttraits, - enumerate, enumutils, exitprocs, isolation, diff --git a/tests/test_nimscript.nims b/tests/test_nimscript.nims index ffb35e074ad..072606da57d 100644 --- a/tests/test_nimscript.nims +++ b/tests/test_nimscript.nims @@ -65,7 +65,7 @@ import std/[ # fails due to copyMem/endians import: sha1 # Miscellaneous: - colors, sugar, varints, enumerate, with, + colors, sugar, varints, with, # fails due to FFI: browsers, segfaults # fails due to times import/methods: logging # fails due to methods: unittest