better tester

This commit is contained in:
Araq 2014-01-17 08:47:51 +01:00
commit 383fbca27e
21 changed files with 39 additions and 31 deletions

23
tests/macros/tmacro1.nim Normal file
View file

@ -0,0 +1,23 @@
import macros
from uri import `/`
macro test*(a: stmt): stmt {.immediate.} =
var nodes: tuple[a, b: int]
nodes.a = 4
nodes[1] = 45
type
TTypeEx = object
x, y: int
case b: bool
of false: nil
of true: z: float
var t: TTypeEx
t.b = true
t.z = 4.5
test:
"hi"

28
tests/macros/tmacro2.nim Normal file
View file

@ -0,0 +1,28 @@
discard """
output: "ta-da Your value sir: 'HE!!!!o Wor!!d'"
"""
import macros, strutils
proc testBlock(): string {.compileTime.} =
block myBlock:
while true:
echo "inner block"
break myBlock
echo "outer block"
result = "ta-da"
macro mac(n: expr): expr =
let n = callsite()
expectKind(n, nnkCall)
expectLen(n, 2)
expectKind(n[1], nnkStrLit)
var s: string = n[1].strVal
s = s.replace("l", "!!")
result = newStrLitNode("Your value sir: '$#'" % [s])
const s = testBlock()
const t = mac("HEllo World")
echo s, " ", t

31
tests/macros/tmacro3.nim Normal file
View file

@ -0,0 +1,31 @@
discard """
output: ""
"""
import macros
type
TA = tuple[a: int]
PA = ref TA
macro test*(a: stmt): stmt {.immediate.} =
var val: PA
new(val)
val.a = 4
test:
"hi"
macro test2*(a: stmt): stmt {.immediate.} =
proc testproc(recurse: int) =
echo "Thats weird"
var o : PNimrodNode = nil
echo " no its not!"
o = newNimNode(nnkNone)
if recurse > 0:
testproc(recurse - 1)
testproc(5)
test2:
"hi"

19
tests/macros/tmacro4.nim Normal file
View file

@ -0,0 +1,19 @@
discard """
output: "after"
"""
import
macros, strutils
macro test_macro*(n: stmt): stmt {.immediate.} =
result = newNimNode(nnkStmtList)
var ass : PNimrodNode = newNimNode(nnkAsgn)
add(ass, newIdentNode("str"))
add(ass, newStrLitNode("after"))
add(result, ass)
when isMainModule:
var str: string = "before"
test_macro(str):
var i : integer = 123
echo str

59
tests/macros/tmacro5.nim Normal file
View file

@ -0,0 +1,59 @@
import macros,json
var decls{.compileTime.}: seq[PNimrodNode] = @[]
var impls{.compileTime.}: seq[PNimrodNode] = @[]
macro importImpl_forward(name, returns): stmt {.immediate.} =
result = newNimNode(nnkEmpty)
var func_name = newNimNode(nnkAccQuoted)
func_name.add newIdentNode("import")
func_name.add name
var res = newNimNode(nnkProcDef)
res.add newNimNode(nnkPostfix)
res[0].add newIdentNode("*")
res[0].add func_name
res.add newNimNode(nnkEmpty)
res.add newNimNode(nnkEmpty)
res.add newNimNode(nnkFormalParams)
res[3].add returns
var p1 = newNimNode(nnkIdentDefs)
p1.add newIdentNode("dat")
p1.add newIdentNOde("PJsonNode")
p1.add newNimNode(nnkEmpty)
res[3].add p1
var p2 = newNimNode(nnkIdentDefs)
p2.add newIdentNode("errors")
p2.add newNimNode(nnkVarTy)
p2.add newNimNode(nnkEmpty)
p2[1].add newNimNode(nnkBracketExpr)
p2[1][0].add newIdentNode("seq")
p2[1][0].add newIdentNode("string")
res[3].add p2
res.add newNimNode(nnkEmpty)
res.add newNimNode(nnkEmpty)
res.add newNimNode(nnkEmpty)
decls.add res
echo(repr(res))
macro importImpl(name, returns: expr, body: stmt): stmt {.immediate.} =
#var res = getAST(importImpl_forward(name, returns))
discard getAST(importImpl_forward(name, returns))
var res = copyNimTree(decls[decls.high])
res[6] = body
echo repr(res)
impls.add res
macro okayy:stmt =
result = newNimNode(nnkStmtList)
for node in decls: result.add node
for node in impls: result.add node
importimpl(Item, int):
echo 42
importImpl(Foo, int16):
echo 77
okayy

