mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-28 17:41:45 +00:00
Merge branch 'devel' into jpoirier-realtimeGCTest
This commit is contained in:
@@ -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):
|
||||
|
||||
10
tests/assign/moverload_asgn2.nim
Normal file
10
tests/assign/moverload_asgn2.nim
Normal 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
|
||||
75
tests/assign/toverload_asgn1.nim
Normal file
75
tests/assign/toverload_asgn1.nim
Normal 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
|
||||
22
tests/assign/toverload_asgn2.nim
Normal file
22
tests/assign/toverload_asgn2.nim
Normal 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()
|
||||
@@ -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
|
||||
|
||||
16
tests/async/tasynctry2.nim
Normal file
16
tests/async/tasynctry2.nim
Normal 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
|
||||
@@ -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
|
||||
|
||||
|
||||
15
tests/ccgbugs/tarray_equality.nim
Normal file
15
tests/ccgbugs/tarray_equality.nim
Normal 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
|
||||
20
tests/ccgbugs/tpartialcs.nim
Normal file
20
tests/ccgbugs/tpartialcs.nim
Normal 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()
|
||||
@@ -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.} =
|
||||
|
||||
19
tests/collections/tcounttable.nim
Normal file
19
tests/collections/tcounttable.nim
Normal 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"
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
17
tests/cpp/tcppraise.nim
Normal 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"
|
||||
23
tests/cpp/tget_subsystem.nim
Normal file
23
tests/cpp/tget_subsystem.nim
Normal 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]()
|
||||
|
||||
19
tests/cpp/tvector_iterator.nim
Normal file
19
tests/cpp/tvector_iterator.nim
Normal 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
38
tests/cpp/tvectorseq.nim
Normal 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)
|
||||
@@ -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",
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
20
tests/distinct/tdistinct_consts.nim
Normal file
20
tests/distinct/tdistinct_consts.nim
Normal 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])
|
||||
@@ -1,5 +1,5 @@
|
||||
discard """
|
||||
line: 16
|
||||
line: 17
|
||||
errormsg: "'mainUnsafe' is not GC-safe"
|
||||
cmd: "nim $target --hints:on --threads:on $options $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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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!
|
||||
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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!")
|
||||
|
||||
@@ -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!":
|
||||
|
||||
21
tests/generics/twrong_generic_object.nim
Normal file
21
tests/generics/twrong_generic_object.nim
Normal 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)
|
||||
@@ -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
24
tests/js/tstringitems.nim
Normal 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()
|
||||
@@ -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
16
tests/macros/tlexerex.nim
Normal 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"
|
||||
12
tests/macros/treturnsempty.nim
Normal file
12
tests/macros/treturnsempty.nim
Normal 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)
|
||||
|
||||
@@ -15,5 +15,6 @@ const
|
||||
valid = 45
|
||||
a = test("foo&&")
|
||||
b = test("valid")
|
||||
c = test("\"") # bug #2504
|
||||
|
||||
echo a, " ", b
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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.}
|
||||
|
||||
@@ -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
10
tests/misc/tcharinc.nim
Normal file
@@ -0,0 +1,10 @@
|
||||
discard """
|
||||
output: "1"
|
||||
"""
|
||||
|
||||
var c = '\0'
|
||||
while true:
|
||||
if c == '\xFF': break
|
||||
inc c
|
||||
|
||||
echo "1"
|
||||
@@ -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()
|
||||
@@ -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")
|
||||
@@ -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")
|
||||
@@ -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
|
||||
|
||||
14
tests/misc/tunsignedinc.nim
Normal file
14
tests/misc/tunsignedinc.nim
Normal 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
|
||||
7
tests/objects/tillegal_recursion.nim
Normal file
7
tests/objects/tillegal_recursion.nim
Normal file
@@ -0,0 +1,7 @@
|
||||
discard """
|
||||
errormsg: "illegal recursion in type 'object'"
|
||||
line: 7
|
||||
"""
|
||||
# bug #1691
|
||||
type
|
||||
Foo = ref object of Foo
|
||||
15
tests/objects/tobjloop.nim
Normal file
15
tests/objects/tobjloop.nim
Normal 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)
|
||||
19
tests/objects/trefobjsyntax2.nim
Normal file
19
tests/objects/trefobjsyntax2.nim
Normal 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)
|
||||
@@ -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
|
||||
|
||||
38
tests/overload/tstmtoverload.nim
Normal file
38
tests/overload/tstmtoverload.nim
Normal 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
|
||||
39
tests/parallel/tgc_unsafe2.nim
Normal file
39
tests/parallel/tgc_unsafe2.nim
Normal 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()
|
||||
53
tests/parallel/twrong_refcounts.nim
Normal file
53
tests/parallel/twrong_refcounts.nim
Normal 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()
|
||||
12
tests/parser/tinvcolonlocation1.nim
Normal file
12
tests/parser/tinvcolonlocation1.nim
Normal 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"
|
||||
15
tests/parser/tinvcolonlocation2.nim
Normal file
15
tests/parser/tinvcolonlocation2.nim
Normal 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"
|
||||
12
tests/parser/tinvcolonlocation3.nim
Normal file
12
tests/parser/tinvcolonlocation3.nim
Normal 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"
|
||||
@@ -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
|
||||
|
||||
35
tests/parser/ttupleunpack.nim
Normal file
35
tests/parser/ttupleunpack.nim
Normal 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()
|
||||
@@ -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
|
||||
|
||||
@@ -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
9
tests/stdlib/treloop.nim
Normal file
@@ -0,0 +1,9 @@
|
||||
discard """
|
||||
output: "@[(, +, 1, 2, )]"
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
let str = "(+ 1 2)"
|
||||
var tokenRE = re"""[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)"""
|
||||
echo str.findAll(tokenRE)
|
||||
14
tests/template/tdefault_nil.nim
Normal file
14
tests/template/tdefault_nil.nim
Normal 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
|
||||
30
tests/template/tstmt_semchecked_twice.nim
Normal file
30
tests/template/tstmt_semchecked_twice.nim
Normal 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)
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
10
tests/tuples/tuint_tuple.nim
Normal file
10
tests/tuples/tuint_tuple.nim
Normal 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)
|
||||
]
|
||||
|
||||
766
tests/tuples/tuple_with_nil.nim
Normal file
766
tests/tuples/tuple_with_nil.nim
Normal 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)
|
||||
46
tests/tuples/tuple_with_seq.nim
Normal file
46
tests/tuples/tuple_with_seq.nim
Normal 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)
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user