This Month with Nim: June 2021
01 July 2021 The Nim Community
CPS
Authors: @Leorize, @disruptek, @Zevv and @saem
The project brings Continuation-Passing Style to Nim. CPS is an elegant approach to writing control-flow which is rooted in musty programming language theory. Now Nim’s macro system allows you the advantages of CPS without having to introduce any syntax.
A short demonstration of implementing goto
in Nim with CPS:
import std/tables
import cps
type
Count = ref object of Continuation
labels: Table[string, Continuation.fn]
proc label(c: Count; name: string): Count {.cpsMagic.} =
c.labels[name] = c.fn
result = c
proc goto(c: Count; name: string): Count {.cpsMagic.} =
c.fn = c.labels[name]
result = c
proc count(upto: int): int {.cps: Count.} =
## deploy the Count to make counting fun again;
## this continuation returns the number of trips through the goto
result = 0
label: "again!"
inc result
echo result, "!"
echo result, " loops, ah ah ah!"
if result < upto:
goto "again!"
echo "whew!"
const many = 1_000
assert many == count(many) # This might take awhile to run
If you are interested, see Zevv’s excellent write up on CPS. Come join us at #cps:matrix.org or #cps on libera.chat.
Whois.nim
Author: @Thisago
The Whois.nim is a simple whois client. With cache!
import whois
echo whois("duckduckgo.com")
# or
var domain = "metager.org".toDomain # convert to a `Domain` instance
domain.update() # Get data from API
echo domain
libFuzzer
Author: @planetis-m
Thin interface for LLVM/Clang libFuzzer, an in-process, coverage-guided, evolutionary fuzzing engine. Fuzzing is an automated bug finding technique, where randomized inputs are fed to a target program in order to get it to crash. With fuzzing, you can increase your test coverage to find edge cases and trigger bugs more effectively.
proc fuzzMe(data: openarray[byte]): bool =
result = data.len >= 3 and
data[0].char == 'F' and
data[1].char == 'U' and
data[2].char == 'Z' and
data[3].char == 'Z' # :‑<
proc initialize(): cint {.exportc: "LLVMFuzzerInitialize".} =
{.emit: "N_CDECL(void, NimMain)(void); NimMain();".}
proc testOneInput(data: ptr UncheckedArray[byte], len: int): cint {.
exportc: "LLVMFuzzerTestOneInput", raises: [].} =
result = 0
discard fuzzMe(data.toOpenArray(0, len-1))
It takes a split second for libFuzzer to perform ~40.000 runs. Behind the scenes it uses value profiling to guide the fuzzer past these comparisons much more efficiently than simply hoping to stumble on the exact sequence of bytes by chance.
Dik
Author: Juan Carlos
Dik is a dictionary implemented as { array[char]: Option[T] }
- Cute pet.
- Destructors.
- Resize in-place.
- Sorted and hashed.
- Same size as Table.
- Dollar and
pretty
. toSeq
andtoDik
.- Tests for everything.
- Documentation with examples.
- Same size and speed as
Table
. - 1 file, 300 lines, 0 dependencies.
newDikOfCap
for custom capacity.- Keys are stored as
array
ofchar
. - Values are stored as
seq
ofOption[T]
. - Can be used like
seq
or likeTable
. len
for lenght andcap
for capacity.- Get items by
string
oropenArray[char]
. - Get items by index or
BackwardsIndex
orSlice[int]
. - Iterators, including
enumerated
yields(index, key, value)
. - From stdlib uses only
options
forOption[T]
,hashes
forhash(T)
.
import std/options ## For Option[T] ops.
import std/json ## For heterogeneous values.
import dik
var myDik = {"key0": %*{"foo": 42, "bar": 3.14}, "key1": %*["baz", true]}.toDik
doAssert myDik.len == 2 # Length
doAssert myDik.cap == 2 # Capacity
doAssert sizeOf(myDik) == 32
doAssert myDik[1].get == %*["baz", true] # Get by index
doAssert myDik[^1].get == %*["baz", true] # Get by BackwardsIndex
doAssert myDik["key1"].get == %*["baz", true] # Get by key
doAssert myDik[1..1][0].get == %*["baz", true] # Get by Slice[int]
echo myDik.pretty # Pretty-print
doAssert myDik.toSeq is seq[Option[JsonNode]] # Dik to seq
doAssert "key0" in myDik # contains(key)
myDik.del "key1" # Delete an item
for (index, key, value) in myDik.enumerated: # Iterators
doAssert index == 0
doAssert key == "key0"
doAssert value.get == %*{"foo": 42, "bar": 3.14}
# Can store the lack of a value, without using "nil".
myDik["key1"] = none JsonNode
doAssert not(myDik[1].isSome)
doAssert myDik[1] == myDik["key1"]
clear myDik
doAssert myDik.len == 0
doAssert $myDik == "{:}"
Want to see your project here next month?
Follow this to add your project to the next month’s blog post.