From 4396270fc7c447fa7ce9478a6bf9682ba7c496a7 Mon Sep 17 00:00:00 2001 From: Miguel Date: Sun, 22 Dec 2013 20:56:33 +0400 Subject: [PATCH 01/25] 'Connection' argument in 'Open' was not used, so MySQL host and port were always default ones. Now 'Connection' is treated as 'host:port'. --- lib/impure/db_mysql.nim | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/impure/db_mysql.nim b/lib/impure/db_mysql.nim index 91cf8a5eb..c27be2817 100644 --- a/lib/impure/db_mysql.nim +++ b/lib/impure/db_mysql.nim @@ -194,9 +194,15 @@ proc Open*(connection, user, password, database: string): TDbConn {. ## opens a database connection. Raises `EDb` if the connection could not ## be established. result = mysql.Init(nil) - if result == nil: dbError("could not open database connection") - if mysql.RealConnect(result, "", user, password, database, - 0'i32, nil, 0) == nil: + if result == nil: dbError("could not open database connection") + var + cnctn = connection.split(':') + host = cnctn[0] + port: int32 = 3306 + if cnctn.len > 1: + port = int32((cnctn[1]).parseInt()) + if mysql.RealConnect(result, host, user, password, database, + port, nil, 0) == nil: var errmsg = $mysql.error(result) db_mysql.Close(result) dbError(errmsg) From 51d2384e1aa890b243f14a80ae2a126308a37d9f Mon Sep 17 00:00:00 2001 From: Miguel Date: Mon, 10 Feb 2014 18:41:39 +0400 Subject: [PATCH 02/25] Fix for db_mysql.Open. 'Connection' argument in 'Open' was not used, so MySQL host and port were always default ones. Now 'Connection' is treated as 'host:port'. --- lib/impure/db_mysql.nim | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/impure/db_mysql.nim b/lib/impure/db_mysql.nim index 1489a0401..32cda3e4d 100644 --- a/lib/impure/db_mysql.nim +++ b/lib/impure/db_mysql.nim @@ -87,7 +87,7 @@ proc newRow(L: int): TRow = proc properFreeResult(sqlres: mysql.PRES, row: cstringArray) = if row != nil: - while mysql.FetchRow(sqlres) != nil: nil + while mysql.FetchRow(sqlres) != nil: discard mysql.FreeResult(sqlres) iterator fastRows*(db: TDbConn, query: TSqlQuery, @@ -194,13 +194,13 @@ proc open*(connection, user, password, database: string): TDbConn {. ## opens a database connection. Raises `EDb` if the connection could not ## be established. result = mysql.Init(nil) - if result == nil: dbError("could not open database connection") - var - cnctn = connection.split(':') - host = cnctn[0] - port: int32 = 3306 - if cnctn.len > 1: - port = int32((cnctn[1]).parseInt()) + if result == nil: dbError("could not open database connection") + let + colonPos = connection.find(':') + host = if colonPos < 0: connection + else: substr(connection, 0, colonPos-1) + port: int32 = if colonPos < 0: 0'i32 + else: substr(connection, colonPos+1).parseInt.int32 if mysql.RealConnect(result, host, user, password, database, port, nil, 0) == nil: var errmsg = $mysql.error(result) From 3ae21ea48e5f61ccf757bc3588c3124e2b2899b3 Mon Sep 17 00:00:00 2001 From: EXetoC Date: Fri, 7 Mar 2014 00:09:23 +0100 Subject: [PATCH 03/25] Better names. --- lib/system.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index 171c7b6b8..de918c78b 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1195,7 +1195,7 @@ when not defined(nimrodVM): ## be freed with ``dealloc``. ## The allocated memory belongs to its allocating thread! ## Use `reallocShared` to reallocate from a shared heap. - proc reallocType*[T](p: ptr T, newSize: int): ptr T {.inline.} = + proc resize*[T](p: ptr T, newSize: int): ptr T {.inline.} = ## grows or shrinks a given memory block. If p is **nil** then a new ## memory block is returned. In either way the block has at least ## ``T.sizeof * newSize`` bytes. If ``newSize == 0`` and p is not @@ -1244,7 +1244,7 @@ when not defined(nimrodVM): ## least ``newSize`` bytes. If ``newSize == 0`` and p is not **nil** ## ``reallocShared`` calls ``deallocShared(p)``. In other cases the ## block has to be freed with ``deallocShared``. - proc reallocSharedType*[T](p: ptr T, newSize: int): ptr T {.inline.} = + proc resizeShared*[T](p: ptr T, newSize: int): ptr T {.inline.} = ## grows or shrinks a given memory block on the heap. If p is **nil** ## then a new memory block is returned. In either way the block has at ## least ``T.sizeof * newSize`` bytes. If ``newSize == 0`` and p is From 90e326504b077bc0a233642e121cd8ea3155d637 Mon Sep 17 00:00:00 2001 From: EXetoC Date: Fri, 7 Mar 2014 00:09:43 +0100 Subject: [PATCH 04/25] Update test with new names. --- tests/system/alloc.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/system/alloc.nim b/tests/system/alloc.nim index 665b448ac..3a10a1a39 100644 --- a/tests/system/alloc.nim +++ b/tests/system/alloc.nim @@ -16,7 +16,7 @@ assert cast[ptr array[4, int]](x)[3] == 0 x = cast[ptr int](x.realloc(2)) assert x != nil -x = x.reallocType(4) +x = x.resize(4) assert x != nil x.dealloc() @@ -37,9 +37,9 @@ assert cast[ptr array[3, int]](x)[2] == 0 x = cast[ptr int](reallocShared(x, 2)) assert x != nil -x = reallocType(x, 12) +x = resize(x, 12) assert x != nil -x = reallocSharedType(x, 1) +x = resizeShared(x, 1) assert x != nil x.deallocShared() From 5e78baa061f36900b28018b6b0c47e4f45dc92cf Mon Sep 17 00:00:00 2001 From: EXetoC Date: Fri, 7 Mar 2014 00:34:44 +0100 Subject: [PATCH 05/25] Use separate names for type-based allocation procs rather than overloading. --- lib/system.nim | 49 +++++++++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index de918c78b..0ae141241 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1164,13 +1164,13 @@ when not defined(nimrodVM): ## from it before writing to it is undefined behaviour! ## The allocated memory belongs to its allocating thread! ## Use `allocShared` to allocate from a shared heap. - proc alloc*(T: typedesc, size = 1): ptr T {.inline.} = + proc create*(T: typedesc, size = 1): ptr T {.inline.} = ## allocates a new memory block with at least ``T.sizeof * size`` - ## bytes. The block has to be freed with ``realloc(block, 0)`` or - ## ``dealloc(block)``. The block is not initialized, so reading + ## bytes. The block has to be freed with ``resize(block, 0)`` or + ## ``free(block)``. The block is not initialized, so reading ## from it before writing to it is undefined behaviour! ## The allocated memory belongs to its allocating thread! - ## Use `allocShared` to allocate from a shared heap. + ## Use `createShared` to allocate from a shared heap. cast[ptr T](alloc(T.sizeof * size)) proc alloc0*(size: int): pointer {.noconv, rtl, tags: [].} ## allocates a new memory block with at least ``size`` bytes. The @@ -1179,13 +1179,13 @@ when not defined(nimrodVM): ## containing zero, so it is somewhat safer than ``alloc``. ## The allocated memory belongs to its allocating thread! ## Use `allocShared0` to allocate from a shared heap. - proc alloc0*(T: typedesc, size = 1): ptr T {.inline.} = + proc create0*(T: typedesc, size = 1): ptr T {.inline.} = ## allocates a new memory block with at least ``T.sizeof * size`` - ## bytes. The block has to be freed with ``realloc(block, 0)`` or - ## ``dealloc(block)``. The block is initialized with all bytes - ## containing zero, so it is somewhat safer than ``alloc``. + ## bytes. The block has to be freed with ``resize(block, 0)`` or + ## ``free(block)``. The block is initialized with all bytes + ## containing zero, so it is somewhat safer than ``create``. ## The allocated memory belongs to its allocating thread! - ## Use `allocShared0` to allocate from a shared heap. + ## Use `createShared0` to allocate from a shared heap. cast[ptr T](alloc0(T.sizeof * size)) proc realloc*(p: pointer, newSize: int): pointer {.noconv, rtl, tags: [].} ## grows or shrinks a given memory block. If p is **nil** then a new @@ -1199,10 +1199,10 @@ when not defined(nimrodVM): ## grows or shrinks a given memory block. If p is **nil** then a new ## memory block is returned. In either way the block has at least ## ``T.sizeof * newSize`` bytes. If ``newSize == 0`` and p is not - ## **nil** ``realloc`` calls ``dealloc(p)``. In other cases the block - ## has to be freed with ``dealloc``. The allocated memory belongs to + ## **nil** ``resize`` calls ``free(p)``. In other cases the block + ## has to be freed with ``free``. The allocated memory belongs to ## its allocating thread! - ## Use `reallocShared` to reallocate from a shared heap. + ## Use `resizeShared` to reallocate from a shared heap. cast[ptr T](realloc(p, T.sizeof * newSize)) proc dealloc*(p: pointer) {.noconv, rtl, tags: [].} ## frees the memory allocated with ``alloc``, ``alloc0`` or @@ -1212,16 +1212,18 @@ when not defined(nimrodVM): ## or other memory may be corrupted. ## The freed memory must belong to its allocating thread! ## Use `deallocShared` to deallocate from a shared heap. + proc free*[T](p: ptr T) {.inline.} = + dealloc(p) proc allocShared*(size: int): pointer {.noconv, rtl.} ## allocates a new memory block on the shared heap with at ## least ``size`` bytes. The block has to be freed with ## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block ## is not initialized, so reading from it before writing to it is ## undefined behaviour! - proc allocShared*(T: typedesc, size: int): ptr T {.inline.} = + proc createShared*(T: typedesc, size: int): ptr T {.inline.} = ## allocates a new memory block on the shared heap with at ## least ``T.sizeof * size`` bytes. The block has to be freed with - ## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block + ## ``resizeShared(block, 0)`` or ``freeShared(block)``. The block ## is not initialized, so reading from it before writing to it is ## undefined behaviour! cast[ptr T](allocShared(T.sizeof * size)) @@ -1231,13 +1233,13 @@ when not defined(nimrodVM): ## ``reallocShared(block, 0)`` or ``deallocShared(block)``. ## The block is initialized with all bytes ## containing zero, so it is somewhat safer than ``allocShared``. - proc allocShared0*(T: typedesc, size: int): ptr T {.inline.} = + proc createShared0*(T: typedesc, size: int): ptr T {.inline.} = ## allocates a new memory block on the shared heap with at ## least ``T.sizeof * size`` bytes. The block has to be freed with - ## ``reallocShared(block, 0)`` or ``deallocShared(block)``. + ## ``resizeShared(block, 0)`` or ``freeShared(block)``. ## The block is initialized with all bytes - ## containing zero, so it is somewhat safer than ``allocShared``. - cast[ptr T](allocShared(T.sizeof * size)) + ## containing zero, so it is somewhat safer than ``createShared``. + cast[ptr T](allocShared0(T.sizeof * size)) proc reallocShared*(p: pointer, newSize: int): pointer {.noconv, rtl.} ## grows or shrinks a given memory block on the heap. If p is **nil** ## then a new memory block is returned. In either way the block has at @@ -1248,8 +1250,8 @@ when not defined(nimrodVM): ## grows or shrinks a given memory block on the heap. If p is **nil** ## then a new memory block is returned. In either way the block has at ## least ``T.sizeof * newSize`` bytes. If ``newSize == 0`` and p is - ## not **nil** ``reallocShared`` calls ``deallocShared(p)``. In other - ## cases the block has to be freed with ``deallocShared``. + ## not **nil** ``resizeShared`` calls ``freeShared(p)``. In other + ## cases the block has to be freed with ``freeShared``. cast[ptr T](reallocShared(p, T.sizeof * newSize)) proc deallocShared*(p: pointer) {.noconv, rtl.} ## frees the memory allocated with ``allocShared``, ``allocShared0`` or @@ -1257,6 +1259,13 @@ when not defined(nimrodVM): ## free the memory a leak occurs; if one tries to access freed ## memory (or just freeing it twice!) a core dump may happen ## or other memory may be corrupted. + proc freeShared*[T](p: ptr T) {.inline.} = + ## frees the memory allocated with ``createShared``, ``createShared0`` or + ## ``resizeShared``. This procedure is dangerous! If one forgets to + ## free the memory a leak occurs; if one tries to access freed + ## memory (or just freeing it twice!) a core dump may happen + ## or other memory may be corrupted. + deallocShared(p) proc swap*[T](a, b: var T) {.magic: "Swap", noSideEffect.} ## swaps the values `a` and `b`. This is often more efficient than From 61e5435081069792dd027a1f127cba836af1ed20 Mon Sep 17 00:00:00 2001 From: EXetoC Date: Fri, 7 Mar 2014 00:36:58 +0100 Subject: [PATCH 06/25] Update unit test. --- tests/system/alloc.nim | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/system/alloc.nim b/tests/system/alloc.nim index 3a10a1a39..f8e14ac04 100644 --- a/tests/system/alloc.nim +++ b/tests/system/alloc.nim @@ -3,11 +3,11 @@ var x: ptr int x = cast[ptr int](alloc(7)) assert x != nil -x = alloc(int, 3) +x = create(int, 3) assert x != nil x.dealloc() -x = alloc0(int, 4) +x = create0(int, 4) assert cast[ptr array[4, int]](x)[0] == 0 assert cast[ptr array[4, int]](x)[1] == 0 assert cast[ptr array[4, int]](x)[2] == 0 @@ -18,28 +18,28 @@ assert x != nil x = x.resize(4) assert x != nil -x.dealloc() +x.free() x = cast[ptr int](allocShared(100)) assert x != nil deallocShared(x) -x = allocShared(int, 3) +x = createShared(int, 3) assert x != nil -x.deallocShared() +x.freeShared() -x = allocShared0(int, 3) +x = createShared0(int, 3) assert x != nil assert cast[ptr array[3, int]](x)[0] == 0 assert cast[ptr array[3, int]](x)[1] == 0 assert cast[ptr array[3, int]](x)[2] == 0 -x = cast[ptr int](reallocShared(x, 2)) +x = cast[ptr int](x.resizeShared(2)) assert x != nil -x = resize(x, 12) +x = x.resize(12) assert x != nil -x = resizeShared(x, 1) +x = x.resizeShared(1) assert x != nil -x.deallocShared() +x.freeShared() From 5b7e44f0aaab8e47e11de029924439175f4ad0bd Mon Sep 17 00:00:00 2001 From: EXetoC Date: Fri, 7 Mar 2014 01:00:18 +0100 Subject: [PATCH 07/25] create -> createU, create0 -> create. --- lib/system.nim | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index 0ae141241..953aa3bce 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1164,13 +1164,13 @@ when not defined(nimrodVM): ## from it before writing to it is undefined behaviour! ## The allocated memory belongs to its allocating thread! ## Use `allocShared` to allocate from a shared heap. - proc create*(T: typedesc, size = 1): ptr T {.inline.} = + proc createU*(T: typedesc, size = 1): ptr T {.inline.} = ## allocates a new memory block with at least ``T.sizeof * size`` ## bytes. The block has to be freed with ``resize(block, 0)`` or ## ``free(block)``. The block is not initialized, so reading ## from it before writing to it is undefined behaviour! ## The allocated memory belongs to its allocating thread! - ## Use `createShared` to allocate from a shared heap. + ## Use `createSharedU` to allocate from a shared heap. cast[ptr T](alloc(T.sizeof * size)) proc alloc0*(size: int): pointer {.noconv, rtl, tags: [].} ## allocates a new memory block with at least ``size`` bytes. The @@ -1179,13 +1179,13 @@ when not defined(nimrodVM): ## containing zero, so it is somewhat safer than ``alloc``. ## The allocated memory belongs to its allocating thread! ## Use `allocShared0` to allocate from a shared heap. - proc create0*(T: typedesc, size = 1): ptr T {.inline.} = + proc create*(T: typedesc, size = 1): ptr T {.inline.} = ## allocates a new memory block with at least ``T.sizeof * size`` ## bytes. The block has to be freed with ``resize(block, 0)`` or ## ``free(block)``. The block is initialized with all bytes - ## containing zero, so it is somewhat safer than ``create``. + ## containing zero, so it is somewhat safer than ``createU``. ## The allocated memory belongs to its allocating thread! - ## Use `createShared0` to allocate from a shared heap. + ## Use `createShared` to allocate from a shared heap. cast[ptr T](alloc0(T.sizeof * size)) proc realloc*(p: pointer, newSize: int): pointer {.noconv, rtl, tags: [].} ## grows or shrinks a given memory block. If p is **nil** then a new @@ -1220,7 +1220,7 @@ when not defined(nimrodVM): ## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block ## is not initialized, so reading from it before writing to it is ## undefined behaviour! - proc createShared*(T: typedesc, size: int): ptr T {.inline.} = + proc createSharedU*(T: typedesc, size: int): ptr T {.inline.} = ## allocates a new memory block on the shared heap with at ## least ``T.sizeof * size`` bytes. The block has to be freed with ## ``resizeShared(block, 0)`` or ``freeShared(block)``. The block @@ -1233,12 +1233,12 @@ when not defined(nimrodVM): ## ``reallocShared(block, 0)`` or ``deallocShared(block)``. ## The block is initialized with all bytes ## containing zero, so it is somewhat safer than ``allocShared``. - proc createShared0*(T: typedesc, size: int): ptr T {.inline.} = + proc createShared*(T: typedesc, size: int): ptr T {.inline.} = ## allocates a new memory block on the shared heap with at ## least ``T.sizeof * size`` bytes. The block has to be freed with ## ``resizeShared(block, 0)`` or ``freeShared(block)``. ## The block is initialized with all bytes - ## containing zero, so it is somewhat safer than ``createShared``. + ## containing zero, so it is somewhat safer than ``createSharedU``. cast[ptr T](allocShared0(T.sizeof * size)) proc reallocShared*(p: pointer, newSize: int): pointer {.noconv, rtl.} ## grows or shrinks a given memory block on the heap. If p is **nil** @@ -1260,7 +1260,7 @@ when not defined(nimrodVM): ## memory (or just freeing it twice!) a core dump may happen ## or other memory may be corrupted. proc freeShared*[T](p: ptr T) {.inline.} = - ## frees the memory allocated with ``createShared``, ``createShared0`` or + ## frees the memory allocated with ``createShared``, ``createSharedU`` or ## ``resizeShared``. This procedure is dangerous! If one forgets to ## free the memory a leak occurs; if one tries to access freed ## memory (or just freeing it twice!) a core dump may happen From c7b83d2c44626cd90d0d83ed2684c120e1490283 Mon Sep 17 00:00:00 2001 From: EXetoC Date: Fri, 7 Mar 2014 01:09:16 +0100 Subject: [PATCH 08/25] Update unit test. --- tests/system/alloc.nim | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/tests/system/alloc.nim b/tests/system/alloc.nim index f8e14ac04..7abefec2a 100644 --- a/tests/system/alloc.nim +++ b/tests/system/alloc.nim @@ -2,20 +2,20 @@ var x: ptr int x = cast[ptr int](alloc(7)) assert x != nil - -x = create(int, 3) +x = cast[ptr int](x.realloc(2)) assert x != nil x.dealloc() -x = create0(int, 4) +x = createU(int, 3) +assert x != nil +x.free() + +x = create(int, 4) assert cast[ptr array[4, int]](x)[0] == 0 assert cast[ptr array[4, int]](x)[1] == 0 assert cast[ptr array[4, int]](x)[2] == 0 assert cast[ptr array[4, int]](x)[3] == 0 -x = cast[ptr int](x.realloc(2)) -assert x != nil - x = x.resize(4) assert x != nil x.free() @@ -24,22 +24,29 @@ x = cast[ptr int](allocShared(100)) assert x != nil deallocShared(x) -x = createShared(int, 3) +x = createSharedU(int, 3) assert x != nil x.freeShared() -x = createShared0(int, 3) +x = createShared(int, 3) assert x != nil assert cast[ptr array[3, int]](x)[0] == 0 assert cast[ptr array[3, int]](x)[1] == 0 assert cast[ptr array[3, int]](x)[2] == 0 +assert x != nil x = cast[ptr int](x.resizeShared(2)) assert x != nil +x.freeShared() +x = create(int, 10) +assert x != nil x = x.resize(12) assert x != nil +x.dealloc() +x = createShared(int, 1) +assert x != nil x = x.resizeShared(1) assert x != nil x.freeShared() From 3147f7f6c2c8fc62d04d5b449df093f113935487 Mon Sep 17 00:00:00 2001 From: EXetoC Date: Fri, 7 Mar 2014 01:32:07 +0100 Subject: [PATCH 09/25] Use 'Natural' or 'Positive' instead of 'int' where applicable. --- lib/system.nim | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index 953aa3bce..24ad50f97 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1164,7 +1164,7 @@ when not defined(nimrodVM): ## from it before writing to it is undefined behaviour! ## The allocated memory belongs to its allocating thread! ## Use `allocShared` to allocate from a shared heap. - proc createU*(T: typedesc, size = 1): ptr T {.inline.} = + proc createU*(T: typedesc, size = 1.Positive): ptr T {.inline.} = ## allocates a new memory block with at least ``T.sizeof * size`` ## bytes. The block has to be freed with ``resize(block, 0)`` or ## ``free(block)``. The block is not initialized, so reading @@ -1179,7 +1179,7 @@ when not defined(nimrodVM): ## containing zero, so it is somewhat safer than ``alloc``. ## The allocated memory belongs to its allocating thread! ## Use `allocShared0` to allocate from a shared heap. - proc create*(T: typedesc, size = 1): ptr T {.inline.} = + proc create*(T: typedesc, size = 1.Positive): ptr T {.inline.} = ## allocates a new memory block with at least ``T.sizeof * size`` ## bytes. The block has to be freed with ``resize(block, 0)`` or ## ``free(block)``. The block is initialized with all bytes @@ -1195,7 +1195,7 @@ when not defined(nimrodVM): ## be freed with ``dealloc``. ## The allocated memory belongs to its allocating thread! ## Use `reallocShared` to reallocate from a shared heap. - proc resize*[T](p: ptr T, newSize: int): ptr T {.inline.} = + proc resize*[T](p: ptr T, newSize: Natural): ptr T {.inline.} = ## grows or shrinks a given memory block. If p is **nil** then a new ## memory block is returned. In either way the block has at least ## ``T.sizeof * newSize`` bytes. If ``newSize == 0`` and p is not @@ -1220,7 +1220,7 @@ when not defined(nimrodVM): ## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block ## is not initialized, so reading from it before writing to it is ## undefined behaviour! - proc createSharedU*(T: typedesc, size: int): ptr T {.inline.} = + proc createSharedU*(T: typedesc, size = 1.Positive): ptr T {.inline.} = ## allocates a new memory block on the shared heap with at ## least ``T.sizeof * size`` bytes. The block has to be freed with ## ``resizeShared(block, 0)`` or ``freeShared(block)``. The block @@ -1233,7 +1233,7 @@ when not defined(nimrodVM): ## ``reallocShared(block, 0)`` or ``deallocShared(block)``. ## The block is initialized with all bytes ## containing zero, so it is somewhat safer than ``allocShared``. - proc createShared*(T: typedesc, size: int): ptr T {.inline.} = + proc createShared*(T: typedesc, size = 1.Positive): ptr T {.inline.} = ## allocates a new memory block on the shared heap with at ## least ``T.sizeof * size`` bytes. The block has to be freed with ## ``resizeShared(block, 0)`` or ``freeShared(block)``. @@ -1246,7 +1246,7 @@ when not defined(nimrodVM): ## least ``newSize`` bytes. If ``newSize == 0`` and p is not **nil** ## ``reallocShared`` calls ``deallocShared(p)``. In other cases the ## block has to be freed with ``deallocShared``. - proc resizeShared*[T](p: ptr T, newSize: int): ptr T {.inline.} = + proc resizeShared*[T](p: ptr T, newSize: Natural): ptr T {.inline.} = ## grows or shrinks a given memory block on the heap. If p is **nil** ## then a new memory block is returned. In either way the block has at ## least ``T.sizeof * newSize`` bytes. If ``newSize == 0`` and p is From 71de5ea909ea16463a985f077a960153f9adc9db Mon Sep 17 00:00:00 2001 From: Clay Sweetser Date: Fri, 7 Mar 2014 17:50:57 -0500 Subject: [PATCH 10/25] Tester now outputs all the test results of the current test run to json. --- tests/testament/htmlgen.nim | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/testament/htmlgen.nim b/tests/testament/htmlgen.nim index 74d8811b8..93e3a4270 100644 --- a/tests/testament/htmlgen.nim +++ b/tests/testament/htmlgen.nim @@ -174,6 +174,10 @@ proc generateJson*(filename: string, commit: int) = on A.name = B.name and A.category = B.category where A.[commit] = ? and B.[commit] = ? and A.machine = ? and A.result != B.result""" + selResults = """select + name, category, target, action, result, expected, given + from TestResult + where [commit] = ?""" var db = open(connection="testament.db", user="testament", password="", database="testament") let lastCommit = db.getCommit(commit) @@ -189,6 +193,21 @@ proc generateJson*(filename: string, commit: int) = outfile.writeln("""{"total": $#, "passed": $#, "skipped": $#""" % data) + let results = newJArray() + for row in db.rows(sql(selResults), lastCommit): + echo(repr(row)) + var obj = newJObject() + obj["name"] = %row[0] + obj["category"] = %row[1] + obj["target"] = %row[2] + obj["action"] = %row[3] + obj["result"] = %row[4] + obj["expected"] = %row[5] + obj["given"] = %row[6] + results.add(obj) + outfile.writeln(""", "results": """) + outfile.write(results.pretty) + if not previousCommit.isNil: let diff = newJArray() From 5f19af9e01bf30b1b28c410377f919e02fc6f1cc Mon Sep 17 00:00:00 2001 From: Clay Sweetser Date: Sat, 8 Mar 2014 14:30:05 -0500 Subject: [PATCH 11/25] Removed debug code --- tests/testament/htmlgen.nim | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/testament/htmlgen.nim b/tests/testament/htmlgen.nim index 93e3a4270..89d56c693 100644 --- a/tests/testament/htmlgen.nim +++ b/tests/testament/htmlgen.nim @@ -195,7 +195,6 @@ proc generateJson*(filename: string, commit: int) = let results = newJArray() for row in db.rows(sql(selResults), lastCommit): - echo(repr(row)) var obj = newJObject() obj["name"] = %row[0] obj["category"] = %row[1] From 085b339b8b12267cb8ed555979db368e151c9ca4 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sat, 8 Mar 2014 22:57:06 +0200 Subject: [PATCH 12/25] implements higher-order inline iterators and return type inference for iterators --- compiler/msgs.nim | 6 +++-- compiler/semexprs.nim | 16 ++++++++++++-- compiler/seminst.nim | 2 +- compiler/semstmts.nim | 18 ++++++++------- compiler/semtypes.nim | 28 ++++++++++++++++++----- compiler/semtypinst.nim | 7 +++++- compiler/sigmatch.nim | 19 +++++++++++++--- compiler/transf.nim | 12 +++++----- tests/iter/tchainediterators.nim | 38 ++++++++++++++++++++++++++++++++ 9 files changed, 119 insertions(+), 27 deletions(-) create mode 100644 tests/iter/tchainediterators.nim diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 66763e7f5..5bc490d14 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -96,8 +96,8 @@ type errOnlyACallOpCanBeDelegator, errUsingNoSymbol, errMacroBodyDependsOnGenericTypes, errDestructorNotGenericEnough, - - errXExpectsTwoArguments, + errInlineIteratorsAsProcParams, + errXExpectsTwoArguments, errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations, errCannotInterpretNodeX, errFieldXNotFound, errInvalidConversionFromTypeX, errAssertionFailed, errCannotGenerateCodeForX, errXRequiresOneArgument, @@ -331,6 +331,8 @@ const "because the parameter '$1' has a generic type", errDestructorNotGenericEnough: "Destructor signarue is too specific. " & "A destructor must be associated will all instantiations of a generic type", + errInlineIteratorsAsProcParams: "inline iterators can be used as parameters only for " & + "templates, macros and other inline iterators", errXExpectsTwoArguments: "\'$1\' expects two arguments", errXExpectsObjectTypes: "\'$1\' expects object types", errXcanNeverBeOfThisSubtype: "\'$1\' can never be of this subtype", diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 203a51816..c16ab9b87 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1119,6 +1119,9 @@ proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} = n.sons[0] = x # 'result[]' --> 'result' n.sons[1] = takeImplicitAddr(c, ri) +template resultTypeIsInferrable(typ: PType): expr = + typ.isMetaType and typ.kind != tyTypeDesc + proc semAsgn(c: PContext, n: PNode): PNode = checkSonsLen(n, 2) var a = n.sons[0] @@ -1170,7 +1173,7 @@ proc semAsgn(c: PContext, n: PNode): PNode = if lhsIsResult: {efAllowDestructor} else: {}) if lhsIsResult: n.typ = enforceVoidContext - if lhs.sym.typ.isMetaType and lhs.sym.typ.kind != tyTypeDesc: + if resultTypeIsInferrable(lhs.sym.typ): if cmpTypes(c, lhs.typ, rhs.typ) == isGeneric: internalAssert c.p.resultSym != nil lhs.typ = rhs.typ @@ -1259,12 +1262,21 @@ proc semYield(c: PContext, n: PNode): PNode = localError(n.info, errYieldNotAllowedInTryStmt) elif n.sons[0].kind != nkEmpty: n.sons[0] = semExprWithType(c, n.sons[0]) # check for type compatibility: - var restype = c.p.owner.typ.sons[0] + var iterType = c.p.owner.typ + var restype = iterType.sons[0] if restype != nil: let adjustedRes = if c.p.owner.kind == skIterator: restype.base else: restype n.sons[0] = fitNode(c, adjustedRes, n.sons[0]) if n.sons[0].typ == nil: internalError(n.info, "semYield") + + if resultTypeIsInferrable(adjustedRes): + let inferred = n.sons[0].typ + if c.p.owner.kind == skIterator: + iterType.sons[0].sons[0] = inferred + else: + iterType.sons[0] = inferred + semYieldVarResult(c, n, adjustedRes) else: localError(n.info, errCannotReturnExpr) diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 8faf1d21a..4bcfa7f15 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -20,7 +20,7 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable, if a.kind != nkSym: internalError(a.info, "instantiateGenericParamList; no symbol") var q = a.sym - if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic}+tyTypeClasses: + if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic, tyIter}+tyTypeClasses: continue var s = newSym(skType, q.name, getCurrOwner(), q.info) s.flags = s.flags + {sfUsed, sfFromGeneric} diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index a11386966..edce7c9bd 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -661,10 +661,18 @@ proc semFor(c: PContext, n: PNode): PNode = openScope(c) n.sons[length-2] = semExprNoDeref(c, n.sons[length-2], {efWantIterator}) var call = n.sons[length-2] - if call.kind in nkCallKinds and call.sons[0].typ.callConv == ccClosure: + let isCallExpr = call.kind in nkCallKinds + if isCallExpr and call.sons[0].sym.magic != mNone: + if call.sons[0].sym.magic == mOmpParFor: + result = semForVars(c, n) + result.kind = nkParForStmt + else: + result = semForFields(c, n, call.sons[0].sym.magic) + elif (isCallExpr and call.sons[0].typ.callConv == ccClosure) or + call.typ.kind == tyIter: # first class iterator: result = semForVars(c, n) - elif call.kind notin nkCallKinds or call.sons[0].kind != nkSym or + elif not isCallExpr or call.sons[0].kind != nkSym or call.sons[0].sym.kind notin skIterators: if length == 3: n.sons[length-2] = implicitIterator(c, "items", n.sons[length-2]) @@ -673,12 +681,6 @@ proc semFor(c: PContext, n: PNode): PNode = else: localError(n.sons[length-2].info, errIteratorExpected) result = semForVars(c, n) - elif call.sons[0].sym.magic != mNone: - if call.sons[0].sym.magic == mOmpParFor: - result = semForVars(c, n) - result.kind = nkParForStmt - else: - result = semForFields(c, n, call.sons[0].sym.magic) else: result = semForVars(c, n) # propagate any enforced VoidContext: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index a619de7ff..875631505 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -721,7 +721,16 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, allowMetaTypes = true) result = newTypeWithSons(c, tyCompositeTypeClass, @[paramType, result]) result = addImplicitGeneric(result) - + + of tyIter: + if paramType.callConv == ccInline: + if procKind notin {skTemplate, skMacro, skIterator}: + localError(info, errInlineIteratorsAsProcParams) + if paramType.len == 1: + let lifted = liftingWalk(paramType.base) + if lifted != nil: paramType.sons[0] = lifted + result = addImplicitGeneric(paramType) + of tyGenericInst: if paramType.lastSon.kind == tyUserTypeClass: var cp = copyType(paramType, getCurrOwner(), false) @@ -852,7 +861,11 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, if lifted != nil: r = lifted r.flags.incl tfRetType r = skipIntLit(r) - if kind == skIterator: r = newTypeWithSons(c, tyIter, @[r]) + if kind == skIterator: + # see tchainediterators + # in cases like iterator foo(it: iterator): type(it) + # we don't need to change the return type to iter[T] + if not r.isInlineIterator: r = newTypeWithSons(c, tyIter, @[r]) result.sons[0] = r res.typ = r @@ -984,7 +997,8 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = of nkTypeOfExpr: # for ``type(countup(1,3))``, see ``tests/ttoseq``. checkSonsLen(n, 1) - result = semExprWithType(c, n.sons[0], {efInTypeof}).typ.skipTypes({tyIter}) + let typExpr = semExprWithType(c, n.sons[0], {efInTypeof}) + result = typExpr.typ.skipTypes({tyIter}) of nkPar: if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev) else: @@ -1103,8 +1117,12 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result = newConstraint(c, tyIter) else: result = semProcTypeWithScope(c, n, prev, skClosureIterator) - result.flags.incl(tfIterator) - result.callConv = ccClosure + if n.lastSon.kind == nkPragma and hasPragma(n.lastSon, wInline): + result.kind = tyIter + result.callConv = ccInline + else: + result.flags.incl(tfIterator) + result.callConv = ccClosure of nkProcTy: if n.sonsLen == 0: result = newConstraint(c, tyProc) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 22edc6e32..46ec31d90 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -305,6 +305,11 @@ proc skipIntLiteralParams(t: PType) = if skipped != p: t.sons[i] = skipped if i > 0: t.n.sons[i].sym.typ = skipped + + # when the typeof operator is used on a static input + # param, the results gets infected with static as well: + if t.sons[0] != nil and t.sons[0].kind == tyStatic: + t.sons[0] = t.sons[0].base proc propagateFieldFlags(t: PType, n: PNode) = # This is meant for objects and tuples @@ -323,7 +328,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = result = t if t == nil: return - if t.kind in {tyStatic, tyGenericParam} + tyTypeClasses: + if t.kind in {tyStatic, tyGenericParam, tyIter} + tyTypeClasses: let lookup = PType(idTableGet(cl.typeMap, t)) if lookup != nil: return lookup diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index c0898ef26..19f10def8 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1014,6 +1014,10 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType, result.typ = getInstantiatedType(c, arg, m, base(f)) m.baseTypeMatch = true +proc isInlineIterator*(t: PType): bool = + result = t.kind == tyIter or + (t.kind == tyBuiltInTypeClass and t.base.kind == tyIter) + proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, argSemantized, argOrig: PNode): PNode = var @@ -1021,7 +1025,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, arg = argSemantized argType = argType c = m.c - + if tfHasStatic in fMaybeStatic.flags: # XXX: When implicit statics are the default # this will be done earlier - we just have to @@ -1060,7 +1064,14 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, return arg.typ.n else: return argOrig - + + if r != isNone and f.isInlineIterator: + var inlined = newTypeS(tyStatic, c) + inlined.sons = @[argType] + inlined.n = argSemantized + put(m.bindings, f, inlined) + return argSemantized + case r of isConvertible: inc(m.convMatches) @@ -1188,7 +1199,9 @@ proc prepareOperand(c: PContext; formal: PType; a: PNode): PNode = # a.typ == nil is valid result = a elif a.typ.isNil: - result = c.semOperand(c, a, {efDetermineType}) + let flags = if formal.kind == tyIter: {efDetermineType, efWantIterator} + else: {efDetermineType} + result = c.semOperand(c, a, flags) else: result = a diff --git a/compiler/transf.nim b/compiler/transf.nim index f4b716c5b..9586398c9 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -425,7 +425,7 @@ proc findWrongOwners(c: PTransf, n: PNode) = x.sym.owner.name.s & " " & getCurrOwner(c).name.s) else: for i in 0 .. Date: Sat, 8 Mar 2014 23:27:33 +0200 Subject: [PATCH 13/25] implicit auto return type for inline iterators --- compiler/semtypes.nim | 8 ++++++-- doc/manual.txt | 20 +++++++++++++------- tests/iter/tchainediterators.nim | 2 +- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 875631505..dd73cf01a 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -849,9 +849,13 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, addParamOrResult(c, arg, kind) if gCmd == cmdPretty: checkDef(a.sons[j], arg) - + var r: PType if n.sons[0].kind != nkEmpty: - var r = semTypeNode(c, n.sons[0], nil) + r = semTypeNode(c, n.sons[0], nil) + elif kind == skIterator: + r = newTypeS(tyAnything, c) + + if r != nil: # turn explicit 'void' return type into 'nil' because the rest of the # compiler only checks for 'nil': if skipTypes(r, {tyGenericInst}).kind != tyEmpty: diff --git a/doc/manual.txt b/doc/manual.txt index 3c1f7b651..04050a99e 100644 --- a/doc/manual.txt +++ b/doc/manual.txt @@ -2822,7 +2822,6 @@ as there are components in the tuple. The i'th iteration variable's type is the type of the i'th component. In other words, implicit tuple unpacking in a for loop context is supported. - Implict items/pairs invocations ------------------------------- @@ -2847,10 +2846,11 @@ First class iterators There are 2 kinds of iterators in Nimrod: *inline* and *closure* iterators. An `inline iterator`:idx: is an iterator that's always inlined by the compiler leading to zero overhead for the abstraction, but may result in a heavy -increase in code size. Inline iterators are second class -citizens; one cannot pass them around like first class procs. +increase in code size. Inline iterators are second class citizens; +They can be passed as parameters only to other inlining code facilities like +templates, macros and other inline iterators. -In contrast to that, a `closure iterator`:idx: can be passed around: +In contrast to that, a `closure iterator`:idx: can be passed around more freely: .. code-block:: nimrod iterator count0(): int {.closure.} = @@ -2873,9 +2873,7 @@ Closure iterators have other restrictions than inline iterators: 1. ``yield`` in a closure iterator can not occur in a ``try`` statement. 2. For now, a closure iterator cannot be evaluated at compile time. 3. ``return`` is allowed in a closure iterator (but rarely useful). -4. Since closure iterators can be used as a collaborative tasking - system, ``void`` is a valid return type for them. -5. Both inline and closure iterators cannot be recursive. +4. Both inline and closure iterators cannot be recursive. Iterators that are neither marked ``{.closure.}`` nor ``{.inline.}`` explicitly default to being inline, but that this may change in future versions of the @@ -2937,6 +2935,14 @@ parameters of an outer factory proc: for f in foo(): echo f +Implicit return type +-------------------- + +Since inline interators must always produce values that will be consumed in +a for loop, the compiler will implicity use the ``auto`` return type if no +type is given by the user. In contrast, since closure iterators can be used +as a collaborative tasking system, ``void`` is a valid return type for them. + Type sections ============= diff --git a/tests/iter/tchainediterators.nim b/tests/iter/tchainediterators.nim index 010703cb5..18d096761 100644 --- a/tests/iter/tchainediterators.nim +++ b/tests/iter/tchainediterators.nim @@ -12,7 +12,7 @@ iterator gaz(it: iterator{.inline.}): type(it) = for x in it: yield x*2 -iterator baz(it: iterator{.inline.}): auto = +iterator baz(it: iterator{.inline.}) = for x in gaz(it): yield x*2 From 4b09a897583a38bea144e86b8b99b1347b525280 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sun, 9 Mar 2014 14:02:01 +0200 Subject: [PATCH 14/25] fix #966 test for ``map`` defined as inline iterator --- compiler/semcall.nim | 12 +++++++++--- tests/iter/titerable.nim | 26 ++++++++++++++++++++++++++ tests/overload/tissue966.nim | 12 ++++++++++++ 3 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 tests/iter/titerable.nim create mode 100644 tests/overload/tissue966.nim diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 2e5def75a..5d480bc98 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -82,7 +82,7 @@ proc notFoundError*(c: PContext, n: PNode, errors: seq[string]) = # fail fast: globalError(n.info, errTypeMismatch, "") var result = msgKindToString(errTypeMismatch) - add(result, describeArgs(c, n, 1 + ord(nfDotField in n.flags))) + add(result, describeArgs(c, n, 1)) add(result, ')') var candidates = "" @@ -114,7 +114,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode, var errors: seq[string] var usedSyms: seq[PNode] - + template pickBest(headSymbol: expr) = pickBestCandidate(c, headSymbol, n, orig, initialBinding, filter, result, alt, errors) @@ -166,7 +166,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode, n.sons[0..1] = [callOp, n[1], calleeName] orig.sons[0..1] = [callOp, orig[1], calleeName] pickBest(callOp) - + if overloadsState == csEmpty and result.state == csEmpty: localError(n.info, errUndeclaredIdentifier, considerAcc(f).s) return @@ -175,9 +175,15 @@ proc resolveOverloads(c: PContext, n, orig: PNode, localError(n.info, errExprXCannotBeCalled, renderTree(n, {renderNoComments})) else: + if {nfDotField, nfDotSetter} * n.flags != {}: + # clean up the inserted ops + n.sons.delete(2) + n.sons[0] = f + errors = @[] pickBest(f) notFoundError(c, n, errors) + return if alt.state == csMatch and cmpCandidates(result, alt) == 0 and diff --git a/tests/iter/titerable.nim b/tests/iter/titerable.nim new file mode 100644 index 000000000..3ec79f68d --- /dev/null +++ b/tests/iter/titerable.nim @@ -0,0 +1,26 @@ +discard """ + output: '''2 +4 +6 +4 +8 +12 +''' +""" + +iterator map[T, U](s: iterator:T{.inline.}, f: proc(x: T): U): U = + for e in s: yield f(e) + +template toSeq(s: expr): expr = + var res = newSeq[type(s)](0) + for e in s: res.add(e) + res + +var s1 = @[1, 2, 3] +for x in map(s1.items, proc (a:int): int = a*2): + echo x + +var s2 = toSeq(map(s1.items, proc (a:int): int = a*4)) +for x in s2: + echo x + diff --git a/tests/overload/tissue966.nim b/tests/overload/tissue966.nim new file mode 100644 index 000000000..53ec2f108 --- /dev/null +++ b/tests/overload/tissue966.nim @@ -0,0 +1,12 @@ +discard """ + msg: 'type mismatch: got (PTest)' +""" + +type + PTest = ref object + +proc test(x: PTest, y: int) = nil + +var buf: PTest +buf.test() + From a0975269564f2474953d2b12aaaab4ba71cec664 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 9 Mar 2014 13:49:38 +0000 Subject: [PATCH 15/25] Fixes to asyncio2 on Linux. --- lib/posix/epoll.nim | 2 +- lib/pure/asyncio2.nim | 28 ++++++++++++++-------------- lib/pure/selectors.nim | 26 ++++++++++++++++++-------- lib/pure/sockets2.nim | 22 ++++++++++++++++++++++ tests/async/tasyncawait.nim | 10 +++++++++- 5 files changed, 64 insertions(+), 24 deletions(-) diff --git a/lib/posix/epoll.nim b/lib/posix/epoll.nim index 366521551..57a2f001f 100644 --- a/lib/posix/epoll.nim +++ b/lib/posix/epoll.nim @@ -36,7 +36,7 @@ type epoll_data* {.importc: "union epoll_data", header: "", pure, final.} = object # TODO: This is actually a union. #thePtr* {.importc: "ptr".}: pointer - fd*: cint # \ + fd* {.importc: "fd".}: cint # \ #u32*: uint32 #u64*: uint64 diff --git a/lib/pure/asyncio2.nim b/lib/pure/asyncio2.nim index 12d4cb5a3..60d489dda 100644 --- a/lib/pure/asyncio2.nim +++ b/lib/pure/asyncio2.nim @@ -473,7 +473,6 @@ else: proc update(p: PDispatcher, sock: TSocketHandle, events: set[TEvent]) = assert sock in p.selector - echo("Update: ", events) if events == {}: discard p.selector.unregister(sock) else: @@ -499,23 +498,25 @@ else: for info in p.selector.select(timeout): let data = PData(info.key.data) assert data.sock == info.key.fd - echo("R: ", data.readCBs.len, " W: ", data.writeCBs.len, ". ", info.events) if EvRead in info.events: - var newReadCBs: seq[TCallback] = @[] - for cb in data.readCBs: + # Callback may add items to ``data.readCBs`` which causes issues if + # we are iterating over ``data.readCBs`` at the same time. We therefore + # make a copy to iterate over. + let currentCBs = data.readCBs + data.readCBs = @[] + for cb in currentCBs: if not cb(data.sock): # Callback wants to be called again. - newReadCBs.add(cb) - data.readCBs = newReadCBs + data.readCBs.add(cb) if EvWrite in info.events: - var newWriteCBs: seq[TCallback] = @[] - for cb in data.writeCBs: + let currentCBs = data.writeCBs + data.writeCBs = @[] + for cb in currentCBs: if not cb(data.sock): # Callback wants to be called again. - newWriteCBs.add(cb) - data.writeCBs = newWriteCBs + data.writeCBs.add(cb) var newEvents: set[TEvent] if data.readCBs.len != 0: newEvents = {EvRead} @@ -615,7 +616,6 @@ else: retFuture.complete(0) addWrite(p, socket, cb) return retFuture - proc acceptAddr*(p: PDispatcher, socket: TSocketHandle): PFuture[tuple[address: string, client: TSocketHandle]] = @@ -854,7 +854,7 @@ when isMainModule: sock.setBlocking false - when false: + when true: # Await tests proc main(p: PDispatcher): PFuture[int] {.async.} = discard await p.connect(sock, "irc.freenode.net", TPort(6667)) @@ -880,7 +880,7 @@ when isMainModule: else: - when false: + when true: var f = p.connect(sock, "irc.freenode.org", TPort(6667)) f.callback = @@ -919,4 +919,4 @@ when isMainModule: - \ No newline at end of file + diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index 6482a01a6..e086ee3ab 100644 --- a/lib/pure/selectors.nim +++ b/lib/pure/selectors.nim @@ -10,11 +10,13 @@ # TODO: Docs. import tables, os, unsigned, hashes +import sockets2 when defined(linux): import posix, epoll elif defined(windows): import winlean proc hash*(x: TSocketHandle): THash {.borrow.} +proc `$`*(x: TSocketHandle): string {.borrow.} type TEvent* = enum @@ -31,7 +33,7 @@ when defined(linux) or defined(nimdoc): type PSelector* = ref object epollFD: cint - events: array[64, ptr epoll_event] + events: array[64, epoll_event] fds: TTable[TSocketHandle, PSelectorKey] proc createEventStruct(events: set[TEvent], fd: TSocketHandle): epoll_event = @@ -66,17 +68,25 @@ when defined(linux) or defined(nimdoc): var event = createEventStruct(events, fd) s.fds[fd].events = events - echo("About to update") if epoll_ctl(s.epollFD, EPOLL_CTL_MOD, fd, addr(event)) != 0: + if OSLastError().cint == ENOENT: + # Socket has been closed. Epoll automatically removes disconnected + # sockets. + s.fds.del(fd) + osError("Socket has been disconnected") + OSError(OSLastError()) - echo("finished updating") result = s.fds[fd] proc unregister*(s: PSelector, fd: TSocketHandle): PSelectorKey {.discardable.} = if not s.fds.hasKey(fd): raise newException(EInvalidValue, "File descriptor not found.") if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fd, nil) != 0: - OSError(OSLastError()) + if osLastError().cint == ENOENT: + # Socket has been closed. Epoll automatically removes disconnected + # sockets so its already been removed. + else: + OSError(OSLastError()) result = s.fds[fd] s.fds.del(fd) @@ -92,21 +102,21 @@ when defined(linux) or defined(nimdoc): ## on the ``fd``. result = @[] - let evNum = epoll_wait(s.epollFD, s.events[0], 64.cint, timeout.cint) + let evNum = epoll_wait(s.epollFD, addr s.events[0], 64.cint, timeout.cint) if evNum < 0: OSError(OSLastError()) if evNum == 0: return @[] for i in 0 .. Date: Sun, 9 Mar 2014 16:04:58 +0200 Subject: [PATCH 16/25] few more fixes for static params in macros; new failing test cases for static evaluation --- compiler/semtypes.nim | 25 +++++++++++++------ tests/vm/tstaticprintseq.nim | 48 ++++++++++++++++++++++++++++++------ 2 files changed, 58 insertions(+), 15 deletions(-) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index dd73cf01a..299a3a9b9 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -602,15 +602,24 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType = incl(result.flags, tfFinal) proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) = - if kind == skMacro and param.typ.kind notin {tyTypeDesc, tyStatic}: - # within a macro, every param has the type PNimrodNode! - # and param.typ.kind in {tyTypeDesc, tyExpr, tyStmt}: - let nn = getSysSym"PNimrodNode" - var a = copySym(param) - a.typ = nn.typ - if sfGenSym notin a.flags: addDecl(c, a) + template addDecl(x) = + if sfGenSym notin x.flags: addDecl(c, x) + + if kind == skMacro: + if param.typ.kind == tyTypeDesc: + addDecl(param) + elif param.typ.kind == tyStatic: + var a = copySym(param) + a.typ = param.typ.base + addDecl(a) + else: + # within a macro, every param has the type PNimrodNode! + let nn = getSysSym"PNimrodNode" + var a = copySym(param) + a.typ = nn.typ + addDecl(a) else: - if sfGenSym notin param.flags: addDecl(c, param) + addDecl(param) let typedescId = getIdent"typedesc" diff --git a/tests/vm/tstaticprintseq.nim b/tests/vm/tstaticprintseq.nim index 99a56d161..f7ed1e2bb 100644 --- a/tests/vm/tstaticprintseq.nim +++ b/tests/vm/tstaticprintseq.nim @@ -4,18 +4,52 @@ discard """ 3 1 2 +3 +1 +2 +3 +1 +2 3''' """ -const s = @[1,2,3] +when false: + const s = @[1,2,3] -macro foo: stmt = - for e in s: - echo e + macro foo: stmt = + for e in s: + echo e -foo() + foo() + + static: + for e in s: + echo e + + macro bar(x: static[seq[int]]): stmt = + for e in x: + echo e + + bar s + bar(@[1, 2, 3]) + +type + TData = tuple + letters: seq[string] + numbers: seq[int] + +const data: TData = (@["aa", "bb"], @[11, 22]) static: - for e in s: - echo e + for x in data.letters: + echo x + var m = data + for x in m.letters: + echo x + +macro ff(d: static[TData]): stmt = + for x in d.letters: + echo x + +ff(data) From eebe0035b5d16d82a3806ff6c3d29935e771226b Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sun, 9 Mar 2014 17:06:29 +0200 Subject: [PATCH 17/25] teach opcLdObj about nkExprColonExpr --- compiler/vm.nim | 4 ++- tests/static/tstaticparammacro.nim | 52 ++++++++++++++++++++++++++++++ tests/vm/tstaticprintseq.nim | 36 ++++++++++----------- 3 files changed, 73 insertions(+), 19 deletions(-) create mode 100644 tests/static/tstaticparammacro.nim diff --git a/compiler/vm.nim b/compiler/vm.nim index f9b143bce..2a80106a5 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -425,7 +425,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = decodeBC(rkNode) let src = regs[rb].node if src.kind notin {nkEmpty..nkNilLit}: - regs[ra].node = src.sons[rc] + let n = src.sons[rc] + regs[ra].node = if n.kind == nkExprColonExpr: n[1] + else: n else: stackTrace(c, tos, pc, errIndexOutOfBounds) of opcWrObj: diff --git a/tests/static/tstaticparammacro.nim b/tests/static/tstaticparammacro.nim new file mode 100644 index 000000000..7fb9e2014 --- /dev/null +++ b/tests/static/tstaticparammacro.nim @@ -0,0 +1,52 @@ +discard """ + msg: '''letters +aa +bb +numbers +11 +22 +AST a +[(11, 22), (33, 44)] +AST b +(e: [55, 66], f: [77, 88]) +55 +''' +""" + +import macros + +type + TConfig = tuple + letters: seq[string] + numbers:seq[int] + +const data: Tconfig = (@["aa", "bb"], @[11, 22]) + +macro mymacro(data: static[TConfig]): stmt = + echo "letters" + for s in items(data.letters): + echo s + echo "numbers" + for n in items(data.numbers): + echo n + +mymacro(data) + +type + Ta = seq[tuple[c:int, d:int]] + Tb = tuple[e:seq[int], f:seq[int]] + +const + a : Ta = @[(11, 22), (33, 44)] + b : Tb = (@[55,66], @[77, 88]) + +macro mA(data: static[Ta]): stmt = + echo "AST a \n", repr(data) + +macro mB(data: static[Tb]): stmt = + echo "AST b \n", repr(data) + echo data.e[0] + +mA(a) +mB(b) + diff --git a/tests/vm/tstaticprintseq.nim b/tests/vm/tstaticprintseq.nim index f7ed1e2bb..4575f3af1 100644 --- a/tests/vm/tstaticprintseq.nim +++ b/tests/vm/tstaticprintseq.nim @@ -10,28 +10,31 @@ discard """ 3 1 2 -3''' +3 +aa +bb +aa +bb''' """ -when false: - const s = @[1,2,3] +const s = @[1,2,3] - macro foo: stmt = - for e in s: - echo e +macro foo: stmt = + for e in s: + echo e - foo() +foo() - static: - for e in s: - echo e +static: + for e in s: + echo e - macro bar(x: static[seq[int]]): stmt = - for e in x: - echo e +macro bar(x: static[seq[int]]): stmt = + for e in x: + echo e - bar s - bar(@[1, 2, 3]) +bar s +bar(@[1, 2, 3]) type TData = tuple @@ -41,9 +44,6 @@ type const data: TData = (@["aa", "bb"], @[11, 22]) static: - for x in data.letters: - echo x - var m = data for x in m.letters: echo x From 752352a6834dad94e0687b2518240e8425e6bcac Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sun, 9 Mar 2014 20:47:05 +0200 Subject: [PATCH 18/25] fix #949 --- compiler/semexprs.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index c16ab9b87..d07d695da 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1951,7 +1951,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = of nkBracketExpr: checkMinSonsLen(n, 1) var s = qualifiedLookUp(c, n.sons[0], {checkUndeclared}) - if s != nil and s.kind in {skProc, skMethod, skConverter}+skIterators: + if (s != nil and s.kind in {skProc, skMethod, skConverter}+skIterators) or + n[0].kind in nkSymChoices: # type parameters: partial generic specialization n.sons[0] = semSymGenericInstantiation(c, n.sons[0], s) result = explicitGenericInstantiation(c, n, s) From 29b7104a5330ebcb188243a271b4409e8613837b Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sun, 9 Mar 2014 21:04:12 +0200 Subject: [PATCH 19/25] fix #829; (macros.quote) the fix is a little bit peculiar: the inserted call to getAst was getting a false-positive for being a lambda proc, because lambdalifting.isInnerProc takes into account who is the owner of a given symbol: (a nested proc is a callable symbol owned by the enclosing proc) --- compiler/semexprs.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index d07d695da..77ac98db7 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1358,7 +1358,7 @@ proc expectString(c: PContext, n: PNode): string = localError(n.info, errStringLiteralExpected) proc getMagicSym(magic: TMagic): PSym = - result = newSym(skProc, getIdent($magic), getCurrOwner(), gCodegenLineInfo) + result = newSym(skProc, getIdent($magic), systemModule, gCodegenLineInfo) result.magic = magic proc newAnonSym(kind: TSymKind, info: TLineInfo, From 3dcf735482bed528f80614dca7a096f5e1a3aaa4 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sun, 9 Mar 2014 22:15:11 +0200 Subject: [PATCH 20/25] fix #909 --- compiler/sem.nim | 4 ++++ compiler/semtempl.nim | 4 +++- tests/template/tissue909.nim | 16 ++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 tests/template/tissue909.nim diff --git a/compiler/sem.nim b/compiler/sem.nim index 5ee46654e..ed4c4b093 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -139,6 +139,10 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym = result = n.sym internalAssert sfGenSym in result.flags internalAssert result.kind == kind + # when there is a nested proc inside a template, semtmpl + # will assign a wrong owner during the first pass over the + # template; we must fix it here: see #909 + result.owner = getCurrOwner() else: result = newSym(kind, considerAcc(n), getCurrOwner(), n.info) diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 31624a97f..42268d44f 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -348,7 +348,9 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = of nkMethodDef: result = semRoutineInTemplBody(c, n, skMethod) of nkIteratorDef: - result = semRoutineInTemplBody(c, n, n[namePos].sym.kind) + let kind = if hasPragma(n[pragmasPos], wClosure): skClosureIterator + else: skIterator + result = semRoutineInTemplBody(c, n, kind) of nkTemplateDef: result = semRoutineInTemplBody(c, n, skTemplate) of nkMacroDef: diff --git a/tests/template/tissue909.nim b/tests/template/tissue909.nim new file mode 100644 index 000000000..5b57a3558 --- /dev/null +++ b/tests/template/tissue909.nim @@ -0,0 +1,16 @@ +import macros + +template baz() = + proc bar() = + var x = 5 + iterator foo(): int {.closure.} = + echo x + var y = foo + discard y() + +macro test(): stmt = + result = getAst(baz()) + echo(treeRepr(result)) + +test() +bar() From 45a345e93da9d80d5a7f2aaa5903e9f75c0bf2d6 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Sun, 9 Mar 2014 23:38:17 +0200 Subject: [PATCH 21/25] fix #866; generic static params --- compiler/ast.nim | 4 ++++ compiler/astalgo.nim | 8 +++++++- compiler/guards.nim | 4 ---- compiler/semtypes.nim | 35 ++++++++++++++++++++++------------- doc/manual.txt | 4 ++-- 5 files changed, 35 insertions(+), 20 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index 9c9dfce9a..f9cab0d88 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -818,6 +818,9 @@ type counter*: int data*: TObjectSeq + TImplication* = enum + impUnknown, impNo, impYes + # BUGFIX: a module is overloadable so that a proc can have the # same name as an imported module. This is necessary because of # the poor naming choices in the standard library. @@ -865,6 +868,7 @@ const nkCallKinds* = {nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit, nkHiddenCallConv} + nkLiterals* = {nkCharLit..nkTripleStrLit} nkLambdaKinds* = {nkLambda, nkDo} declarativeDefs* = {nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef} procDefs* = nkLambdaKinds + declarativeDefs diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index cce2cc215..36dd7f562 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -50,7 +50,7 @@ proc strTableGet*(t: TStrTable, name: PIdent): PSym type TTabIter*{.final.} = object # consider all fields here private h*: THash # current hash - + proc initTabIter*(ti: var TTabIter, tab: TStrTable): PSym proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym # usage: @@ -157,6 +157,12 @@ proc leValue*(a, b: PNode): bool = #InternalError(a.info, "leValue") discard +proc weakLeValue*(a, b: PNode): TImplication = + if a.kind notin nkLiterals or b.kind notin nkLiterals: + result = impUnknown + else: + result = if leValue(a, b): impYes else: impNo + proc lookupInRecord(n: PNode, field: PIdent): PSym = result = nil case n.kind diff --git a/compiler/guards.nim b/compiler/guards.nim index fe868054f..f475f5068 100644 --- a/compiler/guards.nim +++ b/compiler/guards.nim @@ -274,10 +274,6 @@ proc pred(n: PNode): PNode = else: result = n -type - TImplication* = enum - impUnknown, impNo, impYes - proc impliesEq(fact, eq: PNode): TImplication = let (loc, val) = if isLocation(eq.sons[1]): (1, 2) else: (2, 1) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 299a3a9b9..c441c3c44 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -147,26 +147,35 @@ proc semDistinct(c: PContext, n: PNode, prev: PType): PType = else: result = newConstraint(c, tyDistinct) -proc semRangeAux(c: PContext, n: PNode, prev: PType): PType = +proc semRangeAux(c: PContext, n: PNode, prev: PType): PType = assert isRange(n) checkSonsLen(n, 3) result = newOrPrevType(tyRange, prev, c) result.n = newNodeI(nkRange, n.info) - if (n[1].kind == nkEmpty) or (n[2].kind == nkEmpty): + if (n[1].kind == nkEmpty) or (n[2].kind == nkEmpty): localError(n.info, errRangeIsEmpty) - var a = semConstExpr(c, n[1]) - var b = semConstExpr(c, n[2]) - if not sameType(a.typ, b.typ): + + var imm: array[2, PNode] + imm[0] = semExprWithType(c, n[1], {efDetermineType}) + imm[1] = semExprWithType(c, n[2], {efDetermineType}) + + if not sameType(imm[0].typ, imm[1].typ): localError(n.info, errPureTypeMismatch) - elif a.typ.kind notin {tyInt..tyInt64,tyEnum,tyBool,tyChar, - tyFloat..tyFloat128,tyUInt8..tyUInt32}: + elif not imm[0].typ.isOrdinalType: localError(n.info, errOrdinalTypeExpected) - elif enumHasHoles(a.typ): - localError(n.info, errEnumXHasHoles, a.typ.sym.name.s) - elif not leValue(a, b): localError(n.info, errRangeIsEmpty) - addSon(result.n, a) - addSon(result.n, b) - addSonSkipIntLit(result, b.typ) + elif enumHasHoles(imm[0].typ): + localError(n.info, errEnumXHasHoles, imm[0].typ.sym.name.s) + + for i in 0..1: + if hasGenericArguments(imm[i]): + result.n.addSon makeStaticExpr(c, imm[i]) + else: + result.n.addSon semConstExpr(c, imm[i]) + + if weakLeValue(result.n[0], result.n[1]) == impNo: + localError(n.info, errRangeIsEmpty) + + addSonSkipIntLit(result, imm[0].typ) proc semRange(c: PContext, n: PNode, prev: PType): PType = result = nil diff --git a/doc/manual.txt b/doc/manual.txt index 748d41d4b..c85998741 100644 --- a/doc/manual.txt +++ b/doc/manual.txt @@ -4062,8 +4062,8 @@ Static params can also appear in the signatures of generic types: AffineTransform2D[T] = Matrix[3, 3, T] AffineTransform3D[T] = Matrix[4, 4, T] - AffineTransform3D[float] # OK - AffineTransform2D[string] # Error, `string` is not a `Number` + var m1: AffineTransform3D[float] # OK + var m2: AffineTransform2D[string] # Error, `string` is not a `Number` typedesc From 9fb07555721d53139f7275c7f8f7143f5c3c8a01 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Mon, 10 Mar 2014 00:29:15 +0200 Subject: [PATCH 22/25] further improvements for static generic params; activate the hardest test cases --- compiler/sem.nim | 3 ++- compiler/semtypes.nim | 25 ++++++++++++++----------- tests/generics/tgenericshardcases.nim | 18 ++++++++++++------ tests/metatype/tstaticparams.nim | 22 +++++++++++++++++----- 4 files changed, 45 insertions(+), 23 deletions(-) diff --git a/compiler/sem.nim b/compiler/sem.nim index ed4c4b093..c8228618b 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -198,7 +198,8 @@ proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode): PNode = result = semExprWithType(c, evaluated) else: result = evaluated - semmacrosanity.annotateType(result, eOrig.typ) + let expectedType = eOrig.typ.skipTypes({tyStatic}) + semmacrosanity.annotateType(result, expectedType) else: result = semExprWithType(c, evaluated) #result = fitNode(c, e.typ, result) inlined with special case: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index c441c3c44..f91222477 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -155,27 +155,30 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType = if (n[1].kind == nkEmpty) or (n[2].kind == nkEmpty): localError(n.info, errRangeIsEmpty) - var imm: array[2, PNode] - imm[0] = semExprWithType(c, n[1], {efDetermineType}) - imm[1] = semExprWithType(c, n[2], {efDetermineType}) + var range: array[2, PNode] + range[0] = semExprWithType(c, n[1], {efDetermineType}) + range[1] = semExprWithType(c, n[2], {efDetermineType}) - if not sameType(imm[0].typ, imm[1].typ): + var rangeT: array[2, PType] + for i in 0..1: rangeT[i] = range[i].typ.skipTypes({tyStatic}).skipIntLit + + if not sameType(rangeT[0], rangeT[1]): localError(n.info, errPureTypeMismatch) - elif not imm[0].typ.isOrdinalType: + elif not rangeT[0].isOrdinalType: localError(n.info, errOrdinalTypeExpected) - elif enumHasHoles(imm[0].typ): - localError(n.info, errEnumXHasHoles, imm[0].typ.sym.name.s) + elif enumHasHoles(rangeT[0]): + localError(n.info, errEnumXHasHoles, rangeT[0].sym.name.s) for i in 0..1: - if hasGenericArguments(imm[i]): - result.n.addSon makeStaticExpr(c, imm[i]) + if hasGenericArguments(range[i]): + result.n.addSon makeStaticExpr(c, range[i]) else: - result.n.addSon semConstExpr(c, imm[i]) + result.n.addSon semConstExpr(c, range[i]) if weakLeValue(result.n[0], result.n[1]) == impNo: localError(n.info, errRangeIsEmpty) - addSonSkipIntLit(result, imm[0].typ) + addSonSkipIntLit(result, rangeT[0]) proc semRange(c: PContext, n: PNode, prev: PType): PType = result = nil diff --git a/tests/generics/tgenericshardcases.nim b/tests/generics/tgenericshardcases.nim index 2ef63bc20..e3b805db6 100644 --- a/tests/generics/tgenericshardcases.nim +++ b/tests/generics/tgenericshardcases.nim @@ -14,7 +14,8 @@ macro selectType(a, b: typedesc): typedesc = type Foo[T] = object data1: array[T.high, int] - data2: array[typeNameLen(T), float] # data3: array[0..T.typeNameLen, selectType(float, int)] + data2: array[typeNameLen(T), float] + data3: array[0..T.typeNameLen, selectType(float, int)] MyEnum = enum A, B, C, D @@ -27,10 +28,15 @@ echo high(f1.data2) # (MyEnum.len = 6) - 1 == 5 echo high(f2.data1) # 127 - 1 == 126 echo high(f2.data2) # int8.len - 1 == 3 -#static: -# assert high(f1.data1) == ord(D) -# assert high(f1.data2) == 6 # length of MyEnum +static: + assert high(f1.data1) == ord(C) + assert high(f1.data2) == 5 # length of MyEnum minus one, because we used T.high -# assert high(f2.data1) == 127 -# assert high(f2.data2) == 4 # length of int8 + assert high(f2.data1) == 126 + assert high(f2.data2) == 3 + + assert high(f1.data3) == 6 # length of MyEnum + assert high(f2.data3) == 4 # length of int8 + + assert f2.data3[0] is float diff --git a/tests/metatype/tstaticparams.nim b/tests/metatype/tstaticparams.nim index b1377443b..0597325c3 100644 --- a/tests/metatype/tstaticparams.nim +++ b/tests/metatype/tstaticparams.nim @@ -1,6 +1,6 @@ discard """ file: "tstaticparams.nim" - output: "abracadabra\ntest\n3" + output: "abracadabra\ntest\n3\n15" """ type @@ -11,8 +11,8 @@ type data: array[I, T] TA1[T; I: static[int]] = array[I, T] - # TA2[T; I: static[int]] = array[0..I, T] - # TA3[T; I: static[int]] = array[I-1, T] + TA2[T; I: static[int]] = array[0..I, T] + TA3[T; I: static[int]] = array[I-1, T] proc takeFoo(x: TFoo) = echo "abracadabra" @@ -26,6 +26,18 @@ echo high(y.data) var t1: TA1[float, 1] - # t2: TA2[string, 4] - # t3: TA3[int, 10] + t2: TA2[string, 4] + t3: TA3[int, 10] + +# example from the manual: +type + Matrix[M,N: static[int]; T] = array[0..(M*N - 1), T] + # Note how `Number` is just a type constraint here, while + # `static[int]` requires us to supply a compile-time int value + + AffineTransform2D[T] = Matrix[3, 3, T] + AffineTransform3D[T] = Matrix[4, 4, T] + +var m: AffineTransform3D[float] +echo high(m) From d5798b43dec547f372eb49d5a8848a9970b12260 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Mon, 10 Mar 2014 01:57:08 +0200 Subject: [PATCH 23/25] fix #986 --- compiler/semexprs.nim | 34 ++++++++++++++++++++------------ compiler/semtypinst.nim | 4 +++- tests/metatype/tstaticparams.nim | 6 +++++- 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 77ac98db7..f2c5e2854 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -885,7 +885,7 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent, of nkSym: if r.sym.name.id == field.id: result = r.sym else: illFormedAst(n) - + proc makeDeref(n: PNode): PNode = var t = skipTypes(n.typ, {tyGenericInst}) result = n @@ -899,6 +899,21 @@ proc makeDeref(n: PNode): PNode = addSon(result, a) t = skipTypes(t.sons[0], {tyGenericInst}) +proc readTypeParameter(c: PContext, ty: PType, + paramName: PIdent, info: TLineInfo): PNode = + internalAssert ty.kind == tyGenericInst + let ty = ty.skipGenericAlias + let tbody = ty.sons[0] + for s in countup(0, tbody.len-2): + let tParam = tbody.sons[s] + if tParam.sym.name == paramName: + let rawTyp = ty.sons[s + 1] + if rawTyp.kind == tyStatic: + return rawTyp.n + else: + let foundTyp = makeTypeDesc(c, rawTyp) + return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info) + proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = ## returns nil if it's not a built-in field access checkSonsLen(n, 2) @@ -932,18 +947,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = markUsed(n, f) return of tyGenericInst: - assert ty.sons[0].kind == tyGenericBody - let tbody = ty.sons[0] - for s in countup(0, tbody.len-2): - let tParam = tbody.sons[s] - if tParam.sym.name == i: - let rawTyp = ty.sons[s + 1] - if rawTyp.kind == tyStatic: - return rawTyp.n - else: - let foundTyp = makeTypeDesc(c, rawTyp) - return newSymNode(copySym(tParam.sym).linkTo(foundTyp), n.info) - return + return readTypeParameter(c, ty, i, n.info) of tyObject, tyTuple: if ty.n.kind == nkRecList: for field in ty.n.sons: @@ -990,6 +994,10 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = n.typ = f.typ result = n + # we didn't find any field, let's look for a generic param + if result == nil and n.sons[0].typ.kind == tyGenericInst: + result = readTypeParameter(c, n.sons[0].typ, i, n.info) + proc dotTransformation(c: PContext, n: PNode): PNode = if isSymChoice(n.sons[1]): result = newNodeI(nkDotCall, n.info) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 46ec31d90..4229f4797 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -181,7 +181,8 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode = of nkStaticExpr: var n = prepareNode(cl, n) n = reResolveCallsWithTypedescParams(cl, n) - result = cl.c.semExpr(cl.c, n) + result = if cl.allowMetaTypes: n + else: cl.c.semExpr(cl.c, n) else: var length = sonsLen(n) if length > 0: @@ -341,6 +342,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = result = replaceTypeVarsT(cl, lastSon(t)) of tyFromExpr: + if cl.allowMetaTypes: return var n = prepareNode(cl, t.n) n = cl.c.semConstExpr(cl.c, n) if n.typ.kind == tyTypeDesc: diff --git a/tests/metatype/tstaticparams.nim b/tests/metatype/tstaticparams.nim index 0597325c3..e76dae23c 100644 --- a/tests/metatype/tstaticparams.nim +++ b/tests/metatype/tstaticparams.nim @@ -1,6 +1,6 @@ discard """ file: "tstaticparams.nim" - output: "abracadabra\ntest\n3\n15" + output: "abracadabra\ntest\n3\n15\4" """ type @@ -41,3 +41,7 @@ type var m: AffineTransform3D[float] echo high(m) +proc getRows(mtx: Matrix): int = + result = mtx.M + +echo getRows(m) From 85fe5e1940efbde41ac88113e8cc6a954b0414b9 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Mon, 10 Mar 2014 13:04:22 +0200 Subject: [PATCH 24/25] fix #988 trivial crash caused due to unchecked iteration over an empty reclist --- compiler/semexprs.nim | 7 ++++--- compiler/semtypinst.nim | 5 ++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index f2c5e2854..62a816a50 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -931,7 +931,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = var ty = n.sons[0].typ var f: PSym = nil result = nil - if isTypeExpr(n.sons[0]) or ty.kind == tyTypeDesc and ty.base.kind != tyNone: + if isTypeExpr(n.sons[0]) or (ty.kind == tyTypeDesc and ty.base.kind != tyNone): if ty.kind == tyTypeDesc: ty = ty.base case ty.kind of tyEnum: @@ -940,7 +940,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = f = getSymFromList(ty.n, i) if f != nil: break ty = ty.sons[0] # enum inheritance - if f != nil: + if f != nil: result = newSymNode(f) result.info = n.info result.typ = ty @@ -950,7 +950,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = return readTypeParameter(c, ty, i, n.info) of tyObject, tyTuple: if ty.n.kind == nkRecList: - for field in ty.n.sons: + for field in ty.n: if field.sym.name == i: n.typ = newTypeWithSons(c, tyFieldAccessor, @[ty, field.sym.typ]) n.typ.n = copyTree(n) @@ -962,6 +962,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = # XXX: This is probably not relevant any more # reset to prevent 'nil' bug: see "tests/reject/tenumitems.nim": ty = n.sons[0].typ + return nil ty = skipTypes(ty, {tyGenericInst, tyVar, tyPtr, tyRef}) var check: PNode = nil diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 4229f4797..80e2aa284 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -320,9 +320,8 @@ proc propagateFieldFlags(t: PType, n: PNode) = of nkSym: propagateToOwner(t, n.sym.typ) of nkRecList, nkRecCase, nkOfBranch, nkElse: - if n.sons != nil: - for son in n.sons: - propagateFieldFlags(t, son) + for son in n: + propagateFieldFlags(t, son) else: discard proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = From 1546d210c5739213ebf93eb0cb624ca7a9fe9ad6 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Mon, 10 Mar 2014 18:13:48 +0200 Subject: [PATCH 25/25] fix #971 --- lib/nimbase.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/nimbase.h b/lib/nimbase.h index 1100e084b..b16b27b2c 100644 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -314,6 +314,9 @@ static unsigned long nimNaN[2]={0xffffffff, 0x7fffffff}; # define INF INFINITY # elif defined(HUGE_VAL) # define INF HUGE_VAL +# elif defined(_MSC_VER) +# include +# define INF (DBL_MAX+DBL_MAX) # else # define INF (1.0 / 0.0) # endif