View file

@ -0,0 +1,8 @@
import macros
macro foo(x: stmt): stmt =
echo treerepr(callsite())
result = newNimNode(nnkStmtList)
proc zoo() {.foo.} = echo "hi"

View file

@ -0,0 +1,39 @@
discard """
file: "tmacrogenerics.nim"
msg: '''
instantiation 1 with int and float
instantiation 2 with float and string
instantiation 3 with string and string
counter: 3
'''
output: "int\nfloat\nint\nstring"
"""
import typetraits, macros
var counter {.compileTime.} = 0
macro makeBar(A, B: typedesc): typedesc =
inc counter
echo "instantiation ", counter, " with ", A.name, " and ", B.name
result = A
type
Bar[T, U] = makeBar(T, U)
var bb1: Bar[int, float]
var bb2: Bar[float, string]
var bb3: Bar[int, float]
var bb4: Bar[string, string]
proc match(a: int) = echo "int"
proc match(a: string) = echo "string"
proc match(a: float) = echo "float"
match(bb1)
match(bb2)
match(bb3)
match(bb4)
static:
echo "counter: ", counter

31
tests/macros/tmacros1.nim Normal file
View file

@ -0,0 +1,31 @@
discard """
output: "Got: 'nnkCall' hi"
"""
import
macros, strutils
macro outterMacro*(n: stmt): stmt {.immediate.} =
let n = callsite()
var j : string = "hi"
proc innerProc(i: int): string =
echo "Using arg ! " & n.repr
result = "Got: '" & $n.kind & "' " & $j
var callNode = n[0]
expectKind(n, TNimrodNodeKind.nnkCall)
if n.len != 3 or n[1].kind != TNimrodNodeKind.nnkIdent:
error("Macro " & callNode.repr &
" requires the ident passed as parameter (eg: " & callNode.repr &
"(the_name_you_want)): statements.")
result = newNimNode(TNimrodNodeKind.nnkStmtList)
var ass : PNimrodNode = newNimNode(nnkAsgn)
ass.add(newIdentNode(n[1].ident))
ass.add(newStrLitNode(innerProc(4)))
result.add(ass)
var str: string
outterMacro(str):
"hellow"
echo str

View file

@ -0,0 +1,26 @@
import macros
macro case_token(n: stmt): stmt {.immediate.} =
# creates a lexical analyzer from regular expressions
# ... (implementation is an exercise for the reader :-)
nil
case_token: # this colon tells the parser it is a macro statement
of r"[A-Za-z_]+[A-Za-z_0-9]*":
return tkIdentifier
of r"0-9+":
return tkInteger
of r"[\+\-\*\?]+":
return tkOperator
else:
return tkUnknown
case_token: inc i
#bug #488
macro foo: stmt =
var exp = newCall("whatwhat", newIntLitNode(1))
if compiles(getAst(exp)): return exp
else: echo "Does not compute!"
foo()

View file

@ -0,0 +1,12 @@
import macros, typetraits
macro checkType(ex, expected: expr): stmt {.immediate.} =
var t = ex.typ
assert t.name == expected.strVal
proc voidProc = echo "hello"
proc intProc(a, b): int = 10
checkType(voidProc(), "void")
checkType(intProc(10, 20.0), "int")
checkType(noproc(10, 20.0), "Error Type")

View file

@ -0,0 +1,13 @@
discard """
output: "bla"
disabled: true
"""
import macros
proc makeMacro: PNimrodNode =
result = nil
var p = makeMacro()
echo "bla"

16
tests/macros/tprintf.nim Normal file
View file

@ -0,0 +1,16 @@
discard """
file: "tprintf.nim"
output: "Andreas Rumpf"
"""
# Test a printf proc
proc printf(file: TFile, args: openarray[string]) =
var i = 0
while i < args.len:
write(file, args[i])
inc(i)
printf(stdout, ["Andreas ", "Rumpf\n"])
#OUT Andreas Rumpf

View file

@ -0,0 +1,26 @@
discard """
file: "tquotewords.nim"
output: "thisanexample"
"""
# Test an idea I recently had:
import macros
macro quoteWords(n: expr): expr {.immediate.} =
let n = callsite()
result = newNimNode(nnkBracket, n)
for i in 1..n.len-1:
expectKind(n[i], nnkIdent)
result.add(toStrLit(n[i]))
const
myWordList = quoteWords(this, an, example)
var s = ""
for w in items(myWordList):
s.add(w)
echo s #OUT thisanexample

