Merge branch 'devel' into jpoirier-realtimeGCTest

This commit is contained in:
Simon Hafner
2015-05-13 12:06:05 -05:00
250 changed files with 10952 additions and 8848 deletions

View File

@@ -30,7 +30,7 @@ proc bar: int =
# local overrides that are active only
# in this proc
onFailedAssert(msg): echo "WARNING: " & msg
assert(false, "first assertion from bar")
onFailedAssert(msg):

View File

@@ -0,0 +1,10 @@
type
Concrete* = object
a*, b*: string
rc*: int # refcount
proc `=`(d: var Concrete; src: Concrete) =
shallowCopy(d.a, src.a)
shallowCopy(d.b, src.b)
dec d.rc
d.rc = src.rc + 1

View File

@@ -0,0 +1,75 @@
discard """
output: '''Concrete '='
Concrete '='
Concrete '='
Concrete '='
Concrete '='
GenericT[T] '=' int
GenericT[T] '=' float
GenericT[T] '=' float
GenericT[T] '=' float
GenericT[T] '=' string
GenericT[T] '=' int8
GenericT[T] '=' bool
GenericT[T] '=' bool
GenericT[T] '=' bool
GenericT[T] '=' bool'''
"""
import typetraits
type
Concrete = object
a, b: string
proc `=`(d: var Concrete; src: Concrete) =
shallowCopy(d.a, src.a)
shallowCopy(d.b, src.b)
echo "Concrete '='"
var x, y: array[0..2, Concrete]
var cA, cB: Concrete
var cATup, cBTup: tuple[x: int, ha: Concrete]
x = y
cA = cB
cATup = cBTup
type
GenericT[T] = object
a, b: T
proc `=`[T](d: var GenericT[T]; src: GenericT[T]) =
shallowCopy(d.a, src.a)
shallowCopy(d.b, src.b)
echo "GenericT[T] '=' ", type(T).name
var ag: GenericT[int]
var bg: GenericT[int]
ag = bg
var xg, yg: array[0..2, GenericT[float]]
var cAg, cBg: GenericT[string]
var cATupg, cBTupg: tuple[x: int, ha: GenericT[int8]]
xg = yg
cAg = cBg
cATupg = cBTupg
var caSeqg, cbSeqg: seq[GenericT[bool]]
newSeq(cbSeqg, 4)
caSeqg = cbSeqg
when false:
type
Foo = object
case b: bool
of false: xx: GenericT[int]
of true: yy: bool
var
a, b: Foo
a = b

View File

@@ -0,0 +1,22 @@
discard """
output: '''i value 88
2aa'''
"""
import moverload_asgn2
proc passAround(i: int): Concrete =
echo "i value ", i
result = Concrete(a: "aa", b: "bb", rc: 0)
proc main =
let
i = 88
v = passAround(i)
z = v.a
var
x: Concrete
x = v
echo x.rc, z # 2aa
main()

View File

@@ -82,6 +82,15 @@ proc test3(): Future[int] {.async.} =
result = 2
return
proc test4(): Future[int] {.async.} =
try:
discard await foo()
raise newException(ValueError, "Test4")
except OSError:
result = 1
except:
result = 2
var x = test()
assert x.read
@@ -90,3 +99,6 @@ assert x.read
var y = test3()
assert y.read == 2
y = test4()
assert y.read == 2

View File

@@ -0,0 +1,16 @@
discard """
file: "tasynctry2.nim"
errormsg: "\'yield\' cannot be used within \'try\' in a non-inlined iterator"
line: 15
"""
import asyncdispatch
proc foo(): Future[bool] {.async.} = discard
proc test5(): Future[int] {.async.} =
try:
discard await foo()
raise newException(ValueError, "Test5")
except:
discard await foo()
result = 0

View File

