Skip to content

Commit

Permalink
staticfor: compile-time loop unrolling (#232)
Browse files Browse the repository at this point in the history
* staticfor: compile-time loop unrolling

* better code, preserve line info

* one more line info

* license
  • Loading branch information
arnetheduck authored Sep 24, 2024
1 parent 68e8ae6 commit 41f48ef
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 0 deletions.
43 changes: 43 additions & 0 deletions stew/staticfor.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# stew
# Copyright (c) 2024 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
# http://opensource.org/licenses/MIT)
# at your option. This file may not be copied, modified, or distributed except
# according to those terms.

import std/macros

proc replaceNodes(ast: NimNode, what: NimNode, by: NimNode): NimNode =
# Replace "what" ident node by "by"
proc inspect(node: NimNode): NimNode =
case node.kind:
of {nnkIdent, nnkSym}:
if node.eqIdent(what):
by
else:
node
of nnkEmpty, nnkLiterals:
node
else:
let rTree = newNimNode(node.kind, lineInfoFrom = node)
for child in node:
rTree.add inspect(child)
rTree
inspect(ast)

macro staticFor*(idx: untyped{nkIdent}, slice: static Slice[int], body: untyped): untyped =
## Unrolled `for` loop over the given range:
##
## ```nim
## staticFor(i, 0..<2):
## echo default(array[i, byte])
## ```
result = newNimNode(nnkStmtList, lineInfoFrom = body)
for i in slice:
result.add nnkBlockStmt.newTree(
ident(":staticFor" & $idx & $i),
body.replaceNodes(idx, newLit i)
)
1 change: 1 addition & 0 deletions tests/all_tests.nim
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import
test_ptrops,
test_sequtils2,
test_sets,
test_staticfor,
test_strformat,
test_templateutils,
test_winacl
17 changes: 17 additions & 0 deletions tests/test_staticfor.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{.used.}

import unittest2, ../stew/staticfor

suite "staticfor":
test "basics":
var
a = 0
b = 0

for i in 0..10:
a += i

staticFor i, 0..10:
b += default(array[i, byte]).len

check: a == b

0 comments on commit 41f48ef

Please sign in to comment.