View file

@ -0,0 +1,14 @@
discard """
file: "trecmacro.nim"
line: 8
errormsg: "recursive dependency: 'dump'"
"""
macro dump(n: stmt): stmt =
dump(n)
if kind(n) == nnkNone:
nil
else:
hint($kind(n))
for i in countUp(0, len(n)-1):
nil

View file

@ -0,0 +1,74 @@
discard """
file: "tstringinterp.nim"
output: "Hello Alice, 64 | Hello Bob, 10$"
"""
import macros, parseutils, strutils
proc concat(strings: varargs[string]): string =
result = newString(0)
for s in items(strings): result.add(s)
template ProcessInterpolations(e: expr) =
var s = e[1].strVal
for f in interpolatedFragments(s):
case f.kind
of ikStr: addString(f.value)
of ikDollar: addDollar()
of ikVar, ikExpr: addExpr(newCall("$", parseExpr(f.value)))
macro formatStyleInterpolation(e: expr): expr =
let e = callsite()
var
formatString = ""
arrayNode = newNimNode(nnkBracket)
idx = 1
proc addString(s: string) =
formatString.add(s)
proc addExpr(e: PNimrodNode) =
arrayNode.add(e)
formatString.add("$" & $(idx))
inc idx
proc addDollar() =
formatString.add("$$")
ProcessInterpolations(e)
result = parseExpr("\"x\" % [y]")
result[1].strVal = formatString
result[2] = arrayNode
macro concatStyleInterpolation(e: expr): expr =
let e = callsite()
var args: seq[PNimrodNode]
newSeq(args, 0)
proc addString(s: string) = args.add(newStrLitNode(s))
proc addExpr(e: PNimrodNode) = args.add(e)
proc addDollar() = args.add(newStrLitNode"$")
ProcessInterpolations(e)
result = newCall("concat", args)
###
proc sum(a, b, c: int): int =
return (a + b + c)
var
alice = "Alice"
bob = "Bob"
a = 10
b = 20
c = 34
var
s1 = concatStyleInterpolation"Hello ${alice}, ${sum(a, b, c)}"
s2 = formatStyleInterpolation"Hello ${bob}, ${sum(alice.len, bob.len, 2)}$$"
write(stdout, s1 & " | " & s2)

74
tests/macros/tvtable.nim Normal file
View file

@ -0,0 +1,74 @@
discard """
output: '''
OBJ 1 foo
10
OBJ 1 bar
OBJ 2 foo
5
OBJ 2 bar
'''
"""
type
# these are the signatures of the virtual procs for each type
fooProc[T] = proc (o: var T): int
barProc[T] = proc (o: var T)
# an untyped table to store the proc pointers
# it's also possible to use a strongly typed tuple here
VTable = array[0..1, pointer]
TBase = object {.inheritable.}
vtbl: ptr VTable
TUserObject1 = object of TBase
x: int
TUserObject2 = object of TBase
y: int
proc foo(o: var TUserObject1): int =
echo "OBJ 1 foo"
return 10
proc bar(o: var TUserObject1) =
echo "OBJ 1 bar"
proc foo(o: var TUserObject2): int =
echo "OBJ 2 foo"
return 5
proc bar(o: var TUserObject2) =
echo "OBJ 2 bar"
proc getVTable(T: typedesc): ptr VTable =
# pay attention to what's going on here
# this will initialize the vtable for each type at program start-up
#
# fooProc[T](foo) is a type coercion - it looks for a proc named foo
# matching the signature fooProc[T] (e.g. proc (o: var TUserObject1): int)
var vtbl {.global.} = [
cast[pointer](fooProc[T](foo)),
cast[pointer](barProc[T](bar))
]
return vtbl.addr
proc create(T: typedesc): T =
result.vtbl = getVTable(T)
proc baseFoo(o: var TBase): int =
return cast[fooProc[TBase]](o.vtbl[0]) (o)
proc baseBar(o: var TBase) =
cast[barProc[TBase]](o.vtbl[1]) (o)
var a = TUserObject1.create
var b = TUserObject2.create
echo a.baseFoo
a.baseBar
echo b.baseFoo
b.baseBar