@@ -1,17 +1,17 @@
discard """
line: 18
errormsg: "type mismatch: got (proc (TScgi) | proc (AsyncSocket, StringTableRef, string)"
errormsg: "type mismatch: got (proc (s: TScgi) | proc (client: AsyncSocket, headers: StringTableRef, input: string){.gcsafe, locks: 0.}"
"""
#bug #442
import scgi, sockets, asyncio, strtabs
proc handleSCGIRequest[TScgi: ScgiState | AsyncScgiState](s: TScgi) =
discard
proc handleSCGIRequest(client: AsyncSocket, headers: StringTableRef,
proc handleSCGIRequest(client: AsyncSocket, headers: StringTableRef,
input: string) =
discard
proc test(handle: proc (client: AsyncSocket, headers: StringTableRef,
proc test(handle: proc (client: AsyncSocket, headers: StringTableRef,
input: string), b: int) =
discard

View File

@@ -0,0 +1,15 @@
discard """
output: '''true
true'''
"""
# bug #2489
let a = [1]
let b = [1]
echo a == b
# bug #2498
var x: array[0, int]
var y: array[0, int]
echo x == y

View File

@@ -0,0 +1,20 @@
# bug #2551
type Tup = tuple
A, a: int
type Obj = object
A, a: int
var x: Tup # This works.
var y: Obj # This doesn't.
# bug #2212
proc f() =
let
p = 1.0
P = 0.25 + 0.5
f()

View File

@@ -1,6 +1,6 @@
discard """
line: 12
errormsg: "type mismatch: got (proc (int){.closure, gcsafe, locks: 0.})"
errormsg: "type mismatch: got (proc (x: int){.closure, gcsafe, locks: 0.})"
"""
proc ugh[T](x: T) {.closure.} =

View File

@@ -0,0 +1,19 @@
discard """
output: "And we get here"
"""
# bug #2625
const s_len = 32
import tables
var substr_counts: CountTable[string] = initCountTable[string]()
var my_string = "Hello, this is sadly broken for strings over 64 characters. Note that it *does* appear to work for short strings."
for i in 0..(my_string.len - s_len):
let s = my_string[i..i+s_len-1]
substr_counts[s] = 1
# substr_counts[s] = substr_counts[s] + 1 # Also breaks, + 2 as well, etc.
# substr_counts.inc(s) # This works
#echo "Iteration ", i
echo "And we get here"

View File

@@ -1,17 +1,37 @@
discard """
output: '''true
true'''
"""
import sets
var
a = initSet[int]()
b = initSet[int]()
c = initSet[string]()
for i in 0..5: a.incl(i)
for i in 1..6: b.incl(i)
for i in 0..5: c.incl($i)
block setEquality:
var
a = initSet[int]()
b = initSet[int]()
c = initSet[string]()
for i in 0..5: a.incl(i)
for i in 1..6: b.incl(i)
for i in 0..5: c.incl($i)
doAssert map(a, proc(x: int): int = x + 1) == b
doAssert map(a, proc(x: int): string = $x) == c
block setsContainingTuples:
var set = initSet[tuple[i: int, i64: int64, f: float]]()
set.incl( (i: 123, i64: 123'i64, f: 3.14) )
doAssert set.contains( (i: 123, i64: 123'i64, f: 3.14) )
doAssert( not set.contains( (i: 456, i64: 789'i64, f: 2.78) ) )
block setWithTuplesWithSeqs:
var s = initSet[tuple[s: seq[int]]]()
s.incl( (s: @[1, 2, 3]) )
doAssert s.contains( (s: @[1, 2, 3]) )
doAssert( not s.contains((s: @[4, 5, 6])) )
block setWithSequences:
var s = initSet[seq[int]]()
s.incl( @[1, 2, 3] )
doAssert s.contains(@[1, 2, 3])
doAssert( not s.contains(@[4, 5, 6]) )
echo map(a, proc(x: int): int = x + 1) == b
echo map(a, proc(x: int): string = $x) == c

View File

@@ -22,15 +22,15 @@ const
"---00": 346677844,
"0": 34404,
"1": 344004,
"10": 34484,
"10": 34484,
"11": 34474,
"12": 789,
"19": 34464,
"2": 344774, "20": 34454,
"2": 344774, "20": 34454,
"3": 342244, "30": 34141244,
"34": 123456,
"4": 3412344, "40": 344114,
"5": 341232144, "50": 344490,
"5": 341232144, "50": 344490,
"6": 34214544, "60": 344491,
"7": 3434544, "70": 344492,
"8": 344544, "80": 344497,
@@ -46,7 +46,7 @@ block tableTest1:
for x in 0..1:
for y in 0..1:
assert t[(x,y)] == $x & $y
assert($t ==
assert($t ==
"{(x: 0, y: 1): 01, (x: 0, y: 0): 00, (x: 1, y: 0): 10, (x: 1, y: 1): 11}")
block tableTest2:
@@ -55,14 +55,16 @@ block tableTest2:
t["111"] = 1.000043
t["123"] = 1.23
t.del("111")
t["012"] = 67.9
t["123"] = 1.5 # test overwriting
assert t["123"] == 1.5
assert t["111"] == 0.0 # deleted
assert(not hasKey(t, "111"))
assert "123" in t
assert("111" notin t)
for key, val in items(data): t[key] = val.toFloat
for key, val in items(data): assert t[key] == val.toFloat

View File

@@ -22,15 +22,15 @@ const
"---00": 346677844,
"0": 34404,
"1": 344004,
"10": 34484,
"10": 34484,
"11": 34474,
"12": 789,
"19": 34464,
"2": 344774, "20": 34454,
"2": 344774, "20": 34454,
"3": 342244, "30": 34141244,
"34": 123456,
"4": 3412344, "40": 344114,
"5": 341232144, "50": 344490,
"5": 341232144, "50": 344490,
"6": 34214544, "60": 344491,
"7": 3434544, "70": 344492,
"8": 344544, "80": 344497,
@@ -46,7 +46,7 @@ block tableTest1:
for x in 0..1:
for y in 0..1:
assert t[(x,y)] == $x & $y
assert($t ==
assert($t ==
"{(x: 0, y: 1): 01, (x: 0, y: 0): 00, (x: 1, y: 0): 10, (x: 1, y: 1): 11}")
block tableTest2:
@@ -55,17 +55,19 @@ block tableTest2:
t["111"] = 1.000043
t["123"] = 1.23
t.del("111")
t["012"] = 67.9
t["123"] = 1.5 # test overwriting
assert t["123"] == 1.5
assert t["111"] == 0.0 # deleted
assert "123" in t
assert(not hasKey(t, "111"))
assert "111" notin t
for key, val in items(data): t[key] = val.toFloat
for key, val in items(data): assert t[key] == val.toFloat
block orderedTableTest1:
var t = newOrderedTable[string, int](2)

17
tests/cpp/tcppraise.nim Normal file
View File

@@ -0,0 +1,17 @@
discard """
cmd: "nim cpp $file"
output: '''foo
bar
Need odd and >= 3 digits##
baz'''
"""
# bug #1888
echo "foo"
try:
echo "bar"
raise newException(ValueError, "Need odd and >= 3 digits")
# echo "baz"
except ValueError:
echo getCurrentExceptionMsg(), "##"
echo "baz"

View File

@@ -0,0 +1,23 @@
discard """
cmd: "nim cpp $file"
"""
{.emit: """
namespace System {
struct Input {};
}
struct SystemManager {
template <class T>
static T* getSubsystem() { return new T; }
};
""".}
type Input {.importcpp: "System::Input".} = object
proc getSubsystem*[T](): ptr T {.
importcpp: "SystemManager::getSubsystem<'*0>()", nodecl.}
let input: ptr Input = getSubsystem[Input]()

View File

@@ -0,0 +1,19 @@
discard """
cmd: "nim cpp $file"
"""
{.emit: """
template <class T>
struct Vector {
struct Iterator {};
};
""".}
type
Vector {.importcpp: "Vector".} [T] = object
VectorIterator {.importcpp: "Vector<'0>::Iterator".} [T] = object
var x: VectorIterator[void]

38
tests/cpp/tvectorseq.nim Normal file
View File

@@ -0,0 +1,38 @@
discard """
output: '''(x: 1.0)
(x: 0.0)'''
cmd: "nim cpp $file"
disabled: "true"
"""
# This cannot work yet because we omit type information for importcpp'ed types.
# Fixing this is not hard, but also requires fixing Urhonimo.
# bug #2536
{.emit: """/*TYPESECTION*/
struct Vector3 {
public:
Vector3(): x(5) {}
Vector3(float x_): x(x_) {}
float x;
};
""".}
type Vector3 {.importcpp: "Vector3", nodecl} = object
x: cfloat
proc constructVector3(a: cfloat): Vector3 {.importcpp: "Vector3(@)", nodecl}
# hack around another codegen issue: Generics are attached to where they came
# from:
proc `$!`(v: seq[Vector3]): string = "(x: " & $v[0].x & ")"
proc vec3List*(): seq[Vector3] =
let s = @[constructVector3(cfloat(1))]
echo($!s)
result = s
echo($!result)
let f = vec3List()
#echo($!f)

View File

@@ -40,7 +40,7 @@ type
x: A
y: B
z: C
TObjKind = enum A, B, C, D
TCaseObj = object
@@ -57,14 +57,14 @@ type
q: TMyGeneric3[TMyObj, int, int]
r: string
proc destroy(o: var TMyObj) {.override.} =
proc `=destroy`(o: var TMyObj) =
if o.p != nil: dealloc o.p
echo "myobj destroyed"
proc destroy(o: var TMyGeneric1) {.override.} =
proc `=destroy`(o: var TMyGeneric1) =
echo "mygeneric1 destroyed"
proc destroy[A, B](o: var TMyGeneric2[A, B]) {.override.} =
proc `=destroy`[A, B](o: var TMyGeneric2[A, B]) =
echo "mygeneric2 destroyed"
proc open: TMyObj =
@@ -83,12 +83,12 @@ proc mygeneric1() =
proc mygeneric2[T](val: T) =
var a = open()
var b = TMyGeneric2[int, T](x: 10, y: val)
echo "mygeneric2 constructed"
var c = TMyGeneric3[int, int, string](x: 10, y: 20, z: "test")
proc mygeneric3 =
var x = TMyGeneric3[int, string, TMyGeneric1[int]](
x: 10, y: "test", z: TMyGeneric1[int](x: 10))
@@ -111,11 +111,11 @@ proc caseobj =
block:
echo "----"
var o1 = TCaseObj(kind: A, x: TMyGeneric1[int](x: 10))
block:
echo "----"
var o2 = TCaseObj(kind: B, y: open())
block:
echo "----"
var o3 = TCaseObj(kind: D, innerKind: B, r: "test",

View File

@@ -5,14 +5,14 @@ discard """
{.experimental.}
type
type
TMyObj = object
x, y: int
p: pointer
proc destroy(o: var TMyObj) {.override.} =
proc `=destroy`(o: var TMyObj) =
if o.p != nil: dealloc o.p
proc open: TMyObj =
result = TMyObj(x: 1, y: 2, p: alloc(3))

View File

@@ -0,0 +1,20 @@
# bug #2641
type MyChar = distinct char
const c:MyChar = MyChar('a')
type MyBool = distinct bool
const b:MyBool = MyBool(true)
type MyBoolSet = distinct set[bool]
const bs:MyBoolSet = MyBoolSet({true})
type MyCharSet= distinct set[char]
const cs:MyCharSet = MyCharSet({'a'})
type MyBoolSeq = distinct seq[bool]
const bseq:MyBoolSeq = MyBoolSeq(@[true, false])
type MyBoolArr = distinct array[3, bool]
const barr:MyBoolArr = MyBoolArr([true, false, true])

View File

@@ -1,5 +1,5 @@
discard """
line: 16
line: 17
errormsg: "'mainUnsafe' is not GC-safe"
cmd: "nim $target --hints:on --threads:on $options $file"
"""

View File

@@ -5,20 +5,20 @@ discard """
# First variety
try:
raise newException(EOS, "Problem")
except EOS:
raise newException(OSError, "Problem")
except OSError:
for y in [1, 2, 3]:
discard
try:
discard
except EOS:
except OSError:
discard
echo "1"
# Second Variety
try:
raise newException(EOS, "Problem")
except EOS:
raise newException(OSError, "Problem")
except OSError:
for y in [1, 2, 3]:
discard
for y in [1, 2, 3]:
@@ -28,8 +28,8 @@ echo "2"
# Third Variety
try:
raise newException(EOS, "Problem")
except EOS:
raise newException(OSError, "Problem")
except OSError:
block:
break
@@ -38,8 +38,8 @@ echo "3"
# Fourth Variety
block:
try:
raise newException(EOS, "Problem")
except EOS:
raise newException(OSError, "Problem")
except OSError:
break
echo "4"
echo "4"

View File

@@ -35,9 +35,9 @@ echo ""
proc reraise_in_except =
try:
echo "BEFORE"
raise newException(EIO, "")
raise newException(IOError, "")
except EIO:
except IOError:
echo "EXCEPT"
raise
@@ -52,7 +52,7 @@ echo ""
proc return_in_except =
try:
echo "BEFORE"
raise newException(EIO, "")
raise newException(IOError, "")
except:
echo "EXCEPT"

View File

@@ -5,12 +5,12 @@ discard """
# Test inheritance for exception matching:
try:
raise newException(EOS, "dummy message")
except E_Base:
raise newException(OSError, "dummy message")
except Exception:
echo "caught!"
except:
except:
echo "wtf!?"
#OUT caught!

View File

@@ -8,19 +8,19 @@ discard """
var raiseEx = true
var returnA = true
var returnB = false
proc main: int =
proc main: int =
try: #A
try: #B
if raiseEx:
raise newException(EOS, "")
raise newException(OSError, "")
return 3
finally: #B
echo "B1"
if returnB:
return 2
echo "B2"
except EOS: #A
except OSError: #A
echo "catch"
finally: #A
echo "A1"

View File

@@ -7,7 +7,7 @@ discard """
proc test1() =
finally: echo "A"
defer: echo "A"
try:
raise newException(OSError, "Problem")
@@ -19,7 +19,7 @@ test1()
proc test2() =
finally: echo "B"
defer: echo "B"
try:
return

View File

@@ -4,8 +4,8 @@ success'''
"""
type
ESomething = object of E_Base
ESomeOtherErr = object of E_Base
ESomething = object of Exception
ESomeOtherErr = object of Exception
proc genErrors(s: string) =
if s == "error!":
@@ -17,14 +17,14 @@ proc foo() =
var i = 0
try:
inc i
onRaise(proc (e: ref E_Base): bool =
onRaise(proc (e: ref Exception): bool =
echo "i: ", i)
genErrors("errssor!")
except ESomething:
echo("ESomething happened")
except:
echo("Some other error happened")
# test that raise handler is gone:
try:
genErrors("error!")

View File

@@ -4,8 +4,8 @@ discard """
exitcode: "1"
"""
type
ESomething = object of E_Base
ESomeOtherErr = object of E_Base
ESomething = object of Exception
ESomeOtherErr = object of Exception
proc genErrors(s: string) =
if s == "error!":

View File

@@ -0,0 +1,21 @@
discard """
errormsg: "cannot instantiate: 'GenericNodeObj'"
line: 21
"""
# bug #2509
type
GenericNodeObj[T] = ref object
obj: T
Node* = ref object
children*: seq[Node]
parent*: Node
nodeObj*: GenericNodeObj # [int]
proc newNode*(nodeObj: GenericNodeObj): Node =
result = Node(nodeObj: nodeObj)
newSeq(result.children, 10)
var genericObj = GenericNodeObj[int]()
var myNode = newNode(genericObj)

View File

@@ -1,6 +1,7 @@
discard """
output: '''foo
js 3.14'''
js 3.14
7'''
"""
# This file tests the JavaScript generator
@@ -20,3 +21,11 @@ else:
proc foo(val: float): string = "js " & $val
echo foo(3.14)
# #2495
type C = concept x
proc test(x: C, T: typedesc): T =
cast[T](x)
echo 7.test(int8)

24
tests/js/tstringitems.nim Normal file
View File

@@ -0,0 +1,24 @@
discard """
output: '''Hello
Hello'''
"""
# bug #2581
const someVars = [ "Hello" ]
var someVars2 = [ "Hello" ]
proc getSomeVar: string =
for i in someVars:
if i == "Hello":
result = i
break
proc getSomeVar2: string =
for i in someVars2:
if i == "Hello":
result = i
break
echo getSomeVar()
echo getSomeVar2()

View File

@@ -1,3 +1,10 @@
discard """
disabled: "true"
"""
# Unittest uses lambdalifting at compile-time which we disable for the JS
# codegen! So this cannot and will not work for quite some time.
import unittest
suite "Bacon":

16
tests/macros/tlexerex.nim Normal file
View File

@@ -0,0 +1,16 @@
import macros
macro match*(s: cstring|string; pos: int; sections: untyped): untyped =
for sec in sections.children:
expectKind sec, nnkOfBranch
expectLen sec, 2
result = newStmtList()
when isMainModule:
var input = "the input"
var pos = 0
match input, pos:
of r"[a-zA-Z_]\w+": echo "an identifier"
of r"\d+": echo "an integer"
of r".": echo "something else"

View File

@@ -0,0 +1,12 @@
discard """
errormsg: "type mismatch"
line: 11
"""
# bug #2372
macro foo(dummy: int): stmt =
discard
proc takeStr(s: string) = echo s
takeStr foo(12)

View File

@@ -15,5 +15,6 @@ const
valid = 45
a = test("foo&&")
b = test("valid")
c = test("\"") # bug #2504
echo a, " ", b

View File

@@ -1,4 +1,4 @@
# tests to see if a symbol returned from macros.getType() can
# tests to see if a symbol returned from macros.getType() can
# be used as a type
import macros
@@ -20,7 +20,7 @@ static: assert iii is TestFN
proc foo11 : testTypesym(void) =
echo "HI!"
static: assert foo11 is proc():void
static: assert foo11 is (proc():void {.nimcall.})
var sss: testTypesym(seq[int])
static: assert sss is seq[int]

View File

@@ -7,13 +7,13 @@ proc exit(code: int) {.importc, header: "<stdlib.h>", cdecl.}
proc rawoutput(s: string) =
printf("%s\n", s)
proc panic(s: string) =
proc panic(s: string) {.noreturn.} =
rawoutput(s)
exit(1)
# Alternatively we also could implement these 2 here:
#
# template sysFatal(exceptn: typeDesc, message: string)
# template sysFatal(exceptn: typeDesc, message, arg: string)
# proc sysFatal(exceptn: typeDesc, message: string) {.noReturn.}
# proc sysFatal(exceptn: typeDesc, message, arg: string) {.noReturn.}
{.pop.}

View File

@@ -1,11 +1,13 @@
discard """
errormsg: "expression 'generate(builder)' has no type (or is ambiguous)"
output: "empty"
"""
# bug #898
import typetraits
proc measureTime(e: auto) =
discard
echo e.type.name
proc generate(a: int): void =
discard

10
tests/misc/tcharinc.nim Normal file
View File

@@ -0,0 +1,10 @@
discard """
output: "1"
"""
var c = '\0'
while true:
if c == '\xFF': break
inc c
echo "1"

View File

@@ -1,53 +0,0 @@
discard """
disabled: true
"""
import
gtk2, glib2, atk, gdk2, gdk2pixbuf, libglade2, pango,
pangoutils
proc hello(widget: PWidget, data: pointer) {.cdecl.} =
write(stdout, "Hello World\n")
proc delete_event(widget: PWidget, event: PEvent,
data: pointer): bool {.cdecl.} =
# If you return FALSE in the "delete_event" signal handler,
# GTK will emit the "destroy" signal. Returning TRUE means
# you don't want the window to be destroyed.
# This is useful for popping up 'are you sure you want to quit?'
# type dialogs.
write(stdout, "delete event occurred\n")
# Change TRUE to FALSE and the main window will be destroyed with
# a "delete_event".
return false
# Another callback
proc mydestroy(widget: PWidget, data: pointer) {.cdecl.} =
gtk2.main_quit()
proc mymain() =
# GtkWidget is the storage type for widgets
gtk2.nimrod_init()
var window = window_new(gtk2.WINDOW_TOPLEVEL)
discard g_signal_connect(window, "delete_event",
Gcallback(delete_event), nil)
discard g_signal_connect(window, "destroy", Gcallback(mydestroy), nil)
# Sets the border width of the window.
set_border_width(window, 10)
# Creates a new button with the label "Hello World".
var button = button_new("Hello World")
discard g_signal_connect(button, "clicked", Gcallback(hello), nil)
# This packs the button into the window (a gtk container).
add(window, button)
# The final step is to display this newly created widget.
show(button)
# and the window
show(window)
gtk2.main()
mymain()

View File

@@ -1,28 +0,0 @@
discard """
disabled: true
"""
# Test wether the bindings at least compile...
import
unicode, cgi, terminal, libcurl,
parsexml, parseopt, parsecfg,
osproc, complex,
sdl, smpeg, sdl_gfx, sdl_net, sdl_mixer, sdl_ttf,
sdl_image, sdl_mixer_nosmpeg,
cursorfont, xatom, xf86vmode, xkb, xrandr, xshm, xvlib, keysym, xcms, xi,
xkblib, xrender, xutil, x, xf86dga, xinerama, xlib, xresource, xv,
gtk2, glib2, pango, gdk2,
cairowin32, cairoxlib,
odbcsql,
gl, glut, glu, glx, glext, wingl,
lua, lualib, lauxlib, mysql, sqlite3, python, tcl,
db_postgres, db_mysql, db_sqlite, ropes, sockets, browsers, httpserver,
httpclient, parseutils, unidecode, xmldom, xmldomparser, xmltree, xmlparser,
htmlparser, re, graphics, colors, pegs, subexes, dialogs
when defined(linux):
import
zlib, zipfiles
writeln(stdout, "test compilation of binding modules")

View File

@@ -1,21 +0,0 @@
discard """
disabled: true
"""
# Test wether the bindings at least compile...
import
tcl,
sdl, smpeg, sdl_gfx, sdl_net, sdl_mixer, sdl_ttf,
sdl_image, sdl_mixer_nosmpeg,
gtk2, glib2, pango, gdk2,
unicode, cgi, terminal, libcurl,
parsexml, parseopt, parsecfg,
osproc,
cairowin32, cairoxlib,
gl, glut, glu, glx, glext, wingl,
lua, lualib, lauxlib, mysql, sqlite3, db_mongo, md5, asyncio, mimetypes,
cookies, events, ftpclient, scgi, irc
writeln(stdout, "test compilation of binding modules")

View File

@@ -10,3 +10,17 @@ let t1 = v1 mod 2 # works
let t2 = 7'u64 mod 2'u64 # works
let t3 = v2 mod 2'u64 # Error: invalid type: 'range 0..1(uint64)
let t4 = (v2 mod 2'u64).uint64 # works
# bug #2550
var x: uint # doesn't work
echo x mod 2 == 0
var y: uint64 # doesn't work
echo y mod 2 == 0
var z: uint32 # works
echo z mod 2 == 0
var a: int # works
echo a mod 2 == 0

View File

@@ -0,0 +1,14 @@
discard """
output: '''253'''
"""
# bug #2427
import unsigned
var x = 0'u8
dec x # OverflowError
x -= 1 # OverflowError
x = x - 1 # No error
echo x

View File

@@ -0,0 +1,7 @@
discard """
errormsg: "illegal recursion in type 'object'"
line: 7
"""
# bug #1691
type
Foo = ref object of Foo

View File

@@ -0,0 +1,15 @@
discard """
output: "is Nil false"
"""
# bug #1658
type
Loop* = ref object
onBeforeSelect*: proc (L: Loop)
var L: Loop
new L
L.onBeforeSelect = proc (bar: Loop) =
echo "is Nil ", bar.isNil
L.onBeforeSelect(L)

View File

@@ -0,0 +1,19 @@
# bug #2508
type
GenericNodeObj[T] = ref object
obj: T
Node* = ref object
children*: seq[Node]
parent*: Node
nodeObj*: GenericNodeObj[int]
proc newNode*(nodeObj: GenericNodeObj): Node =
result = Node(nodeObj: nodeObj)
newSeq(result.children, 10)
var genericObj = GenericNodeObj[int]()
var myNode = newNode(genericObj)

View File

@@ -11,7 +11,10 @@ ref T
123
2
1
@[123, 2, 1]'''
@[123, 2, 1]
Called!
merge with var
merge no var'''
"""
# Things that's even in the spec now!
@@ -79,3 +82,37 @@ proc takeV[T](a: varargs[T]) =
takeV([123, 2, 1]) # takeV's T is "int", not "array of int"
echo(@[123, 2, 1])
# bug #2600
type
FutureBase* = ref object of RootObj ## Untyped future.
Future*[T] = ref object of FutureBase ## Typed future.
value: T ## Stored value
FutureVar*[T] = distinct Future[T]
proc newFuture*[T](): Future[T] =
new(result)
proc newFutureVar*[T](): FutureVar[T] =
result = FutureVar[T](newFuture[T]())
proc mget*[T](future: FutureVar[T]): var T =
Future[T](future).value
proc reset*[T](future: FutureVar[T]) =
echo "Called!"
proc merge[T](x: Future[T]) = echo "merge no var"
proc merge[T](x: var Future[T]) = echo "merge with var"
when true:
var foo = newFutureVar[string]()
foo.mget() = ""
foo.mget.add("Foobar")
foo.reset()
var bar = newFuture[int]()
bar.merge # merge with var
merge(newFuture[int]()) # merge no var

View File

@@ -0,0 +1,38 @@
# bug #2481
import math
template test(loopCount: int, extraI: int, testBody: stmt): stmt =
block:
for i in 0..loopCount-1:
testBody
echo "done extraI=", extraI
template test(loopCount: int, extraF: float, testBody: stmt): stmt =
block:
test(loopCount, round(extraF), testBody)
template test(loopCount: int, testBody: stmt): stmt =
block:
test(loopCount, 0, testBody)
echo "done extraI passed 0"
when isMainModule:
var
loops = 0
test 0, 0:
loops += 1
echo "test 0 complete, loops=", loops
test 1, 1.0:
loops += 1
echo "test 1.0 complete, loops=", loops
when true:
# when true we get the following compile time error:
# b.nim(35, 6) Error: expression 'loops += 1' has no type (or is ambiguous)
loops = 0
test 2:
loops += 1
echo "test no extra complete, loops=", loops

View File

@@ -0,0 +1,39 @@
discard """
line: 28
nimout: '''tgc_unsafe2.nim(22, 5) Warning: 'trick' is not GC-safe as it accesses 'global' which is a global using GC'ed memory
tgc_unsafe2.nim(26, 5) Warning: 'track' is not GC-safe as it calls 'trick'
tgc_unsafe2.nim(28, 5) Error: 'consumer' is not GC-safe as it calls 'track'
'''
errormsg: "'consumer' is not GC-safe as it calls 'track'"
"""
import threadpool
type StringChannel = TChannel[string]
var channels: array[1..3, StringChannel]
type
MyObject[T] = object
x: T
var global: MyObject[string]
var globalB: MyObject[float]
proc trick(ix: int) =
echo global.x
echo channels[ix].recv()
proc track(ix: int) = trick(ix)
proc consumer(ix: int) {.thread.} =
track(ix)
proc main =
for ix in 1..3: channels[ix].open()
for ix in 1..3: spawn consumer(ix)
for ix in 1..3: channels[ix].send("test")
sync()
for ix in 1..3: channels[ix].close()
when isMainModule:
main()

View File

@@ -0,0 +1,53 @@
discard """
output: "Success"
"""
import math, threadPool
# ---
type
Person = object
age: int
friend: ref Person
var
people: seq[ref Person] = @[]
proc newPerson(age:int): ref Person =
result.new()
result.age = age
proc greet(p:Person) =
#echo p.age, ", ", p.friend.age
p.friend.age += 1
# ---
proc setup =
for i in 0 .. <20:
people.add newPerson(i + 1)
for i in 0 .. <20:
people[i].friend = people[random(20)]
proc update =
var countA: array[20, int]
var countB: array[20, int]
for i, p in people:
countA[i] = getRefCount(p)
parallel:
for i in 0 .. people.high:
spawn greet(people[i][])
for i, p in people:
countB[i] = getRefCount(p)
for i in 0 .. <20:
doAssert countA[i] == countB[i]
echo "Success"
# ---
when isMainModule:
setup()
update()

View File

@@ -0,0 +1,12 @@
discard """
file: "tinvcolonlocation1.nim"
line: 8
column: 3
errormsg: "':' expected"
"""
try #<- missing ':'
echo "try"
except:
echo "except"
finally:
echo "finally"

View File

@@ -0,0 +1,15 @@
discard """
file: "tinvcolonlocation2.nim"
line: 11
column: 1
errormsg: "':' expected"
"""
try:
echo "try"
except #<- missing ':'
echo "except"
finally:
#<-- error will be here above, at the beginning of finally,
# since compiler tries to consome echo and part of except
# expression
echo "finally"

View File

@@ -0,0 +1,12 @@
discard """
file: "tinvcolonlocation3.nim"
line: 12
column: 3
errormsg: "':' expected"
"""
try:
echo "try"
except:
echo "except"
finally #<- missing ':'
echo "finally"

View File

@@ -2,6 +2,12 @@
discard """
output: '''35
true
true
4
true
1
false
77
(Field0: 1, Field1: 2, Field2: 2)
ha
@@ -9,11 +15,26 @@ true
tester args
all
all args
19
-3
false
-2
'''
"""
echo 2+5 * 5
# Keyword operators
echo 1 + 16 shl 1 == 1 + (16 shl 1)
echo 2 and 1 in {0, 30}
echo 2+2 * 2 shr 1
echo false or 2 and 1 in {0, 30}
proc `^`(a, b: int): int = a + b div 2
echo 19 mod 16 ^ 4 + 2 and 1
echo 18 mod 16 ^ 4 > 0
# echo $foo gotcha
let foo = 77
echo $foo
@@ -27,7 +48,7 @@ when true:
let b = 66
let c = 90
let bar = 8000
if foo+4 * 4 == 8 and b&c | 9 ++
if foo+4 * 4 == 8 and b&c | 9 ++
bar:
echo "ho"
else:
@@ -50,3 +71,13 @@ const
echo tester & " " & args|"all"
echo "all" | tester & " " & args
echo "all"|tester & " " & args
# Test arrow like operators. See also tests/macros/tclosuremacro.nim
proc `+->`(a, b: int): int = a + b*4
template `===>`(a, b: int): expr = a - b shr 1
echo 3 +-> 2 + 2 and 4
var arrowed = 3+->2 + 2 and 4 # arrowed = 4
echo arrowed ===> 15
echo (2 * 3+->2) == (2*3 +-> 2)
echo arrowed ===> 2 + 3+->2

View File

@@ -0,0 +1,35 @@
discard """
file: "ttupleunpack.nim"
output: ""
exitcode: 0
"""
proc returnsTuple(): (int, int, int) = (4, 2, 3)
proc main2 =
let (x, _, z) = returnsTuple()
proc main() =
proc foo(): tuple[x, y, z: int] =
return (4, 2, 3)
var (x, _, y) = foo()
doAssert x == 4
doAssert y == 3
var (a, _, _) = foo()
doAssert a == 4
var (aa, _, _) = foo()
doAssert aa == 4
iterator bar(): tuple[x, y, z: int] =
yield (1,2,3)
for x, y, _ in bar():
doAssert x == 1
doAssert y == 2
main()
main2()

View File

@@ -1,6 +1,7 @@
discard """
file: "tsets.nim"
output: "Ha ein F ist in s!"
output: '''Ha ein F ist in s!
false'''
"""
# Test the handling of sets
@@ -15,30 +16,30 @@ type
TAZ = range['a'..'z']
TAZset = set[TAZ]
TTokType* = enum
TTokType* = enum
tkInvalid, tkEof,
tkSymbol,
tkAddr, tkAnd, tkAs, tkAsm, tkBlock, tkBreak, tkCase, tkCast, tkConst,
tkContinue, tkConverter, tkDiscard, tkDiv, tkElif, tkElse, tkEnd, tkEnum,
tkExcept, tkException, tkFinally, tkFor, tkFrom, tkGeneric, tkIf, tkImplies,
tkImport, tkIn, tkInclude, tkIs, tkIsnot, tkIterator, tkLambda, tkMacro,
tkMethod, tkMod, tkNil, tkNot, tkNotin, tkObject, tkOf, tkOr, tkOut, tkProc,
tkPtr, tkRaise, tkRecord, tkRef, tkReturn, tkShl, tkShr, tkTemplate, tkTry,
tkAddr, tkAnd, tkAs, tkAsm, tkBlock, tkBreak, tkCase, tkCast, tkConst,
tkContinue, tkConverter, tkDiscard, tkDiv, tkElif, tkElse, tkEnd, tkEnum,
tkExcept, tkException, tkFinally, tkFor, tkFrom, tkGeneric, tkIf, tkImplies,
tkImport, tkIn, tkInclude, tkIs, tkIsnot, tkIterator, tkLambda, tkMacro,
tkMethod, tkMod, tkNil, tkNot, tkNotin, tkObject, tkOf, tkOr, tkOut, tkProc,
tkPtr, tkRaise, tkRecord, tkRef, tkReturn, tkShl, tkShr, tkTemplate, tkTry,
tkType, tkVar, tkWhen, tkWhere, tkWhile, tkWith, tkWithout, tkXor, tkYield,
tkIntLit, tkInt8Lit, tkInt16Lit, tkInt32Lit, tkInt64Lit, tkFloatLit,
tkFloat32Lit, tkFloat64Lit, tkStrLit, tkRStrLit, tkTripleStrLit, tkCharLit,
tkRCharLit, tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe,
tkCurlyRi, tkBracketDotLe, tkBracketDotRi,
tkCurlyDotLe, tkCurlyDotRi,
tkIntLit, tkInt8Lit, tkInt16Lit, tkInt32Lit, tkInt64Lit, tkFloatLit,
tkFloat32Lit, tkFloat64Lit, tkStrLit, tkRStrLit, tkTripleStrLit, tkCharLit,
tkRCharLit, tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe,
tkCurlyRi, tkBracketDotLe, tkBracketDotRi,
tkCurlyDotLe, tkCurlyDotRi,
tkParDotLe, tkParDotRi,
tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot, tkHat, tkOpr,
tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot, tkHat, tkOpr,
tkComment, tkAccent, tkInd, tkSad, tkDed,
tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr
TTokTypeRange = range[tkSymbol..tkDed]
TTokTypes* = set[TTokTypeRange]
const
toktypes: TTokTypes = {TTokTypeRange(tkSymbol)..pred(tkIntLit),
toktypes: TTokTypes = {TTokTypeRange(tkSymbol)..pred(tkIntLit),
tkStrLit..tkTripleStrLit}
var
@@ -62,3 +63,142 @@ for x in low(TTokTypeRange) .. high(TTokTypeRange):
#OUT Ha ein F ist in s!
type
TMsgKind* = enum
errUnknown, errIllFormedAstX, errInternal, errCannotOpenFile, errGenerated,
errXCompilerDoesNotSupportCpp, errStringLiteralExpected,
errIntLiteralExpected, errInvalidCharacterConstant,
errClosingTripleQuoteExpected, errClosingQuoteExpected,
errTabulatorsAreNotAllowed, errInvalidToken, errLineTooLong,
errInvalidNumber, errNumberOutOfRange, errNnotAllowedInCharacter,
errClosingBracketExpected, errMissingFinalQuote, errIdentifierExpected,
errNewlineExpected,
errInvalidModuleName,
errOperatorExpected, errTokenExpected, errStringAfterIncludeExpected,
errRecursiveDependencyX, errOnOrOffExpected, errNoneSpeedOrSizeExpected,
errInvalidPragma, errUnknownPragma, errInvalidDirectiveX,
errAtPopWithoutPush, errEmptyAsm, errInvalidIndentation,
errExceptionExpected, errExceptionAlreadyHandled,
errYieldNotAllowedHere, errYieldNotAllowedInTryStmt,
errInvalidNumberOfYieldExpr, errCannotReturnExpr, errAttemptToRedefine,
errStmtInvalidAfterReturn, errStmtExpected, errInvalidLabel,
errInvalidCmdLineOption, errCmdLineArgExpected, errCmdLineNoArgExpected,
errInvalidVarSubstitution, errUnknownVar, errUnknownCcompiler,
errOnOrOffExpectedButXFound, errNoneBoehmRefcExpectedButXFound,
errNoneSpeedOrSizeExpectedButXFound, errGuiConsoleOrLibExpectedButXFound,
errUnknownOS, errUnknownCPU, errGenOutExpectedButXFound,
errArgsNeedRunOption, errInvalidMultipleAsgn, errColonOrEqualsExpected,
errExprExpected, errUndeclaredIdentifier, errUseQualifier, errTypeExpected,
errSystemNeeds, errExecutionOfProgramFailed, errNotOverloadable,
errInvalidArgForX, errStmtHasNoEffect, errXExpectsTypeOrValue,
errXExpectsArrayType, errIteratorCannotBeInstantiated, errExprXAmbiguous,
errConstantDivisionByZero, errOrdinalTypeExpected,
errOrdinalOrFloatTypeExpected, errOverOrUnderflow,
errCannotEvalXBecauseIncompletelyDefined, errChrExpectsRange0_255,
errDynlibRequiresExportc, errUndeclaredFieldX, errNilAccess,
errIndexOutOfBounds, errIndexTypesDoNotMatch, errBracketsInvalidForType,
errValueOutOfSetBounds, errFieldInitTwice, errFieldNotInit,
errExprXCannotBeCalled, errExprHasNoType, errExprXHasNoType,
errCastNotInSafeMode, errExprCannotBeCastedToX, errCommaOrParRiExpected,
errCurlyLeOrParLeExpected, errSectionExpected, errRangeExpected,
errMagicOnlyInSystem, errPowerOfTwoExpected,
errStringMayNotBeEmpty, errCallConvExpected, errProcOnlyOneCallConv,
errSymbolMustBeImported, errExprMustBeBool, errConstExprExpected,
errDuplicateCaseLabel, errRangeIsEmpty, errSelectorMustBeOfCertainTypes,
errSelectorMustBeOrdinal, errOrdXMustNotBeNegative, errLenXinvalid,
errWrongNumberOfVariables, errExprCannotBeRaised, errBreakOnlyInLoop,
errTypeXhasUnknownSize, errConstNeedsConstExpr, errConstNeedsValue,
errResultCannotBeOpenArray, errSizeTooBig, errSetTooBig,
errBaseTypeMustBeOrdinal, errInheritanceOnlyWithNonFinalObjects,
errInheritanceOnlyWithEnums, errIllegalRecursionInTypeX,
errCannotInstantiateX, errExprHasNoAddress, errXStackEscape,
errVarForOutParamNeeded,
errPureTypeMismatch, errTypeMismatch, errButExpected, errButExpectedX,
errAmbiguousCallXYZ, errWrongNumberOfArguments,
errXCannotBePassedToProcVar,
errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProc, errImplOfXNotAllowed,
errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX,
errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice,
errInvalidOrderInArrayConstructor,
errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry,
errOptionExpected, errXisNoLabel, errNotAllCasesCovered,
errUnknownSubstitionVar, errComplexStmtRequiresInd, errXisNotCallable,
errNoPragmasAllowedForX, errNoGenericParamsAllowedForX,
errInvalidParamKindX, errDefaultArgumentInvalid, errNamedParamHasToBeIdent,
errNoReturnTypeForX, errConvNeedsOneArg, errInvalidPragmaX,
errXNotAllowedHere, errInvalidControlFlowX,
errXisNoType, errCircumNeedsPointer, errInvalidExpression,
errInvalidExpressionX, errEnumHasNoValueX, errNamedExprExpected,
errNamedExprNotAllowed, errXExpectsOneTypeParam,
errArrayExpectsTwoTypeParams, errInvalidVisibilityX, errInitHereNotAllowed,
errXCannotBeAssignedTo, errIteratorNotAllowed, errXNeedsReturnType,
errNoReturnTypeDeclared,
errInvalidCommandX, errXOnlyAtModuleScope,
errXNeedsParamObjectType,
errTemplateInstantiationTooNested, errInstantiationFrom,
errInvalidIndexValueForTuple, errCommandExpectsFilename,
errMainModuleMustBeSpecified,
errXExpected,
errTIsNotAConcreteType,
errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError,
errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile,
errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitly,
errOnlyACallOpCanBeDelegator, errUsingNoSymbol,
errMacroBodyDependsOnGenericTypes,
errDestructorNotGenericEnough,
errInlineIteratorsAsProcParams,
errXExpectsTwoArguments,
errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations,
errCannotInterpretNodeX, errFieldXNotFound, errInvalidConversionFromTypeX,
errAssertionFailed, errCannotGenerateCodeForX, errXRequiresOneArgument,
errUnhandledExceptionX, errCyclicTree, errXisNoMacroOrTemplate,
errXhasSideEffects, errIteratorExpected, errLetNeedsInit,
errThreadvarCannotInit, errWrongSymbolX, errIllegalCaptureX,
errXCannotBeClosure, errXMustBeCompileTime,
errCannotInferTypeOfTheLiteral,
errCannotInferReturnType,
errGenericLambdaNotAllowed,
errCompilerDoesntSupportTarget,
errUser,
warnCannotOpenFile,
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
warnDeprecated, warnConfigDeprecated,
warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel,
warnUnknownSubstitutionX, warnLanguageXNotSupported,
warnFieldXNotSupported, warnCommentXIgnored,
warnNilStatement, warnTypelessParam,
warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode,
warnEachIdentIsTuple, warnShadowIdent,
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
warnUser,
hintSuccess, hintSuccessX,
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
hintConditionAlwaysTrue, hintName, hintPattern,
hintUser
const
fatalMin* = errUnknown
fatalMax* = errInternal
errMin* = errUnknown
errMax* = errUser
warnMin* = warnCannotOpenFile
warnMax* = pred(hintSuccess)
hintMin* = hintSuccess
hintMax* = high(TMsgKind)
type
TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints
TNoteKinds* = set[TNoteKind]
var
gNotes*: TNoteKinds = {low(TNoteKind)..high(TNoteKind)} -
{warnShadowIdent, warnUninit,
warnProveField, warnProveIndex, warnGcUnsafe}
#import compiler.msgs
echo warnUninit in gNotes

View File

@@ -1,17 +0,0 @@
# Test the dialogs module
import dialogs, gtk2
gtk2.nimrod_init()
var x = chooseFilesToOpen(nil)
for a in items(x):
writeln(stdout, a)
info(nil, "start with an info box")
warning(nil, "now a warning ...")
error(nil, "... and an error!")
writeln(stdout, chooseFileToOpen(nil))
writeln(stdout, chooseFileToSave(nil))
writeln(stdout, chooseDir(nil))

9
tests/stdlib/treloop.nim Normal file
View File

@@ -0,0 +1,9 @@
discard """
output: "@[(, +, 1, 2, )]"
"""
import re
let str = "(+ 1 2)"
var tokenRE = re"""[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)"""
echo str.findAll(tokenRE)

View File

@@ -0,0 +1,14 @@
# bug #2629
import sequtils, os
template glob_rst(basedir: string = nil): expr =
if baseDir.isNil:
to_seq(walk_files("*.rst"))
else:
to_seq(walk_files(basedir/"*.rst"))
let
rst_files = concat(glob_rst(), glob_rst("docs"))
when isMainModule: echo rst_files

View File

@@ -0,0 +1,30 @@
# bug #2585
type
RenderPass = object
state: ref int
RenderData* = object
fb: int
walls: seq[RenderPass]
Mat2 = int
Vector2[T] = T
Pixels=int
template use*(fb: int, st: stmt) : stmt =
echo "a ", $fb
st
echo "a ", $fb
proc render(rdat: var RenderData; passes: var openarray[RenderPass]; proj: Mat2;
indexType = 1) =
for i in 0 .. <len(passes):
echo "blah ", repr(passes[i])
proc render2*(rdat: var RenderData; screenSz: Vector2[Pixels]; proj: Mat2) =
use rdat.fb:
render(rdat, rdat.walls, proj, 1)

View File

@@ -3,12 +3,12 @@ discard """
line: 18
errormsg: "undeclared identifier: \'b\'"
"""
template declareInScope(x: expr, t: typeDesc): stmt {.immediate.} =
template declareInScope(x: untyped, t: typeDesc): untyped {.immediate.} =
var x: t
template declareInNewScope(x: expr, t: typeDesc): stmt {.immediate.} =
template declareInNewScope(x: untyped, t: typeDesc): untyped {.immediate.} =
# open a new scope:
block:
block:
var x: t
declareInScope(a, int)

View File

@@ -238,7 +238,7 @@ proc testStdlib(r: var TResults, pattern, options: string, cat: Category) =
for test in os.walkFiles(pattern):
let contents = readFile(test).string
if contents.contains("when isMainModule"):
testSpec r, makeTest(test, options, cat, actionRun)
testSpec r, makeTest(test, options, cat, actionRunNoSpec)
else:
testNoSpec r, makeTest(test, options, cat, actionCompile)

View File

@@ -10,13 +10,14 @@
import parseutils, strutils, os, osproc, streams, parsecfg
const
cmdTemplate* = r"nim $target --hints:on $options $file"
cmdTemplate* = r"nim $target --hints:on -d:testing $options $file"
type
TTestAction* = enum
actionCompile = "compile"
actionRun = "run"
actionReject = "reject"
actionRunNoSpec = "runNoSpec"
TResultEnum* = enum
reNimcCrash, # nim compiler seems to have crashed
reMsgsDiffer, # error messages differ
@@ -42,7 +43,8 @@ type
action*: TTestAction
file*, cmd*: string
outp*: string
line*, exitCode*: int
line*, column*: int
exitCode*: int
msg*: string
ccodeCheck*: string
err*: TResultEnum
@@ -77,7 +79,7 @@ proc extractSpec(filename: string): string =
when not defined(nimhygiene):
{.pragma: inject.}
template parseSpecAux(fillResult: stmt) {.immediate.} =
template parseSpecAux(fillResult: untyped) =
var ss = newStringStream(extractSpec(filename))
var p {.inject.}: CfgParser
open(p, ss, filename, 1)
@@ -91,13 +93,18 @@ template parseSpecAux(fillResult: stmt) {.immediate.} =
fillResult
close(p)
proc parseSpec*(filename: string): TSpec =
result.file = filename
proc specDefaults*(result: var TSpec) =
result.msg = ""
result.outp = ""
result.nimout = ""
result.ccodeCheck = ""
result.cmd = cmdTemplate
result.line = 0
result.column = 0
proc parseSpec*(filename: string): TSpec =
specDefaults(result)
result.file = filename
parseSpecAux:
case normalize(e.key)
of "action":
@@ -108,7 +115,8 @@ proc parseSpec*(filename: string): TSpec =
else: echo ignoreMsg(p, e)
of "file": result.file = e.value
of "line": discard parseInt(e.value, result.line)
of "output":
of "column": discard parseInt(e.value, result.column)
of "output":
result.action = actionRun
result.outp = e.value
of "outputsub":
@@ -117,7 +125,7 @@ proc parseSpec*(filename: string): TSpec =
result.substr = true
of "sortoutput":
result.sortoutput = parseCfgBool(e.value)
of "exitcode":
of "exitcode":
discard parseInt(e.value, result.exitCode)
of "msg":
result.msg = e.value

View File

@@ -50,7 +50,7 @@ type
let
pegLineError =
peg"{[^(]*} '(' {\d+} ', ' \d+ ') ' ('Error') ':' \s* {.*}"
peg"{[^(]*} '(' {\d+} ', ' {\d+} ') ' ('Error') ':' \s* {.*}"
pegOtherError = peg"'Error:' \s* {.*}"
pegSuccess = peg"'Hint: operation successful'.*"
pegOfInterest = pegLineError / pegOtherError
@@ -77,11 +77,13 @@ proc callCompiler(cmdTemplate, filename, options: string,
result.msg = ""
result.file = ""
result.outp = ""
result.line = -1
result.line = 0
result.column = 0
if err =~ pegLineError:
result.file = extractFilename(matches[0])
result.line = parseInt(matches[1])
result.msg = matches[2]
result.column = parseInt(matches[2])
result.msg = matches[3]
elif err =~ pegOtherError:
result.msg = matches[0]
elif suc =~ pegSuccess:
@@ -149,8 +151,11 @@ proc cmpMsgs(r: var TResults, expected, given: TSpec, test: TTest) =
elif extractFilename(expected.file) != extractFilename(given.file) and
"internal error:" notin expected.msg:
r.addResult(test, expected.file, given.file, reFilesDiffer)
elif expected.line != given.line and expected.line != 0:
r.addResult(test, $expected.line, $given.line, reLinesDiffer)
elif expected.line != given.line and expected.line != 0 or
expected.column != given.column and expected.column != 0:
r.addResult(test, $expected.line & ':' & $expected.column,
$given.line & ':' & $given.column,
reLinesDiffer)
else:
r.addResult(test, expected.msg, given.msg, reSuccess)
inc(r.passed)
@@ -210,7 +215,12 @@ proc testSpec(r: var TResults, test: TTest) =
let tname = test.name.addFileExt(".nim")
inc(r.total)
styledEcho "Processing ", fgCyan, extractFilename(tname)
var expected = parseSpec(tname)
var expected: TSpec
if test.action != actionRunNoSpec:
expected = parseSpec(tname)
else:
specDefaults expected
expected.action = actionRunNoSpec
if expected.err == reIgnored:
r.addResult(test, "", "", reIgnored)
inc(r.skipped)
@@ -220,7 +230,7 @@ proc testSpec(r: var TResults, test: TTest) =
var given = callCompiler(expected.cmd, test.name,
test.options & " --hint[Path]:off --hint[Processing]:off", test.target)
compilerOutputTests(test, given, expected, r)
of actionRun:
of actionRun, actionRunNoSpec:
var given = callCompiler(expected.cmd, test.name, test.options,
test.target)
if given.err != reSuccess:

View File

@@ -0,0 +1,10 @@
# bug #1986 found by gdmoore
proc test(): int64 =
return 0xdeadbeef.int64
const items = [
(var1: test(), var2: 100'u32),
(var1: test(), var2: 192'u32)
]

View File

@@ -0,0 +1,766 @@
import macros
from strutils import IdentStartChars
import parseutils
import unicode
import math
import fenv
import unsigned
import pegs
import streams
type
FormatError = object of Exception ## Error in the format string.
Writer = concept W
## Writer to output a character `c`.
when (NimMajor, NimMinor, NimPatch) > (0, 10, 2):
write(W, 'c')
else:
block:
var x: W
write(x, char)
FmtAlign = enum ## Format alignment
faDefault ## default for given format type
faLeft ## left aligned
faRight ## right aligned
faCenter ## centered
faPadding ## right aligned, fill characters after sign (numbers only)
FmtSign = enum ## Format sign
fsMinus ## only unary minus, no reservered sign space for positive numbers
fsPlus ## unary minus and unary plus
fsSpace ## unary minus and reserved space for positive numbers
FmtType = enum ## Format type
ftDefault ## default format for given parameter type
ftStr ## string
ftChar ## character
ftDec ## decimal integer
ftBin ## binary integer
ftOct ## octal integer
ftHex ## hexadecimal integer
ftFix ## real number in fixed point notation
ftSci ## real number in scientific notation
ftGen ## real number in generic form (either fixed point or scientific)
ftPercent ## real number multiplied by 100 and % added
Format = tuple ## Formatting information.
typ: FmtType ## format type
precision: int ## floating point precision
width: int ## minimal width
fill: string ## the fill character, UTF8
align: FmtAlign ## aligment
sign: FmtSign ## sign notation
baseprefix: bool ## whether binary, octal, hex should be prefixed by 0b, 0x, 0o
upcase: bool ## upper case letters in hex or exponential formats
comma: bool ##
arysep: string ## separator for array elements
PartKind = enum pkStr, pkFmt
Part = object
## Information of a part of the target string.
case kind: PartKind ## type of the part
of pkStr:
str: string ## literal string
of pkFmt:
arg: int ## position argument
fmt: string ## format string
field: string ## field of argument to be accessed
index: int ## array index of argument to be accessed
nested: bool ## true if the argument contains nested formats
const
DefaultPrec = 6 ## Default precision for floating point numbers.
DefaultFmt: Format = (ftDefault, -1, -1, nil, faDefault, fsMinus, false, false, false, nil)
## Default format corresponding to the empty format string, i.e.
## `x.format("") == x.format(DefaultFmt)`.
round_nums = [0.5, 0.05, 0.005, 0.0005, 0.00005, 0.000005, 0.0000005, 0.00000005]
## Rounding offset for floating point numbers up to precision 8.
proc write(s: var string; c: char) =
s.add(c)
proc has(c: Captures; i: range[0..pegs.MaxSubpatterns-1]): bool {.nosideeffect, inline.} =
## Tests whether `c` contains a non-empty capture `i`.
let b = c.bounds(i)
result = b.first <= b.last
proc get(str: string; c: Captures; i: range[0..MaxSubpatterns-1]; def: char): char {.nosideeffect, inline.} =
## If capture `i` is non-empty return that portion of `str` casted
## to `char`, otherwise return `def`.
result = if c.has(i): str[c.bounds(i).first] else: def
proc get(str: string; c: Captures; i: range[0..MaxSubpatterns-1]; def: string; begoff: int = 0): string {.nosideeffect, inline.} =
## If capture `i` is non-empty return that portion of `str` as
## string, otherwise return `def`.
let b = c.bounds(i)
result = if c.has(i): str.substr(b.first + begoff, b.last) else: def
proc get(str: string; c: Captures; i: range[0..MaxSubpatterns-1]; def: int; begoff: int = 0): int {.nosideeffect, inline.} =
## If capture `i` is non-empty return that portion of `str`
## converted to int, otherwise return `def`.
if c.has(i):
discard str.parseInt(result, c.bounds(i).first + begoff)
else:
result = def
proc parse(fmt: string): Format {.nosideeffect.} =
# Converts the format string `fmt` into a `Format` structure.
let p =
sequence(capture(?sequence(anyRune(), &charSet({'<', '>', '=', '^'}))),
capture(?charSet({'<', '>', '=', '^'})),
capture(?charSet({'-', '+', ' '})),
capture(?charSet({'#'})),
capture(?(+digits())),
capture(?charSet({','})),
capture(?sequence(charSet({'.'}), +digits())),
capture(?charSet({'b', 'c', 'd', 'e', 'E', 'f', 'F', 'g', 'G', 'n', 'o', 's', 'x', 'X', '%'})),
capture(?sequence(charSet({'a'}), *pegs.any())))
# let p=peg"{(_&[<>=^])?}{[<>=^]?}{[-+ ]?}{[#]?}{[0-9]+?}{[,]?}{([.][0-9]+)?}{[bcdeEfFgGnosxX%]?}{(a.*)?}"
var caps: Captures
if fmt.rawmatch(p, 0, caps) < 0:
raise newException(FormatError, "Invalid format string")
result.fill = fmt.get(caps, 0, nil)
case fmt.get(caps, 1, 0.char)
of '<': result.align = faLeft
of '>': result.align = faRight
of '^': result.align = faCenter
of '=': result.align = faPadding
else: result.align = faDefault
case fmt.get(caps, 2, '-')
of '-': result.sign = fsMinus
of '+': result.sign = fsPlus
of ' ': result.sign = fsSpace
else: result.sign = fsMinus
result.baseprefix = caps.has(3)
result.width = fmt.get(caps, 4, -1)
if caps.has(4) and fmt[caps.bounds(4).first] == '0':
if result.fill != nil:
raise newException(FormatError, "Leading 0 in with not allowed with explicit fill character")
if result.align != faDefault:
raise newException(FormatError, "Leading 0 in with not allowed with explicit alignment")
result.fill = "0"
result.align = faPadding
result.comma = caps.has(5)
result.precision = fmt.get(caps, 6, -1, 1)
case fmt.get(caps, 7, 0.char)
of 's': result.typ = ftStr
of 'c': result.typ = ftChar
of 'd', 'n': result.typ = ftDec
of 'b': result.typ = ftBin
of 'o': result.typ = ftOct
of 'x': result.typ = ftHex
of 'X': result.typ = ftHex; result.upcase = true
of 'f', 'F': result.typ = ftFix
of 'e': result.typ = ftSci
of 'E': result.typ = ftSci; result.upcase = true
of 'g': result.typ = ftGen
of 'G': result.typ = ftGen; result.upcase = true
of '%': result.typ = ftPercent
else: result.typ = ftDefault
result.arysep = fmt.get(caps, 8, nil, 1)
proc getalign(fmt: Format; defalign: FmtAlign; slen: int) : tuple[left, right:int] {.nosideeffect.} =
## Returns the number of left and right padding characters for a
## given format alignment and width of the object to be printed.
##
## `fmt`
## the format data
## `default`
## if `fmt.align == faDefault`, then this alignment is used
## `slen`
## the width of the object to be printed.
##
## The returned values `(left, right)` will be as minimal as possible
## so that `left + slen + right >= fmt.width`.
result.left = 0
result.right = 0
if (fmt.width >= 0) and (slen < fmt.width):
let alg = if fmt.align == faDefault: defalign else: fmt.align
case alg:
of faLeft: result.right = fmt.width - slen
of faRight, faPadding: result.left = fmt.width - slen
of faCenter:
result.left = (fmt.width - slen) div 2
result.right = fmt.width - slen - result.left
else: discard
proc writefill(o: var Writer; fmt: Format; n: int; signum: int = 0) =
## Write characters for filling. This function also writes the sign
## of a numeric format and handles the padding alignment
## accordingly.
##
## `o`
## output object
## `add`
## output function
## `fmt`
## format to be used (important for padding aligment)
## `n`
## the number of filling characters to be written
## `signum`
## the sign of the number to be written, < 0 negative, > 0 positive, = 0 zero
if fmt.align == faPadding and signum != 0:
if signum < 0: write(o, '-')
elif fmt.sign == fsPlus: write(o, '+')
elif fmt.sign == fsSpace: write(o, ' ')
if fmt.fill == nil:
for i in 1..n: write(o, ' ')
else:
for i in 1..n:
for c in fmt.fill:
write(o, c)
if fmt.align != faPadding and signum != 0:
if signum < 0: write(o, '-')
elif fmt.sign == fsPlus: write(o, '+')
elif fmt.sign == fsSpace: write(o, ' ')
proc writeformat(o: var Writer; s: string; fmt: Format) =
## Write string `s` according to format `fmt` using output object
## `o` and output function `add`.
if fmt.typ notin {ftDefault, ftStr}:
raise newException(FormatError, "String variable must have 's' format type")
# compute alignment
let len = if fmt.precision < 0: runelen(s) else: min(runelen(s), fmt.precision)
var alg = getalign(fmt, faLeft, len)
writefill(o, fmt, alg.left)
var pos = 0
for i in 0..len-1:
let rlen = runeLenAt(s, pos)
for j in pos..pos+rlen-1: write(o, s[j])
pos += rlen
writefill(o, fmt, alg.right)
proc writeformat(o: var Writer; c: char; fmt: Format) =
## Write character `c` according to format `fmt` using output object
## `o` and output function `add`.
if not (fmt.typ in {ftChar, ftDefault}):
raise newException(FormatError, "Character variable must have 'c' format type")
# compute alignment
var alg = getalign(fmt, faLeft, 1)
writefill(o, fmt, alg.left)
write(o, c)
writefill(o, fmt, alg.right)
proc writeformat(o: var Writer; c: Rune; fmt: Format) =
## Write rune `c` according to format `fmt` using output object
## `o` and output function `add`.
if not (fmt.typ in {ftChar, ftDefault}):
raise newException(FormatError, "Character variable must have 'c' format type")
# compute alignment
var alg = getalign(fmt, faLeft, 1)
writefill(o, fmt, alg.left)
let s = c.toUTF8
for c in s: write(o, c)
writefill(o, fmt, alg.right)
proc abs(x: SomeUnsignedInt): SomeUnsignedInt {.inline.} = x
## Return the absolute value of the unsigned int `x`.
proc writeformat(o: var Writer; i: SomeInteger; fmt: Format) =
## Write integer `i` according to format `fmt` using output object
## `o` and output function `add`.
var fmt = fmt
if fmt.typ == ftDefault:
fmt.typ = ftDec
if not (fmt.typ in {ftBin, ftOct, ftHex, ftDec}):
raise newException(FormatError, "Integer variable must of one of the following types: b,o,x,X,d,n")
var base: type(i)
var len = 0
case fmt.typ:
of ftDec:
base = 10
of ftBin:
base = 2
if fmt.baseprefix: len += 2
of ftOct:
base = 8
if fmt.baseprefix: len += 2
of ftHex:
base = 16
if fmt.baseprefix: len += 2
else: assert(false)
if fmt.sign != fsMinus or i < 0: len.inc
var x: type(i) = abs(i)
var irev: type(i) = 0
var ilen = 0
while x > 0.SomeInteger:
len.inc
ilen.inc
irev = irev * base + x mod base
x = x div base
if ilen == 0:
ilen.inc
len.inc
var alg = getalign(fmt, faRight, len)
writefill(o, fmt, alg.left, if i >= 0.SomeInteger: 1 else: -1)
if fmt.baseprefix:
case fmt.typ
of ftBin:
write(o, '0')
write(o, 'b')
of ftOct:
write(o, '0')
write(o, 'o')
of ftHex:
write(o, '0')
write(o, 'x')
else:
raise newException(FormatError, "# only allowed with b, o, x or X")
while ilen > 0:
ilen.dec
let c = irev mod base
irev = irev div base
if c < 10:
write(o, ('0'.int + c.int).char)
elif fmt.upcase:
write(o, ('A'.int + c.int - 10).char)
else:
write(o, ('a'.int + c.int - 10).char)
writefill(o, fmt, alg.right)
proc writeformat(o: var Writer; p: pointer; fmt: Format) =
## Write pointer `i` according to format `fmt` using output object
## `o` and output function `add`.
##
## Pointers are casted to unsigned int and formated as hexadecimal
## with prefix unless specified otherwise.
var f = fmt
if f.typ == 0.char:
f.typ = 'x'
f.baseprefix = true
writeformat(o, add, cast[uint](p), f)
proc writeformat(o: var Writer; x: SomeReal; fmt: Format) =
## Write real number `x` according to format `fmt` using output
## object `o` and output function `add`.
var fmt = fmt
# handle default format
if fmt.typ == ftDefault:
fmt.typ = ftGen
if fmt.precision < 0: fmt.precision = DefaultPrec
if not (fmt.typ in {ftFix, ftSci, ftGen, ftPercent}):
raise newException(FormatError, "Integer variable must of one of the following types: f,F,e,E,g,G,%")
let positive = x >= 0 and classify(x) != fcNegZero
var len = 0
if fmt.sign != fsMinus or not positive: len.inc
var prec = if fmt.precision < 0: DefaultPrec else: fmt.precision
var y = abs(x)
var exp = 0
var numstr, frstr: array[0..31, char]
var numlen, frbeg, frlen = 0
if fmt.typ == ftPercent: y *= 100
case classify(x):
of fcNan:
numstr[0..2] = ['n', 'a', 'n']
numlen = 3
of fcInf, fcNegInf:
numstr[0..2] = ['f', 'n', 'i']
numlen = 3
of fcZero, fcNegZero:
numstr[0] = '0'
numlen = 1
else: # a usual fractional number
if not (fmt.typ in {ftFix, ftPercent}): # not fixed point
exp = int(floor(log10(y)))
if fmt.typ == ftGen:
if prec == 0: prec = 1
if -4 <= exp and exp < prec:
prec = prec-1-exp
exp = 0
else:
prec = prec - 1
len += 4 # exponent
else:
len += 4 # exponent
# shift y so that 1 <= abs(y) < 2
if exp > 0: y /= pow(10.SomeReal, abs(exp).SomeReal)
elif exp < 0: y *= pow(10.SomeReal, abs(exp).SomeReal)
elif fmt.typ == ftPercent:
len += 1 # percent sign
# handle rounding by adding +0.5 * LSB
if prec < len(round_nums): y += round_nums[prec]
# split into integer and fractional part
var mult = 1'i64
for i in 1..prec: mult *= 10
var num = y.int64
var fr = ((y - num.SomeReal) * mult.SomeReal).int64
# build integer part string
while num != 0:
numstr[numlen] = ('0'.int + (num mod 10)).char
numlen.inc
num = num div 10
if numlen == 0:
numstr[0] = '0'
numlen.inc
# build fractional part string
while fr != 0:
frstr[frlen] = ('0'.int + (fr mod 10)).char
frlen.inc
fr = fr div 10
while frlen < prec:
frstr[frlen] = '0'
frlen.inc
# possible remove trailing 0
if fmt.typ == ftGen:
while frbeg < frlen and frstr[frbeg] == '0': frbeg.inc
# update length of string
len += numlen;
if frbeg < frlen:
len += 1 + frlen - frbeg # decimal point and fractional string
let alg = getalign(fmt, faRight, len)
writefill(o, fmt, alg.left, if positive: 1 else: -1)
for i in (numlen-1).countdown(0): write(o, numstr[i])
if frbeg < frlen:
write(o, '.')
for i in (frlen-1).countdown(frbeg): write(o, frstr[i])
if fmt.typ == ftSci or (fmt.typ == ftGen and exp != 0):
write(o, if fmt.upcase: 'E' else: 'e')
if exp >= 0:
write(o, '+')
else:
write(o, '-')
exp = -exp
if exp < 10:
write(o, '0')
write(o, ('0'.int + exp).char)
else:
var i=0
while exp > 0:
numstr[i] = ('0'.int + exp mod 10).char
i+=1
exp = exp div 10
while i>0:
i-=1
write(o, numstr[i])
if fmt.typ == ftPercent: write(o, '%')
writefill(o, fmt, alg.right)
proc writeformat(o: var Writer; b: bool; fmt: Format) =
## Write boolean value `b` according to format `fmt` using output
## object `o`. A boolean may be formatted numerically or as string.
## In the former case true is written as 1 and false as 0, in the
## latter the strings "true" and "false" are shown, respectively.
## The default is string format.
if fmt.typ in {ftStr, ftDefault}:
writeformat(o,
if b: "true"
else: "false",
fmt)
elif fmt.typ in {ftBin, ftOct, ftHex, ftDec}:
writeformat(o,
if b: 1
else: 0,
fmt)
else:
raise newException(FormatError, "Boolean values must of one of the following types: s,b,o,x,X,d,n")
proc writeformat(o: var Writer; ary: openarray[any]; fmt: Format) =
## Write array `ary` according to format `fmt` using output object
## `o` and output function `add`.
if ary.len == 0: return
var sep: string
var nxtfmt = fmt
if fmt.arysep == nil:
sep = "\t"
elif fmt.arysep.len == 0:
sep = ""
else:
let sepch = fmt.arysep[0]
let nxt = 1 + skipUntil(fmt.arysep, sepch, 1)
if nxt >= 1:
nxtfmt.arysep = fmt.arysep.substr(nxt)
sep = fmt.arysep.substr(1, nxt-1)
else:
nxtfmt.arysep = ""
sep = fmt.arysep.substr(1)
writeformat(o, ary[0], nxtfmt)
for i in 1..ary.len-1:
for c in sep: write(o, c)
writeformat(o, ary[i], nxtfmt)
proc addformat[T](o: var Writer; x: T; fmt: Format = DefaultFmt) {.inline.} =
## Write `x` formatted with `fmt` to `o`.
writeformat(o, x, fmt)
proc addformat[T](o: var Writer; x: T; fmt: string) {.inline.} =
## The same as `addformat(o, x, parse(fmt))`.
addformat(o, x, fmt.parse)
proc addformat(s: var string; x: string) {.inline.} =
## Write `x` to `s`. This is a fast specialized version for
## appending unformatted strings.
add(s, x)
proc addformat(f: File; x: string) {.inline.} =
## Write `x` to `f`. This is a fast specialized version for
## writing unformatted strings to a file.
write(f, x)
proc addformat[T](f: File; x: T; fmt: Format = DefaultFmt) {.inline.} =
## Write `x` to file `f` using format `fmt`.
var g = f
writeformat(g, x, fmt)
proc addformat[T](f: File; x: T; fmt: string) {.inline.} =
## Write `x` to file `f` using format string `fmt`. This is the same
## as `addformat(f, x, parse(fmt))`
addformat(f, x, parse(fmt))
proc addformat(s: Stream; x: string) {.inline.} =
## Write `x` to `s`. This is a fast specialized version for
## writing unformatted strings to a stream.
write(s, x)
proc addformat[T](s: Stream; x: T; fmt: Format = DefaultFmt) {.inline.} =
## Write `x` to stream `s` using format `fmt`.
var g = s
writeformat(g, x, fmt)
proc addformat[T](s: Stream; x: T; fmt: string) {.inline.} =
## Write `x` to stream `s` using format string `fmt`. This is the same
## as `addformat(s, x, parse(fmt))`
addformat(s, x, parse(fmt))
proc format[T](x: T; fmt: Format): string =
## Return `x` formatted as a string according to format `fmt`.
result = ""
addformat(result, x, fmt)
proc format[T](x: T; fmt: string): string =
## Return `x` formatted as a string according to format string `fmt`.
result = format(x, fmt.parse)
proc format[T](x: T): string {.inline.} =
## Return `x` formatted as a string according to the default format.
## The default format corresponds to an empty format string.
var fmt {.global.} : Format = DefaultFmt
result = format(x, fmt)
proc unquoted(s: string): string {.compileTime.} =
## Return `s` {{ and }} by single { and }, respectively.
result = ""
var pos = 0
while pos < s.len:
let nxt = pos + skipUntil(s, {'{', '}'})
result.add(s.substr(pos, nxt))
pos = nxt + 2
proc splitfmt(s: string): seq[Part] {.compiletime, nosideeffect.} =
## Split format string `s` into a sequence of "parts".
##
## Each part is either a literal string or a format specification. A
## format specification is a substring of the form
## "{[arg][:format]}" where `arg` is either empty or a number
## refering to the arg-th argument and an additional field or array
## index. The format string is a string accepted by `parse`.
let subpeg = sequence(capture(digits()),
capture(?sequence(charSet({'.'}), *pegs.identStartChars(), *identChars())),
capture(?sequence(charSet({'['}), +digits(), charSet({']'}))),
capture(?sequence(charSet({':'}), *pegs.any())))
result = @[]
var pos = 0
while true:
let oppos = pos + skipUntil(s, {'{', '}'}, pos)
# reached the end
if oppos >= s.len:
if pos < s.len:
result.add(Part(kind: pkStr, str: s.substr(pos).unquoted))
return
# skip double
if oppos + 1 < s.len and s[oppos] == s[oppos+1]:
result.add(Part(kind: pkStr, str: s.substr(pos, oppos)))
pos = oppos + 2
continue
if s[oppos] == '}':
error("Single '}' encountered in format string")
if oppos > pos:
result.add(Part(kind: pkStr, str: s.substr(pos, oppos-1).unquoted))
# find matching closing }
var lvl = 1
var nested = false
pos = oppos
while lvl > 0:
pos.inc
pos = pos + skipUntil(s, {'{', '}'}, pos)
if pos >= s.len:
error("Single '{' encountered in format string")
if s[pos] == '{':
lvl.inc
if lvl == 2:
nested = true
if lvl > 2:
error("Too many nested format levels")
else:
lvl.dec
let clpos = pos
var fmtpart = Part(kind: pkFmt, arg: -1, fmt: s.substr(oppos+1, clpos-1), field: nil, index: int.high, nested: nested)
if fmtpart.fmt.len > 0:
var m: array[0..3, string]
if not fmtpart.fmt.match(subpeg, m):
error("invalid format string")
if m[1] != nil and m[1].len > 0:
fmtpart.field = m[1].substr(1)
if m[2] != nil and m[2].len > 0:
discard parseInt(m[2].substr(1, m[2].len-2), fmtpart.index)
if m[0].len > 0: discard parseInt(m[0], fmtpart.arg)
if m[3] == nil or m[3].len == 0:
fmtpart.fmt = ""
elif m[3][0] == ':':
fmtpart.fmt = m[3].substr(1)
else:
fmtpart.fmt = m[3]
result.add(fmtpart)
pos = clpos + 1
proc literal(s: string): NimNode {.compiletime, nosideeffect.} =
## Return the nim literal of string `s`. This handles the case if
## `s` is nil.
result = if s == nil: newNilLit() else: newLit(s)
proc literal(b: bool): NimNode {.compiletime, nosideeffect.} =
## Return the nim literal of boolean `b`. This is either `true`
## or `false` symbol.
result = if b: "true".ident else: "false".ident
proc literal[T](x: T): NimNode {.compiletime, nosideeffect.} =
## Return the nim literal of value `x`.
when type(x) is enum:
result = ($x).ident
else:
result = newLit(x)
proc generatefmt(fmtstr: string;
args: var openarray[tuple[arg:NimNode, cnt:int]];
arg: var int;): seq[tuple[val, fmt:NimNode]] {.compiletime.} =
## fmtstr
## the format string
## args
## array of expressions for the arguments
## arg
## the number of the next argument for automatic parsing
##
## If arg is < 0 then the functions assumes that explicit numbering
## must be used, otherwise automatic numbering is used starting at
## `arg`. The value of arg is updated according to the number of
## arguments being used. If arg == 0 then automatic and manual
## numbering is not decided (because no explicit manual numbering is
## fixed und no automatically numbered argument has been used so
## far).
##
## The function returns a list of pairs `(val, fmt)` where `val` is
## an expression to be formatted and `fmt` is the format string (or
## Format). Therefore, the resulting string can be generated by
## concatenating expressions `val.format(fmt)`. If `fmt` is `nil`
## then `val` is a (literal) string expression.
try:
result = @[]
for part in splitfmt(fmtstr):
case part.kind
of pkStr: result.add((newLit(part.str), nil))
of pkFmt:
# first compute the argument expression
# start with the correct index
var argexpr : NimNode
if part.arg >= 0:
if arg > 0:
error("Cannot switch from automatic field numbering to manual field specification")
if part.arg >= args.len:
error("Invalid explicit argument index: " & $part.arg)
argexpr = args[part.arg].arg
args[part.arg].cnt = args[part.arg].cnt + 1
arg = -1
else:
if arg < 0:
error("Cannot switch from manual field specification to automatic field numbering")
if arg >= args.len:
error("Too few arguments for format string")
argexpr = args[arg].arg
args[arg].cnt = args[arg].cnt + 1
arg.inc
# possible field access
if part.field != nil and part.field.len > 0:
argexpr = newDotExpr(argexpr, part.field.ident)
# possible array access
if part.index < int.high:
argexpr = newNimNode(nnkBracketExpr).add(argexpr, newLit(part.index))
# now the expression for the format data
var fmtexpr: NimNode
if part.nested:
# nested format string. Compute the format string by
# concatenating the parts of the substring.
for e in generatefmt(part.fmt, args, arg):
var newexpr = if part.fmt == nil: e.val else: newCall(bindsym"format", e.val, e.fmt)
if fmtexpr != nil and fmtexpr.kind != nnkNilLit:
fmtexpr = infix(fmtexpr, "&", newexpr)
else:
fmtexpr = newexpr
else:
# literal format string, precompute the format data
fmtexpr = newNimNode(nnkPar)
for field, val in part.fmt.parse.fieldPairs:
fmtexpr.add(newNimNode(nnkExprColonExpr).add(field.ident, literal(val)))
# add argument
result.add((argexpr, fmtexpr))
finally:
discard
proc addfmtfmt(fmtstr: string; args: NimNode; retvar: NimNode): NimNode {.compileTime.} =
var argexprs = newseq[tuple[arg:NimNode; cnt:int]](args.len)
result = newNimNode(nnkStmtListExpr)
# generate let bindings for arguments
for i in 0..args.len-1:
let argsym = gensym(nskLet, "arg" & $i)
result.add(newLetStmt(argsym, args[i]))
argexprs[i].arg = argsym
# add result values
var arg = 0
for e in generatefmt(fmtstr, argexprs, arg):
if e.fmt == nil or e.fmt.kind == nnkNilLit:
result.add(newCall(bindsym"addformat", retvar, e.val))
else:
result.add(newCall(bindsym"addformat", retvar, e.val, e.fmt))
for i, arg in argexprs:
if arg.cnt == 0:
warning("Argument " & $(i+1) & " `" & args[i].repr & "` is not used in format string")
macro addfmt(s: var string, fmtstr: string{lit}, args: varargs[expr]): expr =
## The same as `s.add(fmtstr.fmt(args...))` but faster.
result = addfmtfmt($fmtstr, args, s)
var s: string = ""
s.addfmt("a:{}", 42)

View File

@@ -0,0 +1,46 @@
discard """
output: '''it's nil
@[1, 2, 3]'''
"""
template foo(s: string = nil) =
if isNil(s):
echo "it's nil"
else:
echo s
foo
# bug #2632
proc takeTup(x: tuple[s: string;x: seq[int]]) =
discard
takeTup(("foo", @[]))
#proc foobar(): () =
proc f(xs: seq[int]) =
discard
proc g(t: tuple[n:int, xs:seq[int]]) =
discard
when isMainModule:
f(@[]) # OK
g((1,@[1])) # OK
g((0,@[])) # NG
# bug #2630
type T = tuple[a: seq[int], b: int]
var t: T = (@[1,2,3], 7)
proc test(s: seq[int]): T =
echo s
(s, 7)
t = test(t.a)

View File

@@ -1,5 +1,13 @@
discard """
output: "1"
output: '''1
foo
bar
baz
foo
bar
baz
yes
no'''
"""
# bug #1708
@@ -24,3 +32,59 @@ when true:
const foo2: seq[string] = @[]
echo foo[0][0][0]
proc takeEmpty(x: openArray[string] = []) = discard
takeEmpty()
takeEmpty([])
proc takeEmpty2(x: openArray[string] = @[]) = discard
takeEmpty2()
takeEmpty2([])
takeEmpty2(@[])
#takeEmpty2([nil])
#rawMessage(errExecutionOfProgramFailed, [])
# bug #2470
const
stuff: seq[string] = @[]
for str in stuff:
echo "str=", str
# bug #1354
proc foo4[T](more: seq[T] = @[]) =
var more2 = more
foo4[int]()
proc maino: int =
var wd: cstring = nil
inc result
discard maino()
proc varargso(a: varargs[string]) =
for x in a:
echo x
varargso(["foo", "bar", "baz"])
varargso("foo", "bar", "baz")
type
Flago = enum
tfNeedsInit, tfNotNil
var s: set[Flago] = {tfNeedsInit}
if {tfNeedsInit, tfNotNil} * s != {}:
echo "yes"
else:
echo "no"
if {tfNeedsInit, tfNotNil} * s <= {tfNotNil}:
echo "yes"
else:
echo "no"

View File

@@ -1,5 +1,11 @@
discard """
output: '''true true false yes'''
output: '''true true false yes
false
false
false
true
true
no'''
"""
proc IsVoid[T](): string =
@@ -28,7 +34,7 @@ no s.items is iterator: float
yes s.items is iterator: TNumber
no s.items is iterator: object
type
type
Iter[T] = iterator: T
yes s.items is Iter[TNumber]
@@ -51,3 +57,34 @@ yes Foo[4, int] is Bar[int]
no Foo[4, int] is Baz[4]
yes Foo[4, float] is Baz[4]
# bug #2505
echo(8'i8 is int32)
# bug #1853
type SeqOrSet[E] = seq[E] or set[E]
type SeqOfInt = seq[int]
type SeqOrSetOfInt = SeqOrSet[int]
# This prints "false", which seems less correct that (1) printing "true" or (2)
# raising a compiler error.
echo seq is SeqOrSet
# This prints "false", as expected.
echo seq is SeqOrSetOfInt
# This prints "true", as expected.
echo SeqOfInt is SeqOrSet
# This causes an internal error (filename: compiler/semtypes.nim, line: 685).
echo SeqOfInt is SeqOrSetOfInt
# bug #2522
proc test[T](x: T) =
when T is typedesc:
echo "yes"
else:
echo "no"
test(7)